import type { NextFunction, Request, Response } from "express";
import { verifyAccessToken } from "../config/jwt.js";
import role from "../constants/role.js";

export const permissionMiddleware = (requiredRoleId: number = role.BOTH) => {
  return (req: Request, res: Response, next: NextFunction): void => {
    let jwtRoleId = req.user?.roleId !== undefined ? Number(req.user.roleId) : undefined;

    if (jwtRoleId === undefined) {
      const authHeader = req.headers.authorization;

      if (!authHeader || !authHeader.startsWith("Bearer ")) {
        res.status(401).json({ message: "Authorization token is required." });
        return;
      }

      const token = authHeader.split(" ")[1];

      try {
        const payload = verifyAccessToken(token as string);
        const normalizedId = payload.id ?? payload.userId;
        if (normalizedId === undefined || normalizedId === null) {
          res.status(401).json({ message: "Invalid token payload: user id is missing." });
          return;
        }

        req.user = {
          ...payload,
          id: normalizedId,
        };

        jwtRoleId = Number(payload.roleId);
      } catch (error) {
        res.status(401).json({ message: error instanceof Error ? error.message : "Unauthorized" });
        return;
      }
    }

    // Check if the required role is BOTH (3) - allow Super Admin (1) and Staff (2)
    if (requiredRoleId === role.BOTH || requiredRoleId === 3) {
      if (jwtRoleId !== role.ADMIN && jwtRoleId !== role.STAFF) {
        res.status(401).json({ message: "Access denied. Insufficient permission." });
        return;
      }

      // Deny edit (PUT, PATCH) and delete (DELETE) operations for Staff role
      if (jwtRoleId === role.STAFF) {
        const method = req.method.toUpperCase();
        if (["PUT", "PATCH", "DELETE"].includes(method)) {
          res.status(412).json({
            message: "Access denied. Staff members are not permitted to edit or delete records.",
          });
          return;
        }
      }

      next();
      return;
    }

    if (jwtRoleId !== Number(requiredRoleId)) {
      res.status(401).json({ message: "Access denied. Insufficient permission." });
      return;
    }

    next();
  };
};
