import type { TransitionTable, WorkflowDefinition } from './machine.js';

/**
 * Admission application lifecycle.
 *
 * One table serves all four admission tracks from SPEC.md §13. The tracks
 * differ by which *path* they take through the graph, not by special-casing in
 * code — which is what keeps "Medicine admissions rules are distinct from
 * undergraduate admissions" (SPEC.md §33.18) true without a parallel machine:
 *
 *   Freshman     SUBMITTED → UNDER_REVIEW → EXAM_SCHEDULED → EXAM_COMPLETED
 *                → REQUIREMENTS_PENDING → REQUIREMENTS_COMPLETE → FOR_INTERVIEW
 *                → DEAN_INTERVIEW_* → ACCEPTED → ENROLLMENT_IN_PROGRESS → ENROLLED
 *
 *   Transferee   SUBMITTED → UNDER_REVIEW → FOR_EVALUATION → EVALUATED
 *                → REQUIREMENTS_PENDING → … (as above)
 *
 *   Medicine     SUBMITTED → UNDER_REVIEW → SCREENING → SCREENING_PASSED
 *                → REQUIREMENTS_PENDING → REQUIREMENTS_COMPLETE → FOR_INTERVIEW
 *                → PANEL_INTERVIEW_* → DEAN_INTERVIEW_* → ACCEPTED → …
 *
 * Which path is offered is decided by the application's `track`, resolved from
 * configuration (`AdmissionTrack`), not hard-coded.
 */
export const APPLICATION_STATUSES = [
  'DRAFT',
  'SUBMITTED',
  'UNDER_REVIEW',
  'SCREENING',
  'SCREENING_PASSED',
  'SCREENING_FAILED',
  'EXAM_SCHEDULED',
  'EXAM_COMPLETED',
  'FOR_EVALUATION',
  'EVALUATED',
  'REQUIREMENTS_PENDING',
  'REQUIREMENTS_COMPLETE',
  'FOR_INTERVIEW',
  'PANEL_INTERVIEW_SCHEDULED',
  'PANEL_INTERVIEW_COMPLETED',
  'DEAN_INTERVIEW_SCHEDULED',
  'DEAN_INTERVIEW_COMPLETED',
  'WAITLISTED',
  'ACCEPTED',
  'DEFERRED',
  'ENROLLMENT_IN_PROGRESS',
  'ENROLLED',
  'REJECTED',
  'WITHDRAWN',
] as const;

export type ApplicationStatus = (typeof APPLICATION_STATUSES)[number];

const transitions: TransitionTable<ApplicationStatus> = {
  DRAFT: {
    // The applicant submits their own draft; no staff permission required.
    SUBMITTED: { label: 'Submit the application' },
    WITHDRAWN: { label: 'Withdraw the application', requiresReason: true },
  },

  SUBMITTED: {
    UNDER_REVIEW: { permission: 'application.review', label: 'Begin reviewing the application' },
    REJECTED: {
      permission: 'application.approve',
      requiresReason: true,
      label: 'Reject the application',
    },
    WITHDRAWN: {
      permission: 'application.manage',
      requiresReason: true,
      label: 'Withdraw the application',
    },
  },

  UNDER_REVIEW: {
    // Medicine track: initial screening against TOR + NMAT.
    SCREENING: { permission: 'application.review', label: 'Send for initial screening' },
    // Undergraduate track: entrance examination.
    EXAM_SCHEDULED: { permission: 'exam.manage', label: 'Schedule the entrance examination' },
    // Transferee track: Dean subject evaluation precedes everything else.
    FOR_EVALUATION: {
      permission: 'application.review',
      label: 'Send for subject evaluation',
    },
    // Tracks configured without an exam step go straight to requirements.
    REQUIREMENTS_PENDING: {
      permission: 'application.review',
      label: 'Request admission requirements',
    },
    REJECTED: {
      permission: 'application.approve',
      requiresReason: true,
      label: 'Reject the application',
    },
    WITHDRAWN: {
      permission: 'application.manage',
      requiresReason: true,
      label: 'Withdraw the application',
    },
  },

  SCREENING: {
    SCREENING_PASSED: {
      permission: 'application.review',
      requires: ['NMAT_THRESHOLD_MET'],
      label: 'Record a passing initial screening',
    },
    SCREENING_FAILED: {
      permission: 'application.review',
      requiresReason: true,
      label: 'Record a failed initial screening',
    },
  },

  SCREENING_PASSED: {
    REQUIREMENTS_PENDING: {
      permission: 'application.review',
      label: 'Request the complete requirements',
    },
    WITHDRAWN: {
      permission: 'application.manage',
      requiresReason: true,
      label: 'Withdraw the application',
    },
  },

  SCREENING_FAILED: {
    REJECTED: {
      permission: 'application.approve',
      requiresReason: true,
      label: 'Reject the application',
    },
    // An applicant may be re-screened if they submit a later NMAT result.
    SCREENING: { permission: 'application.review', label: 'Re-open initial screening' },
  },

  EXAM_SCHEDULED: {
    EXAM_COMPLETED: {
      permission: 'exam.result.manage',
      requires: ['EXAM_RESULT_RECORDED'],
      label: 'Record the examination result',
    },
    // Rescheduling returns the application to review so a new slot is booked.
    UNDER_REVIEW: {
      permission: 'exam.manage',
      requiresReason: true,
      label: 'Cancel the examination booking',
    },
    WITHDRAWN: {
      permission: 'application.manage',
      requiresReason: true,
      label: 'Withdraw the application',
    },
  },

  EXAM_COMPLETED: {
    REQUIREMENTS_PENDING: {
      permission: 'application.review',
      label: 'Request admission requirements',
    },
    REJECTED: {
      permission: 'application.approve',
      requiresReason: true,
      label: 'Reject the application',
    },
  },

  FOR_EVALUATION: {
    EVALUATED: {
      permission: 'transfer_credit.evaluate',
      label: 'Record the subject evaluation',
    },
    WITHDRAWN: {
      permission: 'application.manage',
      requiresReason: true,
      label: 'Withdraw the application',
    },
  },

  EVALUATED: {
    REQUIREMENTS_PENDING: {
      permission: 'application.review',
      label: 'Request admission requirements',
    },
    EXAM_SCHEDULED: {
      permission: 'exam.manage',
      label: 'Schedule the entrance examination',
    },
    REJECTED: {
      permission: 'application.approve',
      requiresReason: true,
      label: 'Reject the application',
    },
  },

  REQUIREMENTS_PENDING: {
    REQUIREMENTS_COMPLETE: {
      permission: 'requirement.review',
      requires: ['REQUIREMENTS_COMPLETE'],
      label: 'Confirm the requirements are complete',
    },
    WITHDRAWN: {
      permission: 'application.manage',
      requiresReason: true,
      label: 'Withdraw the application',
    },
  },

  REQUIREMENTS_COMPLETE: {
    FOR_INTERVIEW: { permission: 'application.review', label: 'Endorse for interview' },
    // Tracks configured without an interview step decide directly.
    ACCEPTED: { permission: 'application.approve', label: 'Accept the applicant' },
    REJECTED: {
      permission: 'application.approve',
      requiresReason: true,
      label: 'Reject the application',
    },
  },

  FOR_INTERVIEW: {
    PANEL_INTERVIEW_SCHEDULED: {
      permission: 'interview.schedule',
      label: 'Schedule the panel interview',
    },
    DEAN_INTERVIEW_SCHEDULED: {
      permission: 'interview.schedule',
      label: 'Schedule the Dean interview',
    },
  },

  PANEL_INTERVIEW_SCHEDULED: {
    PANEL_INTERVIEW_COMPLETED: {
      permission: 'interview.evaluate',
      requires: ['PANEL_INTERVIEW_COMPLETED'],
      label: 'Record the panel interview evaluation',
    },
    FOR_INTERVIEW: {
      permission: 'interview.schedule',
      requiresReason: true,
      label: 'Cancel the panel interview',
    },
  },

  PANEL_INTERVIEW_COMPLETED: {
    DEAN_INTERVIEW_SCHEDULED: {
      permission: 'interview.schedule',
      label: 'Schedule the Dean interview',
    },
    REJECTED: {
      permission: 'application.approve',
      requiresReason: true,
      label: 'Reject the application',
    },
  },

  DEAN_INTERVIEW_SCHEDULED: {
    DEAN_INTERVIEW_COMPLETED: {
      permission: 'interview.evaluate',
      requires: ['INTERVIEW_COMPLETED'],
      label: 'Record the Dean interview evaluation',
    },
    FOR_INTERVIEW: {
      permission: 'interview.schedule',
      requiresReason: true,
      label: 'Cancel the Dean interview',
    },
  },

  DEAN_INTERVIEW_COMPLETED: {
    ACCEPTED: { permission: 'application.approve', label: 'Accept the applicant' },
    WAITLISTED: {
      permission: 'application.approve',
      requiresReason: true,
      label: 'Place the applicant on the waitlist',
    },
    REJECTED: {
      permission: 'application.approve',
      requiresReason: true,
      label: 'Reject the application',
    },
  },

  WAITLISTED: {
    ACCEPTED: { permission: 'application.approve', label: 'Accept the applicant' },
    REJECTED: {
      permission: 'application.approve',
      requiresReason: true,
      label: 'Reject the application',
    },
  },

  ACCEPTED: {
    ENROLLMENT_IN_PROGRESS: {
      permission: 'enrollment.review',
      label: 'Begin enrollment with the Registrar',
    },
    DEFERRED: {
      permission: 'application.manage',
      requiresReason: true,
      label: 'Defer admission to a later term',
    },
    WITHDRAWN: {
      permission: 'application.manage',
      requiresReason: true,
      label: 'Withdraw the application',
    },
  },

  DEFERRED: {
    ENROLLMENT_IN_PROGRESS: {
      permission: 'enrollment.review',
      label: 'Begin enrollment with the Registrar',
    },
    WITHDRAWN: {
      permission: 'application.manage',
      requiresReason: true,
      label: 'Withdraw the application',
    },
  },

  ENROLLMENT_IN_PROGRESS: {
    ENROLLED: {
      permission: 'enrollment.approve',
      label: 'Complete enrollment and issue the COR',
    },
    WITHDRAWN: {
      permission: 'application.manage',
      requiresReason: true,
      label: 'Withdraw the application',
    },
  },
};

export const applicationWorkflow: WorkflowDefinition<ApplicationStatus> = {
  name: 'application',
  initial: 'DRAFT',
  states: APPLICATION_STATUSES,
  terminal: ['ENROLLED', 'REJECTED', 'WITHDRAWN'],
  transitions,
};

/**
 * Presentation grouping for the applicant-facing progress tracker and the
 * admissions funnel. Several internal states collapse into one visible stage so
 * an applicant sees "Requirements" rather than the precise internal status.
 */
export const APPLICATION_STAGE_OF: Record<ApplicationStatus, string> = {
  DRAFT: 'Application',
  SUBMITTED: 'Application',
  UNDER_REVIEW: 'Application',
  SCREENING: 'Screening',
  SCREENING_PASSED: 'Screening',
  SCREENING_FAILED: 'Screening',
  EXAM_SCHEDULED: 'Examination',
  EXAM_COMPLETED: 'Examination',
  FOR_EVALUATION: 'Evaluation',
  EVALUATED: 'Evaluation',
  REQUIREMENTS_PENDING: 'Requirements',
  REQUIREMENTS_COMPLETE: 'Requirements',
  FOR_INTERVIEW: 'Interview',
  PANEL_INTERVIEW_SCHEDULED: 'Interview',
  PANEL_INTERVIEW_COMPLETED: 'Interview',
  DEAN_INTERVIEW_SCHEDULED: 'Interview',
  DEAN_INTERVIEW_COMPLETED: 'Interview',
  WAITLISTED: 'Decision',
  ACCEPTED: 'Decision',
  DEFERRED: 'Decision',
  ENROLLMENT_IN_PROGRESS: 'Enrollment',
  ENROLLED: 'Enrollment',
  REJECTED: 'Decision',
  WITHDRAWN: 'Decision',
};

/** Ordered funnel stages for the admissions dashboard (SPEC.md §14). */
export const ADMISSION_FUNNEL_STAGES = [
  'Lead',
  'Application',
  'Screening',
  'Examination',
  'Evaluation',
  'Requirements',
  'Interview',
  'Decision',
  'Enrollment',
] as const;
