import { Injectable, Logger, NestMiddleware } from "@nestjs/common";
import { NextFunction, Request, Response } from "express";
import * as jwt from 'jsonwebtoken';
import { EntityManager } from "typeorm";

@Injectable()
export class Proxy implements NestMiddleware {

    private logger: Logger = new Logger(Proxy.name);
    private readonly exclPaths: string[] = ["/api/user/logIn"];

    constructor(private readonly entityManager: EntityManager){}

    /**
     * 
     * @param request 
     * @param response 
     * @param next 
     */
    async use(request: Request, response: Response, next: NextFunction) {

        // Headers
        response.setHeader('Access-Control-Allow-Origin', 'http://localhost:5173');
        response.setHeader('Access-Control-Allow-Methods', 'POST,GET,PUT,DELETE,OPTIONS,PATCH');
        response.setHeader('Access-Control-Allow-Headers', 'Content-Type,Authorization,Accept');
        response.setHeader('Access-Control-Allow-Credentials', 'true');

        if(request.method == "OPTIONS"){
            response.sendStatus(200);
            return;
        }

        if(!request.baseUrl.startsWith("/api/")){ // Is a static content element
            next();
            return;
        }

        let goNext = false;
        try{
            const url = request.baseUrl;
            if(this.exclPaths.includes(url)){
                goNext = true;
            }else{
                const session = request.cookies['session'];
                const data: any = jwt.verify(session, process.env.JWT as string);
                if(data && data.id){
                    
                    request['id'] = data.id;

                    // Renew cookie
                    response.cookie(
                        'session', 
                        session, 
                        {
                            sameSite: "none",
                            httpOnly: true,
                            maxAge  : 1000 * 60 * 60, // 1h
                            secure  : true
                        }
                    );

                    if(request.baseUrl != "/api/v1/events/listEvents"){

                        // Try to encode body
                        let encBody: string | null = null;
                        try{
                            if(request.body && request.baseUrl != "/api/v1/media/loadMedia"){
                                encBody = JSON.stringify(request.body);
                            }
                        }catch(e: any){
                            this.logger.error(e.message);
                        }

                        await this.entityManager.query(
                            `
                                INSERT INTO events (
                                    method,
                                    pathname,
                                    body,
                                    user
                                ) VALUES (
                                    ?, ?, ?, ?
                                )
                            `,
                            [
                                request.method,
                                request.originalUrl,
                                encBody,
                                data.name
                            ]
                        );

                    }

                    goNext = true;
                }
            }
        }catch(e: any){
            this.logger.error(e.message);
        }finally{
            if(goNext){
                next();
            }else{
                response.sendStatus(401);
            }
        }
    }

}