#!/bin/bash

# Diagrammers API Module Generator
# Usage: ./scripts/generate-module.sh <module-name>

MODULE_NAME=$1
MODULE_NAME_CAPITALIZED=$(echo $MODULE_NAME | sed 's/^./\U&/')

if [ -z "$MODULE_NAME" ]; then
    echo "❌ Module name is required"
    echo "Usage: ./scripts/generate-module.sh <module-name>"
    echo "Example: ./scripts/generate-module.sh product"
    exit 1
fi

# Validate module name (only letters, numbers, hyphens, underscores)
if [[ ! $MODULE_NAME =~ ^[a-zA-Z][a-zA-Z0-9_-]*$ ]]; then
    echo "❌ Invalid module name. Use only letters, numbers, hyphens, and underscores. Must start with a letter."
    exit 1
fi

echo "🚀 Generating module: $MODULE_NAME"

# Create entity
echo "📝 Creating entity..."
cat > "src/entities/${MODULE_NAME}.ts" << EOF
import * as mongoose from 'mongoose';
import { ObjectId } from "bson";

export interface I${MODULE_NAME_CAPITALIZED} extends mongoose.Document {
    _id: ObjectId,
    name: string,
    description?: string,
    status: number,
    createdAt: Date,
    updatedAt: Date
}
EOF

# Create schema
echo "📋 Creating schema..."
cat > "src/schemas/${MODULE_NAME}.ts" << EOF
import * as mongoose from 'mongoose';
import { I${MODULE_NAME_CAPITALIZED} } from '../entities/${MODULE_NAME}';

export const ${MODULE_NAME}Schema = new mongoose.Schema(
    {
        name: {
            type: mongoose.SchemaTypes.String,
            required: true,
        },
        description: {
            type: mongoose.SchemaTypes.String,
            required: false,
        },
        status: {
            type: mongoose.SchemaTypes.Number,
            default: 1,
        }
    },
    { timestamps: true, suppressReservedKeysWarning: true },
);

export const ${MODULE_NAME_CAPITALIZED}Entity = mongoose.model<I${MODULE_NAME_CAPITALIZED}>('${MODULE_NAME}', ${MODULE_NAME}Schema);
EOF

# Create service
echo "🔧 Creating service..."
cat > "src/services/${MODULE_NAME}-service.ts" << EOF
import { ObjectId } from "bson";
import dbcontext from "../helpers/dbcontext";
import { ResponseCode } from "../helpers/enums";
import { Result } from "../helpers/result";
import { ${MODULE_NAME_CAPITALIZED}Entity } from "../schemas/${MODULE_NAME}";

export class ${MODULE_NAME_CAPITALIZED}Service {
    result: Result;
    className = '${MODULE_NAME_CAPITALIZED}Service';

    constructor(result: Result) {
        this.result = result;
    }

    async getAll(): Promise<Result> {
        try {
            const ${MODULE_NAME}s = await dbcontext.${MODULE_NAME_CAPITALIZED}Entity.find({ status: 1 });
            this.result.Data = ${MODULE_NAME}s;
            this.result.Status = ResponseCode.Ok;
            return this.result;
        } catch (ex) {
            this.result.addException(this.className, 'GetAll', ex);
            return this.result;
        }
    }

    async getById(id: string): Promise<Result> {
        try {
            const ${MODULE_NAME} = await dbcontext.${MODULE_NAME_CAPITALIZED}Entity.findById(id);
            if (${MODULE_NAME}) {
                this.result.Data = ${MODULE_NAME};
                this.result.Status = ResponseCode.Ok;
            } else {
                this.result.Status = ResponseCode.NotExist;
            }
            return this.result;
        } catch (ex) {
            this.result.addException(this.className, 'GetById', ex);
            return this.result;
        }
    }

    async create(${MODULE_NAME}Data: any): Promise<Result> {
        try {
            const ${MODULE_NAME}Entity = new ${MODULE_NAME_CAPITALIZED}Entity({
                _id: new ObjectId(),
                ...${MODULE_NAME}Data,
                status: 1
            });
            const created${MODULE_NAME_CAPITALIZED} = await dbcontext.${MODULE_NAME_CAPITALIZED}Entity.create(${MODULE_NAME}Entity);
            if (created${MODULE_NAME_CAPITALIZED}) {
                this.result.Data = created${MODULE_NAME_CAPITALIZED};
                this.result.Status = ResponseCode.Ok;
            } else {
                this.result.Status = ResponseCode.Error;
                this.result.Errors.push('Failed to create ${MODULE_NAME}');
            }
            return this.result;
        } catch (ex) {
            this.result.addException(this.className, 'Create', ex);
            return this.result;
        }
    }

    async update(id: string, ${MODULE_NAME}Data: any): Promise<Result> {
        try {
            const updated${MODULE_NAME_CAPitalized} = await dbcontext.${MODULE_NAME_CAPITALIZED}Entity.findByIdAndUpdate(
                id,
                { ...${MODULE_NAME}Data },
                { new: true }
            );
            if (updated${MODULE_NAME_CAPitalized}) {
                this.result.Data = updated${MODULE_NAME_CAPitalized};
                this.result.Status = ResponseCode.Ok;
            } else {
                this.result.Status = ResponseCode.NotExist;
            }
            return this.result;
        } catch (ex) {
            this.result.addException(this.className, 'Update', ex);
            return this.result;
        }
    }

    async delete(id: string): Promise<Result> {
        try {
            const deleted${MODULE_NAME_CAPitalized} = await dbcontext.${MODULE_NAME_CAPITALIZED}Entity.findByIdAndUpdate(
                id,
                { status: 0 },
                { new: true }
            );
            if (deleted${MODULE_NAME_CAPitalized}) {
                this.result.Data = deleted${MODULE_NAME_CAPitalized};
                this.result.Status = ResponseCode.Ok;
            } else {
                this.result.Status = ResponseCode.NotExist;
            }
            return this.result;
        } catch (ex) {
            this.result.addException(this.className, 'Delete', ex);
            return this.result;
        }
    }
}
EOF

# Create controller
echo "🎮 Creating controller..."
cat > "src/controllers/${MODULE_NAME}-controller.ts" << EOF
import { AuditMessageType, ResponseCode } from "../helpers/enums";
import handleResponse from "../helpers/handle-response";
import { Result } from "../helpers/result";
import { ${MODULE_NAME_CAPITALIZED}Service } from "../services/${MODULE_NAME}-service";

export default class ${MODULE_NAME_CAPITALIZED}Controller {

    async getAll(req, res) {
        const result = res.locals.result;
        try {
            result.addMessage(AuditMessageType.info, req.baseUrl, 'getAll', 'Started');
            const ${MODULE_NAME}Service = new ${MODULE_NAME_CAPITALIZED}Service(result);
            const serviceResult = await ${MODULE_NAME}Service.getAll();
            result.addMessage(AuditMessageType.info, req.baseUrl, 'getAll', 'Finished');
            return handleResponse(req, res, serviceResult);
        } catch (ex) {
            result.addException(req.baseUrl, 'getAll', ex);
            return handleResponse(req, res, result);
        }
    }

    async getById(req, res) {
        const result = res.locals.result;
        try {
            result.addMessage(AuditMessageType.info, req.baseUrl, 'getById', 'Started');
            const ${MODULE_NAME}Service = new ${MODULE_NAME_CAPITALIZED}Service(result);
            const serviceResult = await ${MODULE_NAME}Service.getById(req.params.id);
            result.addMessage(AuditMessageType.info, req.baseUrl, 'getById', 'Finished');
            return handleResponse(req, res, serviceResult);
        } catch (ex) {
            result.addException(req.baseUrl, 'getById', ex);
            return handleResponse(req, res, result);
        }
    }

    async create(req, res) {
        const result = res.locals.result;
        try {
            result.addMessage(AuditMessageType.info, req.baseUrl, 'create', 'Started');
            const ${MODULE_NAME}Service = new ${MODULE_NAME_CAPITALIZED}Service(result);
            const serviceResult = await ${MODULE_NAME}Service.create(req.body);
            result.addMessage(AuditMessageType.info, req.baseUrl, 'create', 'Finished');
            return handleResponse(req, res, serviceResult);
        } catch (ex) {
            result.addException(req.baseUrl, 'create', ex);
            return handleResponse(req, res, result);
        }
    }

    async update(req, res) {
        const result = res.locals.result;
        try {
            result.addMessage(AuditMessageType.info, req.baseUrl, 'update', 'Started');
            const ${MODULE_NAME}Service = new ${MODULE_NAME_CAPITALIZED}Service(result);
            const serviceResult = await ${MODULE_NAME}Service.update(req.params.id, req.body);
            result.addMessage(AuditMessageType.info, req.baseUrl, 'update', 'Finished');
            return handleResponse(req, res, serviceResult);
        } catch (ex) {
            result.addException(req.baseUrl, 'update', ex);
            return handleResponse(req, res, result);
        }
    }

    async delete(req, res) {
        const result = res.locals.result;
        try {
            result.addMessage(AuditMessageType.info, req.baseUrl, 'delete', 'Started');
            const ${MODULE_NAME}Service = new ${MODULE_NAME_CAPITALIZED}Service(result);
            const serviceResult = await ${MODULE_NAME}Service.delete(req.params.id);
            result.addMessage(AuditMessageType.info, req.baseUrl, 'delete', 'Finished');
            return handleResponse(req, res, serviceResult);
        } catch (ex) {
            result.addException(req.baseUrl, 'delete', ex);
            return handleResponse(req, res, result);
        }
    }
}
EOF

# Create routes
echo "🛣️ Creating routes..."
cat > "src/routes/${MODULE_NAME}-routes.ts" << EOF
import * as express from "express";
import ${MODULE_NAME_CAPITALIZED}Controller from "../controllers/${MODULE_NAME}-controller";

class ${MODULE_NAME_CAPITALIZED}Routes {
    public Router: express.Router = express.Router();
    private Controller: ${MODULE_NAME_CAPITALIZED}Controller = new ${MODULE_NAME_CAPITALIZED}Controller();

    constructor() {
        this.registerRoutes();
    }

    private registerRoutes() {
        this.Router.get('/', (req, res) => {
            res.send("${MODULE_NAME_CAPITALIZED} API is up.");
        });

        // CRUD routes
        this.Router.get('/all', (req, res) => this.Controller.getAll(req, res));
        this.Router.get('/:id', (req, res) => this.Controller.getById(req, res));
        this.Router.post('/', (req, res) => this.Controller.create(req, res));
        this.Router.put('/:id', (req, res) => this.Controller.update(req, res));
        this.Router.delete('/:id', (req, res) => this.Controller.delete(req, res));
    }
}

export const ${MODULE_NAME}Router = new ${MODULE_NAME_CAPITALIZED}Routes().Router;
EOF

# Update dbcontext
echo "🗄️ Updating dbcontext..."
# Add import to dbcontext
sed -i '' "/import { UserEntity } from '..\/schemas\/user';/a\\
import { ${MODULE_NAME_CAPITALIZED}Entity } from '../schemas/${MODULE_NAME}';" src/helpers/dbcontext.ts

# Add entity to dbcontext object
sed -i '' "/UserEntity,/a\\
    ${MODULE_NAME_CAPITALIZED}Entity," src/helpers/dbcontext.ts

# Add to dbcontextMapping
sed -i '' "/users: UserEntity,/a\\
    ${MODULE_NAME}s: ${MODULE_NAME_CAPITALIZED}Entity," src/helpers/dbcontext.ts

# Update routes index
echo "🔗 Updating routes index..."
# Add import
sed -i '' "/import { accountRouter } from \".\/account-routes\";/a\\
import { ${MODULE_NAME}Router } from \".\/${MODULE_NAME}-routes\";" src/routes/index.ts

# Add route prefix
sed -i '' "/const _accRoutePerfix = \"account\";/a\\
const _${MODULE_NAME}RoutePerfix = \"${MODULE_NAME}\";" src/routes/index.ts

# Add route registration
sed -i '' "/server.use(\`\/\${_accRoutePerfix}\/\`, accountRouter);/a\\
        server.use(\`\/\${_${MODULE_NAME}RoutePerfix}\/\`, ${MODULE_NAME}Router);" src/routes/index.ts

echo "✅ Module '$MODULE_NAME' generated successfully!"
echo ""
echo "📁 Generated files:"
echo "   src/entities/${MODULE_NAME}.ts"
echo "   src/schemas/${MODULE_NAME}.ts"
echo "   src/services/${MODULE_NAME}-service.ts"
echo "   src/controllers/${MODULE_NAME}-controller.ts"
echo "   src/routes/${MODULE_NAME}-routes.ts"
echo ""
echo "🔗 API endpoints available at:"
echo "   GET    /${MODULE_NAME}/all"
echo "   GET    /${MODULE_NAME}/:id"
echo "   POST   /${MODULE_NAME}/"
echo "   PUT    /${MODULE_NAME}/:id"
echo "   DELETE /${MODULE_NAME}/:id"
echo ""
echo "🚀 Next steps:"
echo "   1. Review and customize the generated files"
echo "   2. Add any specific business logic"
echo "   3. Test the endpoints"
echo "   4. Build and run: npm run build:dev && npm start" 