// Feature: divisi-metrics, Property 4: Date range filtering returns only in-range data
// **Validates: Requirements 15.4**

import { describe, it, expect } from 'vitest';
import * as fc from 'fast-check';
import {
  income,
  transactions,
  costs,
  suspenseItems,
  auditEvents,
  works,
  composers,
  contracts,
} from '@/lib/mock-data';
import { filterByDateRange } from '@/lib/api/mock-api';
import type { DateRange } from '@/lib/utils/date';

/**
 * 24-month data window boundaries (Jan 1 2024 – Dec 31 2025).
 * All generated mock data dates fall within this window.
 */
const WINDOW_START = new Date('2024-01-01T00:00:00.000Z').getTime();
const WINDOW_END = new Date('2025-12-31T23:59:59.999Z').getTime();

/**
 * Arbitrary that generates a valid DateRange within the 24-month window.
 * Generates a start timestamp, then an end timestamp >= start.
 */
const dateRangeArb = fc
  .tuple(
    fc.integer({ min: WINDOW_START, max: WINDOW_END }),
    fc.integer({ min: 0, max: WINDOW_END - WINDOW_START }),
  )
  .map(([startTs, offset]) => {
    const start = new Date(startTs);
    const endTs = Math.min(startTs + offset, WINDOW_END);
    const end = new Date(endTs);
    return {
      start,
      end,
      label: 'random-range',
    } satisfies DateRange;
  });

/**
 * Each entry maps a collection to its date field key so we can
 * generically verify that filterByDateRange returns only in-range records.
 */
const dateCollections = [
  { label: 'income', collection: income, dateField: 'date' as const },
  { label: 'transactions', collection: transactions, dateField: 'date' as const },
  { label: 'costs', collection: costs, dateField: 'date' as const },
  { label: 'suspenseItems', collection: suspenseItems, dateField: 'date' as const },
  { label: 'auditEvents', collection: auditEvents, dateField: 'timestamp' as const },
  { label: 'works', collection: works, dateField: 'createdAt' as const },
  { label: 'composers', collection: composers, dateField: 'createdAt' as const },
  { label: 'contracts', collection: contracts, dateField: 'startDate' as const },
] as const;

describe('Property 4: Date range filtering returns only in-range data', () => {
  it('all records returned by filterByDateRange have their date field within [start, end]', () => {
    fc.assert(
      fc.property(
        dateRangeArb,
        fc.integer({ min: 0, max: dateCollections.length - 1 }),
        (range, collectionIndex) => {
          const { collection, dateField } = dateCollections[collectionIndex];

          // eslint-disable-next-line @typescript-eslint/no-explicit-any
          const filtered = filterByDateRange(collection as any[], range, dateField as any);

          for (const record of filtered) {
            // eslint-disable-next-line @typescript-eslint/no-explicit-any
            const dateValue = (record as any)[dateField] as Date;
            expect(dateValue).toBeInstanceOf(Date);
            expect(dateValue.getTime()).toBeGreaterThanOrEqual(range.start.getTime());
            expect(dateValue.getTime()).toBeLessThanOrEqual(range.end.getTime());
          }
        },
      ),
      { numRuns: 100 },
    );
  });

  it('no record outside the date range appears in the filtered results', () => {
    fc.assert(
      fc.property(
        dateRangeArb,
        fc.integer({ min: 0, max: dateCollections.length - 1 }),
        (range, collectionIndex) => {
          const { collection, dateField } = dateCollections[collectionIndex];

          // eslint-disable-next-line @typescript-eslint/no-explicit-any
          const filtered = filterByDateRange(collection as any[], range, dateField as any);
          // eslint-disable-next-line @typescript-eslint/no-explicit-any
          const filteredIds = new Set(filtered.map((r: any) => r.id));

          // Every item NOT in the filtered set that has a valid Date field
          // must have its date outside the range
          for (const record of collection) {
            // eslint-disable-next-line @typescript-eslint/no-explicit-any
            const id = (record as any).id as string;
            // eslint-disable-next-line @typescript-eslint/no-explicit-any
            const dateValue = (record as any)[dateField];
            if (dateValue instanceof Date && !filteredIds.has(id)) {
              const ts = dateValue.getTime();
              expect(ts < range.start.getTime() || ts > range.end.getTime()).toBe(true);
            }
          }
        },
      ),
      { numRuns: 100 },
    );
  });
});
