import express from 'express'
import session from 'express-session';
import passport from 'passport';
import compression from 'compression';
import MongoDBStore from 'connect-mongodb-session';
import https from 'https';
import fs from 'fs';
import cookieParser from 'cookie-parser';
import helmet from 'helmet';
import { v4 as uuidv4 } from 'uuid';

/**
 * The Web Server class, manages all request from the web platform, manages the APIs, уеб сървър, управлява всички уеб заявки към платформата, агрегира всички комуникационни/гранични класове
 */
class WebServer {
    name = 'webServer';

    /**
     * Initializes the web server plugin, инициализация
     * @param {App} app The application instance, апликация
     */
    async init(app) {
        const xapp = express();
        this.xapp = xapp;

        xapp.disable('x-powered-by');

        xapp.use(compression());
        xapp.use(cookieParser());

        const store = new MongoDBStore(session)({
            uri: app.config.db.url,
            databaseName: app.config.db.name,
            collection: 'user_sessions'
        });

        store.on('error', function (error) {
            console.log(error);
        });

        xapp.use(session({
            secret: app.config.am.cookie.secret,
            cookie: {
                maxAge: app.config.am.cookie.maxAge || 1000 * 60 * 60 * 24 * 7,
                secure: !!app.config.am.cookie.secure,
                httpOnly: true,
                sameSite: app.config.am.cookie.sameSite
            },
            store,
            resave: false,
            saveUninitialized: (app.config.am?.session?.saveUninitialized === undefined) ? true : app.config.am.session.saveUninitialized,
            proxy: true
        }));

        // xapp.use((req, res, next) => {
        //     let l = app.config.langs.find(l => l.code == (req.query?.lang || req.cookies.lang || 'bg'));
        //     req.lang = l || app.config.langs[0];
        //     next();
        // })

        xapp.use(passport.initialize());
        xapp.use(passport.session());

        xapp.use(express.json({ limit: '150mb' }));
        xapp.use(express.urlencoded({ extended: false, limit: '150mb' }));

        xapp.use((req, res, next) => {
            res.locals.cspNonce = uuidv4();
            next();
        });
        
        app.config.am.helmet && xapp.use(helmet(app.config.am.helmet));
    }

    /**
     * Starts the web server plugin, стартиране на уеб сървъра
     * @param {App} app The application instance, апликация
     */
    async start(app) {
        
        this.xapp.use(express.static(`${this.app.root}/frontend/`));

        this.xapp.use((req, res, next) => {
            if (req.method == 'GET'){
                res.sendFile(`${this.app.root}/frontend/index.html`);
            }else if (req.method == 'POST') {
                return res.status(404).end();
            } else next();
        });

        ///error handler!
        this.xapp.use((err, req, res, next) => {
            console.error(err.stack)
            res.status(500).send('Something broke!')
        })

        let started = () => {
            console.log(`app started on port ${app.config.site.port}. SSL is ${app.config.site.ssl ? 'enabled' : 'disabled'}.`)
        }

        if (app.config.site.ssl) {
            this.server = https.createServer({
                key: fs.readFileSync(app.config.site.certificate.key),
                cert: fs.readFileSync(app.config.site.certificate.cert),
                passphrase: app.config.site.certificate.passphrase
            }, this.xapp).listen(app.config.site.port, started);
        } else {
            this.server = this.xapp.listen(app.config.site.port, app.config.site.hostAddress || '127.0.0.1', started);
        }
    }

    async stop(){
        if (this.server) {
            this.server.close();
        }
    }

}

export { WebServer };