import type { RequisitionStatus, Role } from "@prisma/client";

// Requisition lifecycle state machine — mirrors the PO state machine
// (lib/po-state-machine.ts) and the reconciled spec (Crewing-Implementation-Spec
// §5.2): OPEN → SHORTLISTING → PROPOSING → INTERVIEWING → SELECTED → FILLED,
// with CANCELLED reachable from OPEN/SHORTLISTING (Manager).
//
// The intermediate stage advances are driven by the recruitment pipeline that
// lands in Phase 3; they are modelled here now so the transitions, allowed
// roles and audit are settled and testable. Phase 2 wires raise (create OPEN)
// and cancel via server actions; selection is Manager-only (spec §6).

export type RequisitionAction =
  | "start_shortlisting"
  | "mark_proposing"
  | "start_interviewing"
  | "mark_selected"
  | "mark_filled";

interface Transition {
  to: RequisitionStatus;
  allowedRoles: Role[];
  requiresNote: boolean;
}

type TransitionMap = Partial<Record<RequisitionAction, Transition>>;

// MPO (MANNING) and Manager source recruitment; final selection is Manager-only.
const SOURCING_ROLES: Role[] = ["MANNING", "MANAGER", "SUPERUSER"];
const MANAGER_ROLES: Role[] = ["MANAGER", "SUPERUSER"];

const TRANSITIONS: Partial<Record<RequisitionStatus, TransitionMap>> = {
  OPEN: {
    start_shortlisting: { to: "SHORTLISTING", allowedRoles: SOURCING_ROLES, requiresNote: false },
  },
  SHORTLISTING: {
    mark_proposing: { to: "PROPOSING", allowedRoles: SOURCING_ROLES, requiresNote: false },
  },
  PROPOSING: {
    start_interviewing: { to: "INTERVIEWING", allowedRoles: SOURCING_ROLES, requiresNote: false },
  },
  INTERVIEWING: {
    // Final selection of a candidate is a Manager approval (spec §6).
    mark_selected: { to: "SELECTED", allowedRoles: MANAGER_ROLES, requiresNote: false },
  },
  SELECTED: {
    // The onboarding side-effect (Phase 3) fills the vacancy.
    mark_filled: { to: "FILLED", allowedRoles: SOURCING_ROLES, requiresNote: false },
  },
};

export function getTransition(from: RequisitionStatus, action: RequisitionAction): Transition | null {
  return TRANSITIONS[from]?.[action] ?? null;
}

export function canPerformAction(
  from: RequisitionStatus,
  action: RequisitionAction,
  role: Role
): boolean {
  return getTransition(from, action)?.allowedRoles.includes(role) ?? false;
}

export function getAvailableActions(status: RequisitionStatus, role: Role): RequisitionAction[] {
  const map = TRANSITIONS[status];
  if (!map) return [];
  return (Object.keys(map) as RequisitionAction[]).filter((action) =>
    canPerformAction(status, action, role)
  );
}

export function requiresNote(from: RequisitionStatus, action: RequisitionAction): boolean {
  return getTransition(from, action)?.requiresNote ?? false;
}

// ── Cancellation (orthogonal) ────────────────────────────────────────────────
// A requisition may be withdrawn while it is still early in the pipeline — OPEN
// or SHORTLISTING (spec §5.2) — and a reason is required. WHO may cancel is the
// `cancel_requisition` grant (spec §6: MPO + Manager + SuperUser); the actions
// enforce that permission, and CANCEL_ROLES mirrors it so the state machine and
// the matrix agree. Modelled separately from TRANSITIONS, like PO CANCEL_ROLES.

export const CANCEL_ROLES: Role[] = ["MANNING", "MANAGER", "SUPERUSER"];
export const CANCELLABLE_FROM: RequisitionStatus[] = ["OPEN", "SHORTLISTING"];

export function canCancel(from: RequisitionStatus, role: Role): boolean {
  return CANCELLABLE_FROM.includes(from) && CANCEL_ROLES.includes(role);
}
