import { TestBed } from '@angular/core/testing';
import { ChartCanvas } from './chart-canvas';

// `vi.mock`'s factory is hoisted above regular imports, so the shared mock class is
// loaded via a dynamic import inside `vi.hoisted` rather than a plain top-level import.
const { MockChart } = await vi.hoisted(async () => import('./testing/mock-chart'));

vi.mock('chart.js', () => ({ Chart: MockChart, registerables: [] }));

describe('ChartCanvas', () => {
  afterEach(() => {
    MockChart.instances.length = 0;
  });

  it('creates a Chart.js instance from the type/data/options inputs', () => {
    const fixture = TestBed.createComponent(ChartCanvas);
    fixture.componentRef.setInput('type', 'line');
    fixture.componentRef.setInput('data', { labels: ['Jan'], datasets: [{ data: [1] }] });
    fixture.componentRef.setInput('options', { responsive: true });
    fixture.detectChanges();

    expect(MockChart.instances).toHaveLength(1);
    const instance = MockChart.instances[0];
    expect(instance.config.type).toBe('line');
    expect(instance.config.data).toEqual({ labels: ['Jan'], datasets: [{ data: [1] }] });
    expect(instance.config.options).toEqual({ responsive: true });
  });

  it('updates the chart instance in place when the data input changes', () => {
    const fixture = TestBed.createComponent(ChartCanvas);
    fixture.componentRef.setInput('type', 'bar');
    fixture.componentRef.setInput('data', { labels: ['Jan'], datasets: [{ data: [1] }] });
    fixture.detectChanges();
    const instance = MockChart.instances[0];

    fixture.componentRef.setInput('data', { labels: ['Feb'], datasets: [{ data: [2] }] });
    fixture.detectChanges();

    expect(MockChart.instances).toHaveLength(1);
    expect(instance.data).toEqual({ labels: ['Feb'], datasets: [{ data: [2] }] });
    expect(instance.update).toHaveBeenCalled();
  });

  it('updates the chart instance when the options input changes', () => {
    const fixture = TestBed.createComponent(ChartCanvas);
    fixture.componentRef.setInput('type', 'bar');
    fixture.componentRef.setInput('data', { labels: ['Jan'], datasets: [{ data: [1] }] });
    fixture.componentRef.setInput('options', { responsive: true });
    fixture.detectChanges();
    const instance = MockChart.instances[0];

    fixture.componentRef.setInput('options', { responsive: false });
    fixture.detectChanges();

    expect(instance.options).toEqual({ responsive: false });
    expect(instance.update).toHaveBeenCalled();
  });

  it('recreates the chart instance when the chart type changes', () => {
    const fixture = TestBed.createComponent(ChartCanvas);
    fixture.componentRef.setInput('type', 'line');
    fixture.componentRef.setInput('data', { labels: ['Jan'], datasets: [{ data: [1] }] });
    fixture.detectChanges();
    const firstInstance = MockChart.instances[0];

    fixture.componentRef.setInput('type', 'bar');
    fixture.detectChanges();

    expect(firstInstance.destroy).toHaveBeenCalled();
    expect(MockChart.instances).toHaveLength(2);
    expect(MockChart.instances[1].config.type).toBe('bar');
  });

  it('destroys the chart instance when the component is destroyed', () => {
    const fixture = TestBed.createComponent(ChartCanvas);
    fixture.componentRef.setInput('type', 'line');
    fixture.componentRef.setInput('data', { labels: [], datasets: [] });
    fixture.detectChanges();
    const instance = MockChart.instances[0];

    fixture.destroy();

    expect(instance.destroy).toHaveBeenCalled();
  });
});
