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

/**
 * Admission requirement lifecycle (SPEC.md §11).
 *
 * A requirement never loses its history: each submission adds a new
 * `RequirementSubmission` version rather than replacing the previous file, and
 * every review captures reviewer, timestamp, comment and the version reviewed.
 * Rejection and resubmission requests both require a reason (SPEC.md §33.13).
 *
 * `WAIVED` exists for checklist items that are satisfied outside the system —
 * a physical brown envelope handed over the counter, or a document the
 * institution has decided not to require for a particular applicant.
 */
export const REQUIREMENT_STATUSES = [
  'NOT_SUBMITTED',
  'SUBMITTED',
  'UNDER_REVIEW',
  'ACCEPTED',
  'REJECTED',
  'NEEDS_RESUBMISSION',
  'WAIVED',
] as const;

export type RequirementStatus = (typeof REQUIREMENT_STATUSES)[number];

const transitions: TransitionTable<RequirementStatus> = {
  NOT_SUBMITTED: {
    // The applicant uploads their own document; no staff permission required.
    SUBMITTED: { label: 'Submit the requirement' },
    WAIVED: {
      permission: 'requirement.review',
      requiresReason: true,
      label: 'Waive the requirement',
    },
    // Physical checklist items are marked satisfied directly by staff.
    ACCEPTED: { permission: 'requirement.review', label: 'Mark the requirement as received' },
  },

  SUBMITTED: {
    UNDER_REVIEW: { permission: 'requirement.review', label: 'Begin reviewing the requirement' },
    ACCEPTED: { permission: 'requirement.review', label: 'Accept the requirement' },
    REJECTED: {
      permission: 'requirement.review',
      requiresReason: true,
      label: 'Reject the requirement',
    },
    NEEDS_RESUBMISSION: {
      permission: 'requirement.review',
      requiresReason: true,
      label: 'Request a resubmission',
    },
    WAIVED: {
      permission: 'requirement.review',
      requiresReason: true,
      label: 'Waive the requirement',
    },
  },

  UNDER_REVIEW: {
    ACCEPTED: { permission: 'requirement.review', label: 'Accept the requirement' },
    REJECTED: {
      permission: 'requirement.review',
      requiresReason: true,
      label: 'Reject the requirement',
    },
    NEEDS_RESUBMISSION: {
      permission: 'requirement.review',
      requiresReason: true,
      label: 'Request a resubmission',
    },
    WAIVED: {
      permission: 'requirement.review',
      requiresReason: true,
      label: 'Waive the requirement',
    },
  },

  NEEDS_RESUBMISSION: {
    // A new version is uploaded; the previous version is retained.
    SUBMITTED: { label: 'Submit a new version of the requirement' },
    WAIVED: {
      permission: 'requirement.review',
      requiresReason: true,
      label: 'Waive the requirement',
    },
  },

  REJECTED: {
    // Reviewers may reopen a rejection; the original decision stays in history.
    NEEDS_RESUBMISSION: {
      permission: 'requirement.review',
      requiresReason: true,
      label: 'Allow a resubmission',
    },
    WAIVED: {
      permission: 'requirement.review',
      requiresReason: true,
      label: 'Waive the requirement',
    },
  },

  ACCEPTED: {
    // Correcting a mistaken acceptance is possible but always reasoned.
    NEEDS_RESUBMISSION: {
      permission: 'requirement.review',
      requiresReason: true,
      label: 'Reopen the requirement for resubmission',
    },
  },
};

export const requirementWorkflow: WorkflowDefinition<RequirementStatus> = {
  name: 'requirement',
  initial: 'NOT_SUBMITTED',
  states: REQUIREMENT_STATUSES,
  // No state is truly terminal: an accepted requirement can be reopened with a
  // reason, and a waiver can be revisited, so corrections stay auditable rather
  // than forcing staff to delete and recreate the record.
  terminal: [],
  transitions,
};

/** Statuses that count as satisfied when checking whether a set is complete. */
export const SATISFIED_REQUIREMENT_STATUSES: readonly RequirementStatus[] = ['ACCEPTED', 'WAIVED'];

export interface RequirementCompletionInput {
  readonly status: RequirementStatus;
  readonly isMandatory: boolean;
}

export interface RequirementCompletion {
  readonly isComplete: boolean;
  readonly satisfied: number;
  readonly mandatoryTotal: number;
  readonly outstanding: number;
}

/**
 * Whether every mandatory requirement is satisfied. Optional requirements are
 * counted for display but never block progression — which requirements are
 * mandatory is configuration (`AdmissionRequirementDefinition.isMandatory`),
 * not a code constant.
 */
export function evaluateRequirementCompletion(
  requirements: readonly RequirementCompletionInput[],
): RequirementCompletion {
  const mandatory = requirements.filter((requirement) => requirement.isMandatory);
  const satisfied = mandatory.filter((requirement) =>
    SATISFIED_REQUIREMENT_STATUSES.includes(requirement.status),
  ).length;

  return {
    isComplete: mandatory.length > 0 && satisfied === mandatory.length,
    satisfied,
    mandatoryTotal: mandatory.length,
    outstanding: mandatory.length - satisfied,
  };
}
