import { EXECUTOR_VERIFIER_ROLE_ID, ROLE_IDS } from "../constants/hseRoles.js";
import {
  assertSessionToken,
  TokenClaimError,
  verifyToken as verifyHseToken,
} from "../../../shared/hse-jwt/index.js";

const API_AUD = "swi";

function getTokenFromHeader(req) {
  const authHeader = req.headers.authorization || "";
  const [scheme, token] = authHeader.split(" ");
  if (scheme !== "Bearer" || !token) {
    return null;
  }
  return token;
}

function envRole(name, fallback) {
  return String(process.env[name] || fallback)
    .trim()
    .toLowerCase()
    .replace(/\s*\/\s*/g, "/");
}

function normalizedRoleFromIds(roleIds) {
  if (!Array.isArray(roleIds) || roleIds.length === 0) {
    return null;
  }
  const ids = roleIds.map((id) => Number(id)).filter((n) => !Number.isNaN(n));
  const admin = envRole("JWT_ADMIN_ROLE", "admin");
  const user = envRole("JWT_USER_ROLE", "user");
  const exec = envRole("JWT_EXECUTOR_ROLE", "executer/varifier");
  const support = envRole("JWT_SUPPORT_ROLE", "support");
  if (ids.includes(ROLE_IDS.ADMIN)) return admin;
  if (ids.includes(EXECUTOR_VERIFIER_ROLE_ID)) return exec;
  if (ids.includes(ROLE_IDS.USER)) return user;
  if (ids.includes(ROLE_IDS.SUPPORT)) return support;
  return null;
}

export function getNormalizedRole(userPayload) {
  const roleValue =
    userPayload?.role ??
    userPayload?.role_name ??
    userPayload?.roleName ??
    userPayload?.user_role ??
    userPayload?.userRole ??
    userPayload?.type ??
    (Array.isArray(userPayload?.roles) && userPayload.roles.length > 0
      ? userPayload.roles[0]
      : undefined);

  if (typeof roleValue === "string" && roleValue.trim()) {
    return roleValue.trim().toLowerCase().replace(/\s*\/\s*/g, "/");
  }

  if (userPayload?.isAdmin === true) {
    return envRole("JWT_ADMIN_ROLE", "admin");
  }

  const fromIds = normalizedRoleFromIds(userPayload?.roleIds);
  if (fromIds) {
    return fromIds;
  }

  return "";
}

export function getJwtUserId(userPayload) {
  const raw =
    userPayload?.user_id ??
    userPayload?.userId ??
    userPayload?.id ??
    userPayload?.sub;
  if (raw == null || raw === "") {
    return null;
  }
  return String(raw);
}

function verifyAuthToken(token) {
  const secret = process.env.JWT_SECRET;
  if (typeof secret === "string" && secret.trim() !== "") {
    const decoded = verifyHseToken(token, secret.trim());
    assertSessionToken(decoded, API_AUD);
    return decoded;
  }
  if (process.env.NODE_ENV === "test") {
    const decoded = verifyHseToken(token, "test-jwt-secret");
    assertSessionToken(decoded, API_AUD);
    return decoded;
  }
  throw new Error("JWT_SECRET is not configured");
}

export function requireAuth(req, res, next) {
  const token = getTokenFromHeader(req);
  if (!token) {
    return res
      .status(401)
      .json({ message: "Missing or invalid Authorization header" });
  }

  try {
    req.user = verifyAuthToken(token);
    return next();
  } catch (error) {
    if (error instanceof TokenClaimError) {
      return res.status(error.status).json({ message: error.message });
    }
    return res.status(401).json({ message: "Invalid or expired token" });
  }
}

export function requireAdmin(req, res, next) {
  const token = getTokenFromHeader(req);
  if (!token) {
    return res
      .status(401)
      .json({ message: "Missing or invalid Authorization header" });
  }

  try {
    req.user = verifyAuthToken(token);
  } catch (error) {
    if (error instanceof TokenClaimError) {
      return res.status(error.status).json({ message: error.message });
    }
    return res.status(401).json({ message: "Invalid or expired token" });
  }

  const adminRoleName = (process.env.JWT_ADMIN_ROLE || "admin")
    .trim()
    .toLowerCase();
  const role = getNormalizedRole(req.user);

  if (role !== adminRoleName) {
    return res.status(403).json({ message: "Admin access required" });
  }

  return next();
}
