/**
 * Unit tests for the mock data barrel export and mock API layer.
 *
 * Validates that:
 * - The barrel export produces datasets with the expected minimum sizes
 * - Mock API helper functions (filterByDateRange, groupBy, sumBy, topN) work correctly
 * - Each dashboard API function returns the expected shape
 */

import { describe, it, expect } from 'vitest';
import * as mockData from '@/lib/mock-data';
import {
  filterByDateRange,
  groupBy,
  groupByMonth,
  sumBy,
  topN,
  getOverviewData,
  getWorksData,
  getComposersData,
  getPayeesData,
  getContractsData,
  getIncomeData,
  getTransactionsData,
  getCostsData,
  getStatementsData,
  getSuspenseData,
  getAuditData,
} from '@/lib/api/mock-api';
import type { DateRange } from '@/lib/utils/date';

// ── Barrel export tests ─────────────────────────────────────────────────────

describe('Mock data barrel export', () => {
  it('generates the minimum required dataset sizes', () => {
    expect(mockData.works.length).toBeGreaterThanOrEqual(200);
    expect(mockData.composers.length).toBeGreaterThanOrEqual(50);
    expect(mockData.payees.length).toBeGreaterThanOrEqual(40);
    expect(mockData.contracts.length).toBeGreaterThanOrEqual(60);
    expect(mockData.income.length).toBeGreaterThanOrEqual(500);
    expect(mockData.transactions.length).toBeGreaterThanOrEqual(300);
    expect(mockData.costs.length).toBeGreaterThanOrEqual(100);
    expect(mockData.statements.length).toBeGreaterThanOrEqual(30);
    expect(mockData.suspenseItems.length).toBeGreaterThanOrEqual(40);
    expect(mockData.auditEvents.length).toBeGreaterThanOrEqual(100);
    expect(mockData.users.length).toBe(4);
  });

  it('produces deterministic data (same seed → same output)', () => {
    // The first work should always have the same title with seed 42
    expect(mockData.works[0].id).toBe('WRK-00001');
    expect(mockData.composers[0].id).toBe('CMP-0001');
  });
});

// ── Helper function tests ───────────────────────────────────────────────────

describe('filterByDateRange', () => {
  const items = [
    { id: '1', date: new Date('2024-06-15') },
    { id: '2', date: new Date('2024-01-01') },
    { id: '3', date: new Date('2025-12-31') },
    { id: '4', date: new Date('2024-03-10') },
  ];

  it('returns only items within the date range (inclusive)', () => {
    const range: DateRange = {
      start: new Date('2024-01-01'),
      end: new Date('2024-06-30'),
      label: 'Test',
    };
    const result = filterByDateRange(items, range, 'date');
    expect(result).toHaveLength(3);
    expect(result.map((r) => r.id)).toEqual(['1', '2', '4']);
  });

  it('returns empty array when no items match', () => {
    const range: DateRange = {
      start: new Date('2026-01-01'),
      end: new Date('2026-12-31'),
      label: 'Future',
    };
    const result = filterByDateRange(items, range, 'date');
    expect(result).toHaveLength(0);
  });
});

describe('groupBy', () => {
  it('groups and counts by a string field', () => {
    const items = [
      { type: 'a' },
      { type: 'b' },
      { type: 'a' },
      { type: 'c' },
      { type: 'a' },
    ];
    const result = groupBy(items, 'type');
    expect(result).toEqual([
      { name: 'a', value: 3 },
      { name: 'b', value: 1 },
      { name: 'c', value: 1 },
    ]);
  });
});

describe('sumBy', () => {
  it('sums a numeric field', () => {
    const items = [{ amount: 10.5 }, { amount: 20.3 }, { amount: 5.2 }];
    expect(sumBy(items, 'amount')).toBe(36);
  });
});

describe('topN', () => {
  it('returns the top N items by value descending', () => {
    const items = [
      { name: 'a', value: 10 },
      { name: 'b', value: 50 },
      { name: 'c', value: 30 },
      { name: 'd', value: 20 },
    ];
    const result = topN(items, 'value', 2);
    expect(result).toHaveLength(2);
    expect(result[0].name).toBe('b');
    expect(result[1].name).toBe('c');
  });
});

describe('groupByMonth', () => {
  it('groups items by month and sums values', () => {
    const items = [
      { date: new Date('2024-01-15'), amount: 100 },
      { date: new Date('2024-01-20'), amount: 200 },
      { date: new Date('2024-02-10'), amount: 50 },
    ];
    const result = groupByMonth(items, 'date', 'amount');
    expect(result).toEqual([
      { month: '2024-01', value: 300 },
      { month: '2024-02', value: 50 },
    ]);
  });
});

// ── Dashboard API function tests ────────────────────────────────────────────

const fullRange: DateRange = {
  start: new Date('2024-01-01'),
  end: new Date('2025-12-31'),
  label: 'Full Range',
};

describe('getOverviewData', () => {
  it('returns expected KPI and chart data shape', () => {
    const result = getOverviewData(fullRange);
    expect(result.kpis).toHaveProperty('totalWorks');
    expect(result.kpis).toHaveProperty('totalComposers');
    expect(result.kpis).toHaveProperty('totalIncome');
    expect(result.kpis).toHaveProperty('activeContracts');
    expect(result.kpis).toHaveProperty('pendingSuspense');
    expect(result.kpis).toHaveProperty('pendingStatements');
    expect(result.incomeOverTime.length).toBeGreaterThan(0);
    expect(result.incomeByTerritory.length).toBeGreaterThan(0);
    expect(result.topWorks.length).toBeLessThanOrEqual(10);
    expect(result.incomeByMediaType.length).toBeGreaterThan(0);
  });
});

describe('getWorksData', () => {
  it('returns expected shape', () => {
    const result = getWorksData(fullRange);
    expect(result.kpis.totalWorks).toBeGreaterThan(0);
    expect(result.byGenre.length).toBeGreaterThan(0);
    expect(result.byRightsType.length).toBe(2);
    expect(result.topByIncome.length).toBeLessThanOrEqual(10);
    expect(result.writerSplitDistribution.length).toBe(4);
  });
});

describe('getComposersData', () => {
  it('returns expected shape', () => {
    const result = getComposersData(fullRange);
    expect(result.kpis.totalComposers).toBeGreaterThan(0);
    expect(result.topByIncome.length).toBeLessThanOrEqual(10);
    expect(result.incomePerTop5OverTime.length).toBeLessThanOrEqual(5);
  });
});

describe('getPayeesData', () => {
  it('returns expected shape', () => {
    const result = getPayeesData(fullRange);
    expect(result.kpis.totalPayees).toBe(40);
    expect(result.topByEarnings.length).toBe(10);
    expect(result.byType.length).toBeGreaterThan(0);
  });
});

describe('getContractsData', () => {
  it('returns expected shape', () => {
    const result = getContractsData(fullRange);
    expect(result.kpis.totalContracts).toBeGreaterThanOrEqual(60);
    expect(result.kpis).toHaveProperty('activeContracts');
    expect(result.kpis).toHaveProperty('expiringIn90Days');
    expect(result.activeVsInactive).toHaveLength(2);
    expect(result.splitDistribution).toHaveLength(5);
  });
});

describe('getIncomeData', () => {
  it('returns expected shape', () => {
    const result = getIncomeData(fullRange);
    expect(result.kpis.grossIncome).toBeGreaterThan(0);
    expect(result.kpis.netIncome).toBeGreaterThan(0);
    expect(result.kpis.recordCount).toBeGreaterThanOrEqual(500);
    expect(result.grossVsNetByMonth.length).toBeGreaterThan(0);
    expect(result.topWorks.length).toBeLessThanOrEqual(10);
  });
});

describe('getTransactionsData', () => {
  it('returns expected shape', () => {
    const result = getTransactionsData(fullRange);
    expect(result.kpis.totalCount).toBeGreaterThanOrEqual(300);
    expect(result.byType.length).toBeGreaterThan(0);
  });
});

describe('getCostsData', () => {
  it('returns expected shape', () => {
    const result = getCostsData(fullRange);
    expect(result.kpis.totalCosts).toBeGreaterThan(0);
    expect(typeof result.kpis.costToIncomeRatio).toBe('number');
    expect(result.byType.length).toBeGreaterThan(0);
    expect(result.ratioOverTime.length).toBeGreaterThan(0);
  });
});

describe('getStatementsData', () => {
  it('returns expected shape', () => {
    const result = getStatementsData(fullRange);
    expect(result.kpis.totalStatements).toBeGreaterThanOrEqual(30);
    expect(result.byStatus).toHaveLength(3);
    expect(result.topPayees.length).toBeLessThanOrEqual(10);
  });
});

describe('getSuspenseData', () => {
  it('returns expected shape', () => {
    const result = getSuspenseData(fullRange);
    expect(result.kpis.totalItems).toBeGreaterThan(0);
    expect(result.kpis).toHaveProperty('unmatchedCount');
    expect(result.kpis).toHaveProperty('ambiguousCount');
    expect(typeof result.kpis.resolutionRate).toBe('number');
    expect(result.byMatchType).toHaveLength(2);
  });
});

describe('getAuditData', () => {
  it('returns expected shape', () => {
    const result = getAuditData(fullRange);
    expect(result.kpis.totalEvents).toBeGreaterThanOrEqual(100);
    expect(result.kpis.uniqueUsers).toBeGreaterThan(0);
    expect(result.byEntityType.length).toBeGreaterThan(0);
    expect(result.byActionType.length).toBeGreaterThan(0);
    expect(result.mostActiveUsers.length).toBeGreaterThan(0);
  });
});
