import { describe, expect, it } from 'bun:test';
import { renderToStaticMarkup } from 'react-dom/server';
import {
  EarningsPanel,
  buildEarningsCommand,
  buildEarningsRangeCommand,
  reconcileEarningsRange,
} from './EarningsPanel';
import type { EarningsPanelData } from '../../types/financial';

const makePeriod = (
  periodEnd: string,
  overrides: Partial<EarningsPanelData['periods'][number]> = {},
): EarningsPanelData['periods'][number] => ({
  label: periodEnd,
  displayLabel: "FY2024 Q1 (Mar)",
  periodEnd,
  filedDate: '2025-08-01',
  form: '10-Q',
  totalRevenues: 100,
  totalRevenuesYoyChangePercent: 5,
  costOfSales: 45,
  grossProfit: 55,
  grossProfitMargin: 55,
  sellingGeneralAndAdministrativeExpenses: 10,
  researchAndDevelopmentExpenses: 5,
  otherOperatingExpenses: undefined,
  operatingProfit: 40,
  operatingMargin: 40,
  nonOperatingIncome: 2,
  totalNonOperatingIncome: 2,
  incomeBeforeProvisionForIncomeTaxes: 42,
  provisionForIncomeTaxes: 8,
  consolidatedNetIncome: 34,
  netIncomeAttributableToCommonShareholders: 33,
  basicEps: 1.1,
  dilutedEps: 1,
  basicWeightedAverageSharesOutstanding: 98,
  totalSharesOutstanding: 101,
  dilutedWeightedAverageSharesOutstanding: 100,
  ebitda: 44,
  effectiveTaxRate: 19,
  revenue: 100,
  netIncome: 34,
  dilutedWeightedAverageShares: 100,
  revenueYoyChangePercent: 5,
  dilutedEpsYoyChangePercent: 4,
  ...overrides,
});

const samplePanel: EarningsPanelData = {
  symbol: 'AAPL',
  companyName: 'Apple Inc.',
  cik: '0000320193',
  frequency: 'annual',
  latestFiling: {
    accessionNumber: '0000320193-25-000010',
    filingDate: '2025-02-01',
    form: '10-K',
  },
  sourceStatus: {
    companyfactsUsed: true,
  },
  availableConcepts: [],
  mappingWarnings: [],
  availablePeriods: [
    {
      id: '2021',
      label: 'FY2021 (Sep)',
      frequency: 'annual',
      fiscalYear: '2021',
      fiscalPeriod: 'FY',
      periodEnd: '2021-09-25',
      sortKey: '2021',
    },
    {
      id: '2022',
      label: 'FY2022 (Sep)',
      frequency: 'annual',
      fiscalYear: '2022',
      fiscalPeriod: 'FY',
      periodEnd: '2022-09-24',
      sortKey: '2022',
    },
    {
      id: '2023',
      label: 'FY2023 (Sep)',
      frequency: 'annual',
      fiscalYear: '2023',
      fiscalPeriod: 'FY',
      periodEnd: '2023-09-30',
      sortKey: '2023',
    },
    {
      id: '2024',
      label: 'FY2024 (Sep)',
      frequency: 'annual',
      fiscalYear: '2024',
      fiscalPeriod: 'FY',
      periodEnd: '2024-09-28',
      sortKey: '2024',
    },
  ],
  selectedPeriodStart: '2021',
  selectedPeriodEnd: '2024',
  selectedCurrency: 'EUR',
  availableCurrencies: ['EUR', 'USD'],
  periods: [
    makePeriod('2024-09-28', {
      fiscalYear: '2024',
      fiscalPeriod: 'FY',
      displayLabel: 'FY2024 (Sep)',
    }),
    makePeriod('2023-09-30', {
      fiscalYear: '2023',
      fiscalPeriod: 'FY',
      displayLabel: 'FY2023 (Sep)',
    }),
    makePeriod('2022-09-24', {
      fiscalYear: '2022',
      fiscalPeriod: 'FY',
      displayLabel: 'FY2022 (Sep)',
    }),
    makePeriod('2021-09-25', {
      fiscalYear: '2021',
      fiscalPeriod: 'FY',
      displayLabel: 'FY2021 (Sep)',
    }),
  ],
};

describe('EarningsPanel', () => {
  it('renders the expanded income statement metric order', () => {
    const html = renderToStaticMarkup(<EarningsPanel data={samplePanel} />);

    expect(html).toContain('Total Revenues');
    expect(html).toContain('Total Revenues %Chg');
    expect(html).toContain('Cost of Sales');
    expect(html).toContain('Gross Profit Margin');
    expect(html).toContain('Operating Profit');
    expect(html).not.toContain('Total Non-Operating Income');
    expect(html).toContain('Effective Tax Rate');
    expect(html.indexOf('Total Revenues')).toBeLessThan(
      html.indexOf('Effective Tax Rate'),
    );
  });

  it('renders range selectors and backend-provided annual labels', () => {
    const html = renderToStaticMarkup(<EarningsPanel data={samplePanel} />);

    expect(html).toContain('Reported Range');
    expect(html).toContain('Start Period');
    expect(html).toContain('End Period');
    expect(html).toContain('FY2024 (Sep)');
    expect(html).not.toContain('2025</th><th');
  });

  it('renders missing values as em dashes without crashing', () => {
    const html = renderToStaticMarkup(
      <EarningsPanel
        data={{
          ...samplePanel,
          periods: [
            {
              ...samplePanel.periods[0],
              otherOperatingExpenses: undefined,
              nonOperatingIncome: undefined,
              ebitda: undefined,
            },
          ],
        }}
      />,
    );

    expect(html).toContain('Other Operating Expenses');
    expect(html).toContain('—');
  });

  it('only offers mapping on direct filing rows, not calculated rows', () => {
    const html = renderToStaticMarkup(
      <EarningsPanel
        data={{
          ...samplePanel,
          periods: [
            {
              ...samplePanel.periods[0],
              otherOperatingExpenses: 0,
              totalRevenues: undefined,
              totalRevenuesYoyChangePercent: undefined,
              grossProfitMargin: undefined,
              operatingMargin: undefined,
            },
          ],
        }}
      />,
    );

    expect((html.match(/>Map</g) || []).length).toBe(1);
  });

  it('builds canonical /em commands for selected ranges', () => {
    expect(buildEarningsRangeCommand('NVDA', 'quarterly', '2024Q1', '2025Q2')).toBe(
      '/em NVDA quarterly 2024Q1 2025Q2',
    );
  });

  it('builds canonical /em commands with range and currency', () => {
    expect(
      buildEarningsCommand('SAP', 'quarterly', {
        start: '2024Q1',
        end: '2025Q2',
        currency: 'eur',
      }),
    ).toBe('/em SAP quarterly 2024Q1 2025Q2 --currency EUR');
  });

  it('clamps invalid local ranges to an inclusive reported window', () => {
    expect(
      reconcileEarningsRange('2024', '2022', samplePanel.availablePeriods),
    ).toEqual({
      start: '2022',
      end: '2022',
    });
  });

  it('renders mapping warnings when present', () => {
    const html = renderToStaticMarkup(
      <EarningsPanel
        data={{
          ...samplePanel,
          mappingWarnings: [
            'Ebitda: Concept not found in XBRL document: us-gaap:Depreciation',
          ],
        }}
      />,
    );

    expect(html).toContain('Mapping &amp; Calculation Warnings');
    expect(html).toContain('us-gaap:Depreciation');
  });

  it('does not render mapping warnings section when warnings are empty', () => {
    const html = renderToStaticMarkup(<EarningsPanel data={samplePanel} />);

    expect(html).not.toContain('Mapping &amp; Calculation Warnings');
  });

  it('renders the currency selector when multiple currencies are available', () => {
    const html = renderToStaticMarkup(<EarningsPanel data={samplePanel} onRunCommand={() => {}} />);

    expect(html).toContain('Currency');
    expect(html).toContain('aria-label="Earnings currency"');
    expect(html).toContain('EUR');
    expect(html).toContain('USD');
  });

  it('renders a static currency label when only one currency is available', () => {
    const html = renderToStaticMarkup(
      <EarningsPanel
        data={{
          ...samplePanel,
          selectedCurrency: 'EUR',
          availableCurrencies: ['EUR'],
        }}
      />,
    );

    expect(html).toContain('Currency');
    expect(html).not.toContain('aria-label="Earnings currency"');
    expect(html).toContain('>EUR<');
  });
});
