import { ApiError } from "./ApiError.js";
import { getNormalizedRole } from "../middlewares/authMiddleware.js";

/** With verifier for review — executor must not access work until returned (status 4). */
const ASSESSMENT_STATUS_VERIFICATION_REQUIRED = 5;

function isAdminRequest(req) {
  if (!req?.user) return false;
  const adminRoleName = (process.env.JWT_ADMIN_ROLE || "admin")
    .trim()
    .toLowerCase();
  return getNormalizedRole(req.user) === adminRoleName;
}

/**
 * Risk observations / snaps / answer submissions belong to the assigned executor
 * when one is set (keeps non-executors from recording observations on the case).
 * @param {import('express').Request|null} req - When set, admin JWT skips this check.
 */
export function assertCurrentUserIsAssessmentExecutor(userId, executorId, req = null) {
  if (req && isAdminRequest(req)) return;
  if (executorId == null || executorId === "") return;
  const uid = Number(userId);
  if (!Number.isInteger(uid) || uid <= 0) {
    throw new ApiError(401, "Could not resolve user from token");
  }
  if (Number(executorId) !== uid) {
    throw new ApiError(
      403,
      "Only the assigned executor can record or submit observations for this assessment."
    );
  }
}

/**
 * Verifier-only actions (report / return) — current user must match `verifier_id`.
 */
export function assertCurrentUserIsAssessmentVerifier(userId, verifierId, req = null) {
  if (req && isAdminRequest(req)) return;
  if (verifierId == null || verifierId === "") {
    throw new ApiError(400, "No verifier is assigned to this assessment.");
  }
  const uid = Number(
    userId ?? (req?.user?.user_id ?? req?.user?.userId ?? req?.user?.id ?? req?.user?.sub)
  );
  if (!Number.isInteger(uid) || uid <= 0) {
    throw new ApiError(401, "Could not resolve user from token");
  }
  if (Number(verifierId) !== uid) {
    throw new ApiError(403, "Only the assigned verifier can perform this action on this assessment.");
  }
}

/**
 * While an assessment is awaiting verifier review (status 5), the assigned executor may not view or change snaps/answers until the verifier returns it (status 4).
 */
export function assertExecutorNotBlockedByPendingVerification(req, row) {
  if (!row) return;
  if (isAdminRequest(req)) return;
  const uid = Number(
    req.user?.user_id ?? req.user?.userId ?? req.user?.id ?? req.user?.sub
  );
  if (!Number.isInteger(uid) || uid <= 0) return;
  const { executor_id, assessment_status_id } = row;
  if (executor_id == null || executor_id === "") return;
  if (Number(executor_id) !== uid) return;
  if (Number(assessment_status_id) !== ASSESSMENT_STATUS_VERIFICATION_REQUIRED) return;
  throw new ApiError(
    403,
    "This assessment is currently awaiting verifier review (status: Verification Required). " +
    "You cannot add or change observations until the verifier returns it to you. " +
    "Ask the verifier to use 'Return to Executor', or ask an admin to reset the assessment status."
  );
}

/**
 * Read-only access to an assessment’s snaps (list, image) for uploader, executor, verifier, or admin.
 * @param {object} row - `orac_assessments` row with uploader_user_id, executor_id, verifier_id, assessment_status_id
 */
export function assertUserCanViewAssessmentSnapsFromRow(req, row) {
  if (!row) {
    throw new ApiError(404, "Assessment not found");
  }
  if (isAdminRequest(req)) {
    return;
  }
  const uid = Number(
    req.user?.user_id ?? req.user?.userId ?? req.user?.id ?? req.user?.sub
  );
  if (!Number.isInteger(uid) || uid <= 0) {
    throw new ApiError(401, "Could not resolve user from token");
  }
  const { uploader_user_id, executor_id, verifier_id } = row;
  if (Number(uploader_user_id) === uid) {
    return;
  }
  if (executor_id != null && executor_id !== "" && Number(executor_id) === uid) {
    // Read-only listing / images: executor may review saved snaps even while status is
    // verification-required (5). Mutations (POST/PUT/DELETE snaps) still use
    // assertExecutorNotBlockedByPendingVerification in the snaps controller.
    return;
  }
  if (verifier_id != null && verifier_id !== "" && Number(verifier_id) === uid) {
    return;
  }
  throw new ApiError(403, "Not allowed to view snaps for this assessment.");
}
