import { TestBed } from '@angular/core/testing';
import { DonutChart } from './donut-chart';

interface OutcomeRow {
  readonly outcome: string;
  readonly count: number;
}

const SAMPLE: readonly OutcomeRow[] = [
  { outcome: 'success', count: 120 },
  { outcome: 'failure', count: 6 },
  { outcome: 'denied', count: 3 },
];

function render() {
  TestBed.configureTestingModule({ imports: [DonutChart] });
  const fixture = TestBed.createComponent<DonutChart<OutcomeRow>>(DonutChart);
  fixture.componentRef.setInput('data', SAMPLE);
  fixture.componentRef.setInput('categoryKey', 'outcome');
  fixture.componentRef.setInput('valueKey', 'count');
  fixture.componentRef.setInput('caption', 'Outcome breakdown');
  fixture.componentRef.setInput(
    'description',
    'Donut chart of audit-event outcomes for the current page (success, failure, denied).',
  );
  fixture.componentRef.setInput('ariaLabel', 'Outcome breakdown — donut chart');
  fixture.componentRef.setInput('centerLabel', '129');
  fixture.detectChanges();
  return fixture;
}

describe('DonutChart', () => {
  beforeEach(() => TestBed.resetTestingModule());

  it('wraps the chart in a <figure role="img"> with aria-labelledby + aria-describedby', () => {
    const fixture = render();
    const figure = (fixture.nativeElement as HTMLElement).querySelector('figure.chart-figure');
    expect(figure?.getAttribute('role')).toBe('img');
    expect(figure?.getAttribute('aria-labelledby')).toMatch(/^chart-\d+-title$/);
    expect(figure?.getAttribute('aria-describedby')).toMatch(/^chart-\d+-desc$/);
  });

  it('renders an SVG with <title> + <desc> as the first two children + one <path> per slice', () => {
    const fixture = render();
    const root = fixture.nativeElement as HTMLElement;
    const svg = root.querySelector<SVGSVGElement>('.chart-canvas svg');
    expect(svg).not.toBeNull();
    const children = Array.from(svg?.children ?? []);
    expect(children[0]?.tagName).toBe('title');
    expect(children[1]?.tagName).toBe('desc');
    const slices = children.filter((c) => c.tagName === 'path');
    expect(slices.length).toBe(SAMPLE.length);
  });

  it('each slice has its own <title> child carrying "<category>: <value>"', () => {
    const fixture = render();
    const root = fixture.nativeElement as HTMLElement;
    const slices = root.querySelectorAll<SVGPathElement>('.chart-canvas svg path');
    expect(slices.length).toBe(SAMPLE.length);
    expect(slices[0]?.querySelector('title')?.textContent).toBe('success: 120');
    expect(slices[1]?.querySelector('title')?.textContent).toBe('failure: 6');
  });

  it('renders the centerLabel in a <text> when supplied', () => {
    const fixture = render();
    const root = fixture.nativeElement as HTMLElement;
    expect(root.querySelector('.donut-center-label')?.textContent?.trim()).toBe('129');
  });

  it('renders a <details> tabular fallback with one row per category', () => {
    const fixture = render();
    const root = fixture.nativeElement as HTMLElement;
    const rows = root.querySelectorAll('details.chart-fallback tbody tr');
    expect(rows.length).toBe(SAMPLE.length);
    expect(rows[0]?.querySelector('th')?.textContent?.trim()).toBe('success');
    expect(rows[0]?.querySelector('td')?.textContent?.trim()).toBe('120');
  });

  it('honours an optional `colorMap` to colour slices by category', () => {
    TestBed.configureTestingModule({ imports: [DonutChart] });
    const fixture = TestBed.createComponent<DonutChart<OutcomeRow>>(DonutChart);
    fixture.componentRef.setInput('data', SAMPLE);
    fixture.componentRef.setInput('categoryKey', 'outcome');
    fixture.componentRef.setInput('valueKey', 'count');
    fixture.componentRef.setInput('caption', 'Outcome breakdown');
    fixture.componentRef.setInput('description', 'Donut chart of audit-event outcomes.');
    fixture.componentRef.setInput('ariaLabel', 'Outcome breakdown — donut chart');
    fixture.componentRef.setInput('colorMap', {
      success: '#16a34a',
      failure: '#dc2626',
      denied: '#ea580c',
    });
    fixture.detectChanges();

    const root = fixture.nativeElement as HTMLElement;
    const slices = root.querySelectorAll<SVGPathElement>('.chart-canvas svg path');
    // SAMPLE order: success, failure, denied — fills must match the
    // map exactly so admins read "green = success, orange = denied"
    // without consulting the legend.
    expect(slices[0]?.getAttribute('fill')).toBe('#16a34a');
    expect(slices[1]?.getAttribute('fill')).toBe('#dc2626');
    expect(slices[2]?.getAttribute('fill')).toBe('#ea580c');
  });
});
