import { Request, Response, NextFunction } from 'express';
import { sendError } from '../utils/response';
import { ErrorCode, Role } from '@saferoute/constants';

export function requireRoles(...allowedRoles: (Role | string)[]) {
  return (req: Request, res: Response, next: NextFunction): void => {
    if (!req.user) {
      sendError(res, ErrorCode.ACCESS_DENIED, 'Authentication required.', {}, 403);
      return;
    }

    const userRoles = req.user.roles;
    const hasPermission = allowedRoles.some((role) => userRoles.includes(role));

    if (!hasPermission) {
      sendError(
        res,
        ErrorCode.ACCESS_DENIED,
        'You do not have permission to perform this action.',
        { requiredRoles: allowedRoles, userRoles },
        403
      );
      return;
    }

    next();
  };
}

export function enforceSchoolScope(schoolIdParam = 'schoolId') {
  return (req: Request, res: Response, next: NextFunction): void => {
    if (!req.user) {
      sendError(res, ErrorCode.ACCESS_DENIED, 'Authentication required.', {}, 403);
      return;
    }

    const platformWideRoles = [
      Role.OWNER,
      Role.CTO,
      Role.OPERATIONS_MANAGER,
      Role.FINANCE_MANAGER,
      Role.SUPPORT_EXECUTIVE,
      Role.HARDWARE_TECHNICIAN,
      Role.INSURANCE_COORDINATOR,
    ];

    const hasPlatformAccess = req.user.roles.some((r) => platformWideRoles.includes(r as Role));
    if (hasPlatformAccess) {
      next();
      return;
    }

    const requestedSchoolId = req.params[schoolIdParam];
    if (requestedSchoolId && !req.user.schoolIds.includes(requestedSchoolId)) {
      sendError(
        res,
        ErrorCode.ACCESS_DENIED,
        'You do not have access to this school.',
        {},
        403
      );
      return;
    }

    next();
  };
}

export function enforceParentChildScope() {
  return async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    if (!req.user) {
      sendError(res, ErrorCode.ACCESS_DENIED, 'Authentication required.', {}, 403);
      return;
    }

    const isParentOrGuardian =
      req.user.roles.includes(Role.PARENT) || req.user.roles.includes(Role.GUARDIAN);

    if (!isParentOrGuardian) {
      next();
      return;
    }

    next();
  };
}
