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

/**
 * Payment lifecycle (SPEC.md §17).
 *
 * A posted payment is immutable. There is deliberately no transition that
 * deletes one: corrections move to VOIDED or REVERSED, both of which require
 * elevated permission and a mandatory reason, and both leave the original row
 * and its amount intact for reconciliation.
 */
export const PAYMENT_STATUSES = ['POSTED', 'VOIDED', 'REVERSED'] as const;

export type PaymentStatus = (typeof PAYMENT_STATUSES)[number];

const paymentTransitions: TransitionTable<PaymentStatus> = {
  POSTED: {
    // VOID is for a same-session correction of an unallocated payment.
    VOIDED: {
      permission: 'payment.void',
      requiresReason: true,
      label: 'Void the payment',
    },
    // REVERSAL posts a compensating record for anything already allocated.
    REVERSED: {
      permission: 'payment.void',
      requiresReason: true,
      label: 'Reverse the payment',
    },
  },
};

export const paymentWorkflow: WorkflowDefinition<PaymentStatus> = {
  name: 'payment',
  initial: 'POSTED',
  states: PAYMENT_STATUSES,
  terminal: ['VOIDED', 'REVERSED'],
  transitions: paymentTransitions,
};

/** Assessment lifecycle. An assessment is superseded, never edited in place. */
export const ASSESSMENT_STATUSES = ['DRAFT', 'FINALIZED', 'SUPERSEDED', 'CANCELLED'] as const;

export type AssessmentStatus = (typeof ASSESSMENT_STATUSES)[number];

const assessmentTransitions: TransitionTable<AssessmentStatus> = {
  DRAFT: {
    FINALIZED: { permission: 'assessment.manage', label: 'Finalize the assessment' },
    CANCELLED: {
      permission: 'assessment.manage',
      requiresReason: true,
      label: 'Cancel the assessment',
    },
  },
  FINALIZED: {
    // Adding or dropping subjects produces a new assessment that supersedes
    // this one; the original stays for the payment history that references it.
    SUPERSEDED: {
      permission: 'assessment.manage',
      requiresReason: true,
      label: 'Supersede the assessment with a revised one',
    },
    CANCELLED: {
      permission: 'assessment.manage',
      requiresReason: true,
      label: 'Cancel the assessment',
    },
  },
};

export const assessmentWorkflow: WorkflowDefinition<AssessmentStatus> = {
  name: 'assessment',
  initial: 'DRAFT',
  states: ASSESSMENT_STATUSES,
  terminal: ['SUPERSEDED', 'CANCELLED'],
  transitions: assessmentTransitions,
};

/**
 * Whether a payment still counts toward a balance. Voided and reversed
 * payments remain visible in history but contribute nothing.
 */
export function paymentCountsTowardBalance(status: PaymentStatus): boolean {
  return status === 'POSTED';
}
