import {
  EntrySource,
  EntryType,
  Incidence,
  type TimeTrackingEntry,
} from 'src/types/timeTracking';

import { getIncidenceEntryPairId } from './utils';

const buildEntry = (
  overrides: Partial<TimeTrackingEntry> &
    Pick<TimeTrackingEntry, 'id' | 'time' | 'type'>,
): TimeTrackingEntry => ({
  comment: null,
  createdAt: '2026-05-21T08:00:00.000Z',
  createdBy: null,
  entryId: `${overrides.id}`,
  eventTime: null,
  facialRecognitionSkipped: null,
  instanceId: 1,
  isRemoteWork: false,
  kiosk: null,
  kioskId: null,
  latitude: null,
  location: null,
  locationIncidence: false,
  longitude: null,
  siteId: null,
  siteName: null,
  source: EntrySource.WEB,
  summaryId: 1,
  updatedAt: '2026-05-21T08:00:00.000Z',
  updatedBy: null,
  userId: 1,
  ...overrides,
});

describe('getIncidenceEntryPairId', () => {
  it('returns null when incidenceType is null', () => {
    const entries = [
      buildEntry({
        id: 1,
        time: '2026-05-21T09:00:00.000Z',
        type: EntryType.START,
      }),
    ];
    expect(getIncidenceEntryPairId(entries, null)).toBeNull();
  });

  it('returns null when entries are empty', () => {
    expect(getIncidenceEntryPairId([], Incidence.LATE)).toBeNull();
  });

  it('returns null for ABSENT', () => {
    const entries = [
      buildEntry({
        id: 1,
        time: '2026-05-21T09:00:00.000Z',
        type: EntryType.START,
      }),
      buildEntry({
        id: 2,
        time: '2026-05-21T17:00:00.000Z',
        type: EntryType.END,
      }),
    ];
    expect(getIncidenceEntryPairId(entries, Incidence.ABSENT)).toBeNull();
  });

  describe('LATE', () => {
    it('picks the earliest start when there are multiple pairs', () => {
      const entries = [
        buildEntry({
          id: 1,
          time: '2026-05-21T09:00:00.000Z',
          type: EntryType.START,
        }),
        buildEntry({
          id: 2,
          time: '2026-05-21T12:00:00.000Z',
          type: EntryType.END,
        }),
        buildEntry({
          id: 3,
          time: '2026-05-21T13:00:00.000Z',
          type: EntryType.START,
        }),
        buildEntry({
          id: 4,
          time: '2026-05-21T17:00:00.000Z',
          type: EntryType.END,
        }),
      ];
      // pairs (DESC by start): [3-4, 1-2]; earliest start pair is 1-2
      expect(getIncidenceEntryPairId(entries, Incidence.LATE)).toBe('1-2');
    });

    it('returns the only pair when there is just one start', () => {
      const entries = [
        buildEntry({
          id: 1,
          time: '2026-05-21T09:00:00.000Z',
          type: EntryType.START,
        }),
        buildEntry({
          id: 2,
          time: '2026-05-21T17:00:00.000Z',
          type: EntryType.END,
        }),
      ];
      expect(getIncidenceEntryPairId(entries, Incidence.LATE)).toBe('1-2');
    });

    it('ignores orphan ends and picks the earliest pair with a start', () => {
      const entries = [
        buildEntry({
          id: 1,
          time: '2026-05-21T09:00:00.000Z',
          type: EntryType.START,
        }),
        buildEntry({
          id: 2,
          time: '2026-05-21T17:00:00.000Z',
          type: EntryType.END,
        }),
        buildEntry({
          id: 3,
          time: '2026-05-21T20:00:00.000Z',
          type: EntryType.END,
        }),
      ];
      // orphan END id=3 sorts first; LATE filter ignores it
      expect(getIncidenceEntryPairId(entries, Incidence.LATE)).toBe('1-2');
    });
  });

  describe('AUTO_CLOSE', () => {
    it('picks the pair whose end was auto-closed', () => {
      const entries = [
        buildEntry({
          id: 1,
          time: '2026-05-21T09:00:00.000Z',
          type: EntryType.START,
        }),
        buildEntry({
          id: 2,
          time: '2026-05-21T17:00:00.000Z',
          type: EntryType.END,
          source: EntrySource.AUTO_CLOSE,
        }),
        buildEntry({
          id: 3,
          time: '2026-05-21T18:00:00.000Z',
          type: EntryType.START,
        }),
        buildEntry({
          id: 4,
          time: '2026-05-21T20:00:00.000Z',
          type: EntryType.END,
        }),
      ];
      expect(getIncidenceEntryPairId(entries, Incidence.AUTO_CLOSE)).toBe(
        '1-2',
      );
    });

    it('returns null when no end is auto-closed', () => {
      const entries = [
        buildEntry({
          id: 1,
          time: '2026-05-21T09:00:00.000Z',
          type: EntryType.START,
        }),
        buildEntry({
          id: 2,
          time: '2026-05-21T17:00:00.000Z',
          type: EntryType.END,
        }),
      ];
      expect(getIncidenceEntryPairId(entries, Incidence.AUTO_CLOSE)).toBeNull();
    });
  });

  describe('LOCATION_INCIDENCE', () => {
    it('picks the pair whose start carries the location incidence, not the most recent', () => {
      const entries = [
        buildEntry({
          id: 1,
          time: '2026-05-21T09:00:00.000Z',
          type: EntryType.START,
          locationIncidence: true,
        }),
        buildEntry({
          id: 2,
          time: '2026-05-21T12:00:00.000Z',
          type: EntryType.END,
        }),
        buildEntry({
          id: 3,
          time: '2026-05-21T13:00:00.000Z',
          type: EntryType.START,
        }),
        buildEntry({
          id: 4,
          time: '2026-05-21T17:00:00.000Z',
          type: EntryType.END,
        }),
      ];
      expect(
        getIncidenceEntryPairId(entries, Incidence.LOCATION_INCIDENCE),
      ).toBe('1-2');
    });

    it('picks the pair whose end carries the location incidence', () => {
      const entries = [
        buildEntry({
          id: 1,
          time: '2026-05-21T09:00:00.000Z',
          type: EntryType.START,
        }),
        buildEntry({
          id: 2,
          time: '2026-05-21T17:00:00.000Z',
          type: EntryType.END,
          locationIncidence: true,
        }),
      ];
      expect(
        getIncidenceEntryPairId(entries, Incidence.LOCATION_INCIDENCE),
      ).toBe('1-2');
    });

    it('returns null when no entry has a location incidence', () => {
      const entries = [
        buildEntry({
          id: 1,
          time: '2026-05-21T09:00:00.000Z',
          type: EntryType.START,
        }),
        buildEntry({
          id: 2,
          time: '2026-05-21T17:00:00.000Z',
          type: EntryType.END,
        }),
      ];
      expect(
        getIncidenceEntryPairId(entries, Incidence.LOCATION_INCIDENCE),
      ).toBeNull();
    });

    it('does not return an orphan-end pair when the orphan has no location incidence', () => {
      const entries = [
        buildEntry({
          id: 1,
          time: '2026-05-21T09:00:00.000Z',
          type: EntryType.START,
          locationIncidence: true,
        }),
        buildEntry({
          id: 2,
          time: '2026-05-21T17:00:00.000Z',
          type: EntryType.END,
        }),
        buildEntry({
          id: 3,
          time: '2026-05-21T20:00:00.000Z',
          type: EntryType.END,
        }),
      ];
      // orphan END id=3 sorts first in DESC; must not be selected
      expect(
        getIncidenceEntryPairId(entries, Incidence.LOCATION_INCIDENCE),
      ).toBe('1-2');
    });
  });
});
