import { Express }       from 'express-serve-static-core';
import express           from 'express';
import { StatusCodes }   from 'http-status-codes';
import ExerciseManager   from '../managers/ExerciseManager.js';
import AssignmentManager from '../managers/AssignmentManager.js';


type GetFunction = (id: string | number, ...args: Array<unknown>) => Promise<unknown>


class ParamsCallbackManager {
    protected listenParam(paramName: string, backend: Express, getFunction: GetFunction, args: Array<unknown>, indexName: string) {
        backend.param(paramName, (req: express.Request, res: express.Response, next: express.NextFunction, id: string | number) => {
            void getFunction(id, ...args).then(result => {
                if ( result ) {
                    this.initBoundParams(req);
                    (req.boundParams as Record<string, unknown>)[indexName] = result;

                    next();
                } else {
                    req.session.sendResponse(res, StatusCodes.NOT_FOUND, {}, 'Param bounding failed: ' + paramName);
                }
            });
        });
    }

    initBoundParams(req: express.Request) {
        if ( !req.boundParams ) {
            req.boundParams = {
                assignment: undefined,
                exercise  : undefined
            };
        }
    }

    registerOnBackend(backend: Express) {
        this.listenParam('assignmentNameOrUrl', backend, (AssignmentManager.get as GetFunction).bind(AssignmentManager), [ {
            exercises: true,
            staff    : true
        } ], 'assignment');

        this.listenParam('exerciseIdOrUrl', backend, (ExerciseManager.get as GetFunction).bind(ExerciseManager), [ {
            assignment: true,
            members   : true,
            results   : true
        } ], 'exercise');
    }
}


export default new ParamsCallbackManager();