/**
 * RecoveryChart — VVP-02 [P1] + RECOVERYCHART-DATAPROP
 * Annotated clicks-recovery curve: baseline → core-update drop → fix applied → recovery.
 * TDD: these tests FAIL before RecoveryChart.tsx exists, PASS after.
 */
import { render, screen } from '@testing-library/react';
import { describe, expect, it, vi } from 'vitest';

// recharts uses ResizeObserver/getBoundingClientRect — both mocked in setup.ts
// We need to mock recharts to render in jsdom without SVG measurement.
vi.mock('recharts', async () => {
  const actual = await vi.importActual<typeof import('recharts')>('recharts');
  return {
    ...actual,
    // ResponsiveContainer passes a fixed size in jsdom so children render.
    ResponsiveContainer: ({ children }: { children: React.ReactElement }) => (
      <div data-testid="responsive-container" style={{ width: 300, height: 200 }}>
        {children}
      </div>
    ),
    // AreaChart: render children so ReferenceLine mocks can appear.
    AreaChart: ({ children }: { children: React.ReactNode }) => (
      <svg data-testid="area-chart">{children}</svg>
    ),
    // Strip purely decorative/layout recharts primitives.
    CartesianGrid: () => null,
    XAxis: () => null,
    YAxis: () => null,
    Tooltip: () => null,
    Area: () => <path data-testid="area-path" />,
    // ReferenceLine renders as an accessible div so label text is queryable.
    ReferenceLine: ({
      label,
    }: {
      label?: string | { value?: string; position?: string; offset?: number; style?: React.CSSProperties };
    }) => {
      const labelText =
        typeof label === 'string'
          ? label
          : typeof label === 'object' && label !== null && 'value' in label
            ? (label.value ?? '')
            : '';
      return <div data-testid="reference-line">{labelText}</div>;
    },
  };
});

// Mock theme hook — used by useChartColors
vi.mock('@/Components/theme', () => ({
  useTheme: () => ({ resolvedTheme: 'light' }),
}));

// Mock ScrollReveal to render children directly (no IntersectionObserver needed)
vi.mock('@/Components/marketing/operator/ScrollReveal', () => ({
  ScrollReveal: ({ children }: { children: React.ReactNode }) => (
    <div data-testid="scroll-reveal">{children}</div>
  ),
}));

// Import AFTER mocks are set up
import { RecoveryChart } from './RecoveryChart';
import type { ChartPoint } from './RecoveryChart';

describe('RecoveryChart (VVP-02)', () => {
  it('renders an SVG area/path element (the recovery curve)', () => {
    const { container } = render(<RecoveryChart />);
    // recharts renders an <svg> with <path> elements for Area fills/strokes
    const svgOrPath =
      container.querySelector('svg') ?? container.querySelector('path') ?? container.querySelector('[data-testid="responsive-container"]');
    expect(svgOrPath).toBeInTheDocument();
  });

  it('renders a ReferenceLine labelled "Core update" (the update marker)', () => {
    render(<RecoveryChart />);
    const labels = screen.getAllByTestId('reference-line').map((el) => el.textContent ?? '');
    expect(labels.some((t) => /core update/i.test(t))).toBe(true);
  });

  it('renders a ReferenceLine labelled "Fix applied"', () => {
    render(<RecoveryChart />);
    const labels = screen.getAllByTestId('reference-line').map((el) => el.textContent ?? '');
    expect(labels.some((t) => /fix applied/i.test(t))).toBe(true);
  });

  it('exposes an accessible aria-label describing the recovery curve', () => {
    render(<RecoveryChart />);
    // ChartContainer renders role="img" with aria-label
    const chart = screen.getByRole('img');
    expect(chart).toBeInTheDocument();
    expect(chart.getAttribute('aria-label')).toBeTruthy();
  });

  it('wraps the chart in a ScrollReveal for draw-on-scroll', () => {
    render(<RecoveryChart />);
    expect(screen.getByTestId('scroll-reveal')).toBeInTheDocument();
  });

  it('disables animation when prefers-reduced-motion is set', () => {
    // Override matchMedia to report reduced motion
    const original = window.matchMedia;
    Object.defineProperty(window, 'matchMedia', {
      writable: true,
      value: vi.fn((query: string) => ({
        matches: query === '(prefers-reduced-motion: reduce)',
        media: query,
        onchange: null,
        addListener: vi.fn(),
        removeListener: vi.fn(),
        addEventListener: vi.fn(),
        removeEventListener: vi.fn(),
        dispatchEvent: vi.fn(),
      })),
    });

    render(<RecoveryChart reducedMotion />);

    // The chart should still render (just without animation)
    expect(screen.getByTestId('scroll-reveal')).toBeInTheDocument();
    expect(screen.getByRole('img')).toBeInTheDocument();

    // Restore
    Object.defineProperty(window, 'matchMedia', { writable: true, value: original });
  });

  // ===== RECOVERYCHART-DATAPROP tests =====

  it('default (no props): renders the visible illustrative footer label', () => {
    render(<RecoveryChart />);
    expect(
      screen.getByText(/Illustrative — your report uses your own GSC data/i),
    ).toBeInTheDocument();
  });

  it('default (no props): renders the sr-only illustrative disclosure', () => {
    render(<RecoveryChart />);
    // sr-only text is still in the DOM, just visually hidden
    const srOnly = screen.getByText(/Illustrative example — not a real customer result/i);
    expect(srOnly).toBeInTheDocument();
  });

  it('with real data + annotations: does NOT render the illustrative labels', () => {
    const data: ChartPoint[] = [
      { week: 'W1', clicks: 100 },
      { week: 'W2', clicks: 120 },
      { week: 'W3', clicks: 90 },
      { week: 'W4', clicks: 80 },
      { week: 'W5', clicks: 140 },
    ];
    render(
      <RecoveryChart
        data={data}
        annotations={{ updateWeek: 'W3', fixWeek: 'W5' }}
      />,
    );
    expect(
      screen.queryByText(/Illustrative — your report uses your own GSC data/i),
    ).not.toBeInTheDocument();
    expect(
      screen.queryByText(/Illustrative example — not a real customer result/i),
    ).not.toBeInTheDocument();
  });

  it('with real data + annotations: renders the chart area (real data path)', () => {
    const data: ChartPoint[] = [
      { week: 'W1', clicks: 100 },
      { week: 'W2', clicks: 120 },
      { week: 'W3', clicks: 90 },
      { week: 'W4', clicks: 80 },
      { week: 'W5', clicks: 140 },
    ];
    render(
      <RecoveryChart
        data={data}
        annotations={{ updateWeek: 'W3', fixWeek: 'W5' }}
      />,
    );
    // Chart still renders — just without illustrative labels
    expect(screen.getByRole('img')).toBeInTheDocument();
  });

  it('with real data but NO annotations: throws an Error (annotation guard)', () => {
    const data: ChartPoint[] = [
      { week: 'W1', clicks: 100 },
      { week: 'W2', clicks: 200 },
    ];
    // Suppress console.error for this expected throw
    const consoleError = vi.spyOn(console, 'error').mockImplementation(() => {});
    expect(() => render(<RecoveryChart data={data} />)).toThrow(
      /RecoveryChart: supplying data requires both before\/after annotation markers/i,
    );
    consoleError.mockRestore();
  });

  it('illustrative={true} with data + annotations: renders the illustrative label (explicit override)', () => {
    // Caller explicitly forces illustrative labeling even with data supplied.
    // Annotations are required whenever data is passed — regardless of illustrative flag.
    const data: ChartPoint[] = [{ week: 'W1', clicks: 100 }];
    render(
      <RecoveryChart
        data={data}
        illustrative
        annotations={{ updateWeek: 'W1', fixWeek: 'W1' }}
      />,
    );
    expect(
      screen.getByText(/Illustrative — your report uses your own GSC data/i),
    ).toBeInTheDocument();
  });

  it('illustrative={true} with data but NO annotations: throws (annotations required with any data)', () => {
    const data: ChartPoint[] = [{ week: 'W1', clicks: 100 }];
    const consoleError = vi.spyOn(console, 'error').mockImplementation(() => {});
    expect(() =>
      render(<RecoveryChart data={data} illustrative />),
    ).toThrow(/RecoveryChart: supplying data requires both before\/after annotation markers/i);
    consoleError.mockRestore();
  });

  it('empty data array (data=[]): throws an Error (empty array cannot be a real report)', () => {
    const consoleError = vi.spyOn(console, 'error').mockImplementation(() => {});
    expect(() => render(<RecoveryChart data={[]} />)).toThrow();
    consoleError.mockRestore();
  });
});
