import type { Role } from "@prisma/client";
import { SUBMITTER_VIEW_ALL_ENABLED } from "./feature-flags";

export type Permission =
  | "create_po"
  | "submit_po"
  | "edit_own_draft_po"
  | "view_own_pos"
  | "view_all_pos"
  | "approve_po"
  | "reject_po"
  | "cancel_po"
  | "request_edits"
  | "request_vendor_id"
  | "process_payment"
  | "confirm_receipt"
  | "view_analytics"
  | "export_reports"
  | "manage_users"
  | "manage_vendors"
  | "create_vendor"
  | "manage_vessels_accounts"
  | "manage_products"
  | "manage_sites"
  | "manage_delivery_locations"
  | "manage_terms"
  // ── Crewing (feature-flagged) — mirrors Crewing-Implementation-Spec §6 ──────
  | "raise_requisition"
  | "request_relief_cover"
  | "convert_relief_to_requisition"
  | "cancel_requisition"
  | "view_requisitions"
  | "manage_candidates"
  | "record_reference_check"
  | "record_interview_result"
  | "request_interview_waiver"
  | "approve_interview_waiver"
  | "approve_salary_structure"
  | "select_candidate"
  | "onboard_crew"
  | "sign_off_crew"
  | "view_crew_records"
  | "upload_crew_records"
  | "issue_ppe"
  | "apply_leave"
  | "decide_leave"
  | "record_attendance"
  | "view_attendance"
  | "verify_site_records"
  | "verify_bank_epf"
  | "raise_appraisal"
  | "verify_appraisal"
  | "approve_appraisal"
  | "generate_wage_report"
  | "approve_wage_report"
  | "view_wage_report"
  | "manage_ranks"
  // Office/admin crew management — direct placement (no requisition), crew CRUD,
  // and per-vessel rank-strength config. Held by Manager + Admin (+ SuperUser).
  | "manage_crew";

// Purchasing / admin permissions (the original PPMS matrix). SITE_STAFF is a
// crewing-only role and holds no purchasing permissions.
const PO_ROLE_PERMISSIONS: Record<Role, Permission[]> = {
  TECHNICAL: ["create_po", "submit_po", "edit_own_draft_po", "view_own_pos", "confirm_receipt", "create_vendor"],
  MANNING: ["create_po", "submit_po", "edit_own_draft_po", "view_own_pos", "confirm_receipt", "create_vendor"],
  ACCOUNTS: ["view_all_pos", "process_payment", "manage_vendors", "create_vendor"],
  MANAGER: [
    "create_po",
    "submit_po",
    "edit_own_draft_po",
    "view_own_pos",
    "view_all_pos",
    "approve_po",
    "reject_po",
    "cancel_po",
    "request_edits",
    "request_vendor_id",
    "view_analytics",
    "export_reports",
    "manage_vendors",
    "create_vendor",
    "manage_vessels_accounts",
    "manage_products",
    "manage_sites",
    "manage_delivery_locations",
    "manage_terms",
    "confirm_receipt",
    "process_payment"
  ],
  SUPERUSER: [
    "create_po",
    "submit_po",
    "edit_own_draft_po",
    "view_own_pos",
    "view_all_pos",
    "approve_po",
    "reject_po",
    "cancel_po",
    "request_edits",
    "request_vendor_id",
    "process_payment",
    "confirm_receipt",
    "view_analytics",
    "export_reports",
    "create_vendor",
    "manage_delivery_locations",
    "manage_terms",
  ],
  AUDITOR: ["view_own_pos", "view_all_pos", "view_analytics", "export_reports"],
  ADMIN: [
    "view_own_pos",
    "view_all_pos",
    "view_analytics",
    "export_reports",
    "manage_users",
    "manage_vendors",
    "create_vendor",
    "manage_vessels_accounts",
    "manage_products",
    "manage_sites",
    "manage_delivery_locations",
    "manage_terms",
  ],
  SITE_STAFF: [],
};

// Crewing permissions — a verbatim transcription of the §6 grant matrix in
// wiki Crewing-Implementation-Spec. Gating these is harmless until the screens
// land (the module is behind NEXT_PUBLIC_CREWING_ENABLED). Notes from the spec:
// MPO (MANNING) has NO attendance/leave; decide_leave/approve_* and selection are
// Manager-only; manage_ranks is Manager + Admin (not SuperUser).
const CREWING_ROLE_PERMISSIONS: Record<Role, Permission[]> = {
  TECHNICAL: [],
  SITE_STAFF: [
    "request_relief_cover",
    "sign_off_crew",
    "view_crew_records",
    "upload_crew_records",
    "issue_ppe",
    "apply_leave",
    "record_attendance",
    "view_attendance",
    "raise_appraisal",
  ],
  MANNING: [
    "raise_requisition",
    "convert_relief_to_requisition",
    "cancel_requisition",
    "view_requisitions",
    "manage_candidates",
    "record_reference_check",
    "record_interview_result",
    "request_interview_waiver",
    "onboard_crew",
    "sign_off_crew",
    "view_crew_records",
    "upload_crew_records",
    "issue_ppe",
    "verify_site_records",
    "verify_appraisal",
  ],
  ACCOUNTS: ["view_crew_records", "verify_bank_epf", "view_wage_report"],
  MANAGER: [
    "raise_requisition",
    "convert_relief_to_requisition",
    "cancel_requisition",
    "view_requisitions",
    "manage_candidates",
    "record_reference_check",
    "record_interview_result",
    "approve_interview_waiver",
    "approve_salary_structure",
    "select_candidate",
    "onboard_crew",
    "sign_off_crew",
    "view_crew_records",
    "upload_crew_records",
    "issue_ppe",
    "apply_leave",
    "decide_leave",
    "view_attendance",
    "verify_site_records",
    "raise_appraisal",
    "verify_appraisal",
    "approve_appraisal",
    "generate_wage_report",
    "approve_wage_report",
    "view_wage_report",
    "manage_ranks",
    "manage_crew",
  ],
  SUPERUSER: [
    "raise_requisition",
    "request_relief_cover",
    "convert_relief_to_requisition",
    "cancel_requisition",
    "view_requisitions",
    "manage_candidates",
    "record_reference_check",
    "record_interview_result",
    "request_interview_waiver",
    "approve_interview_waiver",
    "approve_salary_structure",
    "select_candidate",
    "onboard_crew",
    "sign_off_crew",
    "view_crew_records",
    "upload_crew_records",
    "issue_ppe",
    "apply_leave",
    "decide_leave",
    "record_attendance",
    "view_attendance",
    "verify_site_records",
    "verify_bank_epf",
    "raise_appraisal",
    "verify_appraisal",
    "approve_appraisal",
    "generate_wage_report",
    "approve_wage_report",
    "view_wage_report",
    "manage_crew",
  ],
  AUDITOR: ["view_requisitions", "view_crew_records", "view_attendance", "view_wage_report"],
  ADMIN: ["view_requisitions", "view_crew_records", "view_wage_report", "manage_ranks", "manage_crew"],
};

const ROLE_PERMISSIONS: Record<Role, Permission[]> = Object.fromEntries(
  (Object.keys(PO_ROLE_PERMISSIONS) as Role[]).map((role) => [
    role,
    [...PO_ROLE_PERMISSIONS[role], ...CREWING_ROLE_PERMISSIONS[role]],
  ])
) as Record<Role, Permission[]>;

export function hasPermission(role: Role, permission: Permission): boolean {
  return ROLE_PERMISSIONS[role]?.includes(permission) ?? false;
}

export function requirePermission(role: Role, permission: Permission): void {
  if (!hasPermission(role, permission)) {
    throw new Error(`Forbidden: role ${role} lacks permission ${permission}`);
  }
}

export function getPermissions(role: Role): Permission[] {
  return ROLE_PERMISSIONS[role] ?? [];
}

// ── Submitter roles & feature-flagged view-all ────────────────────────────────
// Submitters raise and track their own POs. The two "submitter" roles below hold
// `view_own_pos` but not `view_all_pos`.

export const SUBMITTER_ROLES: Role[] = ["TECHNICAL", "MANNING"];

export function isSubmitterRole(role: Role): boolean {
  return SUBMITTER_ROLES.includes(role);
}

/**
 * Feature-flagged: when NEXT_PUBLIC_SUBMITTER_VIEW_ALL_ENABLED=true, submitters may
 * read & export every PO (not just their own) and reach the History page. This is a
 * read-only widening — it does not grant approval, payment, or edit rights.
 */
export function submitterCanViewAll(role: Role): boolean {
  return SUBMITTER_VIEW_ALL_ENABLED && isSubmitterRole(role);
}

/**
 * Whether a role may view/export any PO, not just the ones they submitted.
 * True for `view_all_pos` holders (ACCOUNTS, MANAGER, SUPERUSER, AUDITOR, ADMIN) and,
 * when the feature flag is on, for submitters too.
 */
export function canViewAllPos(role: Role): boolean {
  return hasPermission(role, "view_all_pos") || submitterCanViewAll(role);
}
