import { describe, expect, it } from 'vitest';
import { examStageFor, registrationForApplication } from './exam-stage';
import type { MyRegistration } from '../exams/pages/ExamsPage';

/* eslint-disable @typescript-eslint/no-explicit-any */

const registration = (over: Partial<MyRegistration> = {}): MyRegistration =>
  ({
    id: 'registration-1',
    admissionNumber: 'ADM-2026-000001',
    createdAt: '2026-08-01',
    kind: 'NEW',
    attemptNumber: 1,
    attendanceStatus: 'REGISTERED',
    applicationId: 'app-1',
    exam: { id: 'exam-1', date: '2026-09-10' } as any,
    attempt: null,
    ...over,
  }) as MyRegistration;

/**
 * The portal kept saying "Awaiting Exam Date" after the back office had
 * evaluated the paper, because it read only the application status —
 * registering, attendance and the sitting all happen on the registration.
 */
describe('examStageFor', () => {
  it('leaves non-exam applications to the ordinary status label', () => {
    expect(examStageFor({ status: 'UNDER_REVIEW' })).toBeNull();
    expect(examStageFor({ status: 'CERTIFICATE_ISSUED' })).toBeNull();
  });

  it('reads a paid application as eligible to register, not as waiting', () => {
    expect(examStageFor({ status: 'EXAM_PAID' })).toBe('ELIGIBLE_TO_REGISTER');
  });

  it('reports a registration whose attendance has not been taken', () => {
    expect(
      examStageFor({ status: 'EXAM_SCHEDULED' }, registration()),
    ).toBe('REGISTERED');
  });

  it.each(['PRESENT', 'LATE'] as const)(
    'reports attendance confirmed once an invigilator marks %s',
    (attendanceStatus) => {
      expect(
        examStageFor({ status: 'EXAM_SCHEDULED' }, registration({ attendanceStatus })),
      ).toBe('ATTENDANCE_CONFIRMED');
    },
  );

  it('does not treat a candidate who is not sitting as confirmed', () => {
    expect(
      examStageFor({ status: 'EXAM_SCHEDULED' }, registration({ attendanceStatus: 'ABSENT' })),
    ).toBe('REGISTERED');
  });

  it('follows the attempt once the candidate starts', () => {
    expect(
      examStageFor(
        { status: 'EXAM_SCHEDULED' },
        registration({ attendanceStatus: 'PRESENT', attempt: { status: 'IN_PROGRESS' } }),
      ),
    ).toBe('SITTING');
  });

  it.each(['SUBMITTED', 'EXPIRED'] as const)(
    'reports a %s attempt as awaiting evaluation',
    (status) => {
      expect(
        examStageFor(
          { status: 'EXAM_SCHEDULED' },
          registration({ attendanceStatus: 'PRESENT', attempt: { status } }),
        ),
      ).toBe('UNDER_EVALUATION');
    },
  );

  it('reports the published outcome, whatever the registration still says', () => {
    expect(examStageFor({ status: 'EXAM_PASSED' }, registration())).toBe('PASSED');
    expect(examStageFor({ status: 'EXAM_FAILED' }, registration())).toBe('FAILED');
  });

  it('falls back to registered when the registration has not loaded yet', () => {
    expect(examStageFor({ status: 'EXAM_SCHEDULED' })).toBe('REGISTERED');
  });
});

describe('registrationForApplication', () => {
  it('matches on the application the sitting answers', () => {
    const mine = [registration({ applicationId: 'app-2', id: 'r-2' }), registration()];

    expect(registrationForApplication('app-1', mine)?.id).toBe('registration-1');
    expect(registrationForApplication('app-3', mine)).toBeUndefined();
    expect(registrationForApplication('app-1', undefined)).toBeUndefined();
  });

  it('ignores registrations made outside the certificate course', () => {
    const mine = [registration({ applicationId: null })];

    expect(registrationForApplication('app-1', mine)).toBeUndefined();
  });
});
