import express           from 'express';
import { StatusCodes }   from 'http-status-codes';
import SecurityCheckType from '../types/SecurityCheckType';
import logger            from '../shared/logging/WinstonLogger';
import AssignmentManager from '../managers/AssignmentManager';


class SecurityMiddleware {
    // First check if connected then check if at least ONE rule match. It's NOT an AND but it's a OR function.
    check(checkIfConnected: boolean, ...checkTypes: Array<SecurityCheckType>): (req: express.Request, res: express.Response, next: express.NextFunction) => void {
        return async (req: express.Request, res: express.Response, next: express.NextFunction) => {
            if ( checkIfConnected ) {
                if ( req.session.profile === null || req.session.profile === undefined ) {
                    return req.session.sendResponse(res, StatusCodes.UNAUTHORIZED);
                }
            }

            let isAllowed = checkTypes.length === 0;

            if ( !isAllowed ) {
                for ( const checkType of checkTypes ) {
                    try {
                        switch ( String(checkType) ) {
                            case SecurityCheckType.TEACHING_STAFF:
                                isAllowed = isAllowed || req.session.profile.isTeachingStaff;
                                break;
                            case SecurityCheckType.ASSIGNMENT_STAFF:
                                isAllowed = isAllowed || await AssignmentManager.isUserAllowedToAccessAssignment(req.boundParams.assignment!, req.session.profile);
                                break;
                            case SecurityCheckType.ASSIGNMENT_IS_PUBLISHED:
                                isAllowed = isAllowed || (req.boundParams.assignment?.published ?? false);
                                break;
                            case SecurityCheckType.EXERCISE_SECRET:
                                isAllowed = isAllowed || (req.headers.exercisesecret as string | undefined) === req.boundParams.exercise!.secret;
                                break;
                            default:
                                break;
                        }
                    } catch ( e ) {
                        logger.error('Security check failed !!! => ' + e);
                        isAllowed = isAllowed || false;
                    }
                }
            }

            if ( !isAllowed ) {
                return req.session.sendResponse(res, StatusCodes.FORBIDDEN);
            }

            return next();
        };
    }
}


export default new SecurityMiddleware();