import express from "express";
import compression from "compression";
import cors from "cors";
import { Routes } from "./core/interfaces/router";

import bodyParser from "body-parser";
import fileUpload from "express-fileupload";
import { DevEnv } from "./core/env/env";
import path from 'path';
import { locator } from "./core/di/register_di";
export const dirname = path.resolve();

const corsOptions = {
    origin: process.env.CORS_ALLOW_ORIGIN || '*',
    methods: ['GET', 'PUT', 'POST', 'DELETE', 'OPTIONS'],
    allowedHeaders: ['Content-Type', 'Authorization']
};
export class App {
    public app: express.Application;

    public port: string | number;
    
    public env: string;
    
    constructor(routes: Routes[], port) {
        this.app = express();
        this.port = port;
        this.env = process.env.NODE_ENV || "development";
        this.initializeMiddleware();
        this.initializeRoutes(routes);
        this.loadAppDependencies();
    }

    public listen() {
        this.app.listen(this.port, () => {
            console.info(`=================================`);
            console.info(`======= ENV: ${this.env} =======`);
            console.info(`🚀 App listening on the port ${this.port}`);
            console.info(`=================================`);
        });
    }

    public getServer() {
        return this.app;
    }

    private initializeMiddleware() {
        this.app.use(
            cors(corsOptions)
        );
        this.app.use(compression());
        this.app.use(express.json());
        this.app.use(express.urlencoded({ extended: true }));
        this.app.use(bodyParser.json());
        this.app.use(bodyParser.urlencoded({ extended: true }));
        this.app.use(express.static(dirname + '/public/'));
        this.app.use(fileUpload({
            createParentPath: true
        }));
    }

    private initializeRoutes(routes: Routes[]) {
        routes.forEach((route) => {
            this.app.use("/", route.router);
        });
    }
    
    loadAppDependencies() {
        locator(new DevEnv());
    }
}