import { beforeEach, describe, expect, test } from 'vitest';
import { createDataset } from '@core/dataset';
import { createSnippet } from '@core/snippet';
import { useAppStore } from '../stores/AppStore';
import { useChartBuilderStore } from '../stores/ChartBuilderStore';
import { useDatasetStore } from '../stores/DatasetStore';
import { useSnippetStore } from '../stores/SnippetStore';
import { applyView, deriveViewState } from './UrlStateSync';

const T = new Date('2026-06-01T00:00:00Z');

const seedDataset = (id: number, name: string) =>
  createDataset({ id, name, data: [{ a: 1 }], format: 'json', source: 'inline', now: T });

beforeEach(() => {
  useSnippetStore.getState().reset();
  useDatasetStore.getState().reset();
  useChartBuilderStore.setState({ datasetId: null });
  useAppStore.getState().setActiveModal(null);
  window.location.hash = '';
});

describe('deriveViewState — the URL is derived from store state', () => {
  test('no snippet, no modal → default snippets view', () => {
    useSnippetStore.getState().hydrate([], null);
    expect(deriveViewState()).toEqual({ kind: 'snippets' });
  });

  test('an active snippet → #snippet-<id>', () => {
    useSnippetStore.getState().hydrate([createSnippet({ id: 's1', now: T })], 's1');
    expect(deriveViewState()).toEqual({ kind: 'snippet', snippetId: 's1' });
  });

  test('Datasets manager (list) → #datasets', () => {
    useAppStore.getState().setActiveModal('datasets');
    expect(deriveViewState()).toEqual({ kind: 'datasets' });
  });

  test('a selected dataset → #datasets/dataset-<id>', () => {
    useDatasetStore.getState().hydrate([seedDataset(7, 'Sales')]);
    useDatasetStore.getState().select(7);
    useAppStore.getState().setActiveModal('datasets');
    expect(deriveViewState()).toEqual({ kind: 'dataset', datasetId: 7 });
  });

  test('the new-dataset form → #datasets/new', () => {
    useDatasetStore.getState().startCreate();
    useAppStore.getState().setActiveModal('datasets');
    expect(deriveViewState()).toEqual({ kind: 'dataset-new' });
  });

  test('the Chart Builder → #datasets/dataset-<id>/build', () => {
    useChartBuilderStore.setState({ datasetId: 42 });
    useAppStore.getState().setActiveModal('chartBuilder');
    expect(deriveViewState()).toEqual({ kind: 'dataset-build', datasetId: 42 });
  });

  test('a non-navigable modal (extract) leaves the underlying snippet view in the URL', () => {
    useSnippetStore.getState().hydrate([createSnippet({ id: 's1', now: T })], 's1');
    useAppStore.getState().setActiveModal('extract');
    expect(deriveViewState()).toEqual({ kind: 'snippet', snippetId: 's1' });
  });
});

describe('applyView — the hash drives the stores (restore / Back-Forward)', () => {
  test('restoring a snippet selects it and closes any modal', () => {
    useSnippetStore.getState().hydrate([createSnippet({ id: 's1', now: T })], null);
    useAppStore.getState().setActiveModal('datasets');

    applyView({ kind: 'snippet', snippetId: 's1' });

    expect(useAppStore.getState().activeModal).toBeNull();
    expect(useSnippetStore.getState().activeSnippetId).toBe('s1');
  });

  test('a dead snippet id falls back to the default view and cleans the URL', () => {
    useSnippetStore.getState().hydrate([], null);
    window.location.hash = '#snippet-gone';

    applyView({ kind: 'snippet', snippetId: 'gone' });

    expect(useSnippetStore.getState().activeSnippetId).toBeNull();
    expect(window.location.hash).toBe('');
  });

  test('restoring the Datasets list opens the manager on its list view', () => {
    applyView({ kind: 'datasets' });
    expect(useAppStore.getState().activeModal).toBe('datasets');
    expect(useDatasetStore.getState().view).toBe('list');
  });

  test('restoring a specific dataset selects it in the open manager', () => {
    useDatasetStore.getState().hydrate([seedDataset(7, 'Sales')]);

    applyView({ kind: 'dataset', datasetId: 7 });

    expect(useAppStore.getState().activeModal).toBe('datasets');
    expect(useDatasetStore.getState().selectedId).toBe(7);
    expect(useDatasetStore.getState().view).toBe('detail');
  });

  test('a dead dataset id degrades to the Datasets list and cleans the URL', () => {
    useDatasetStore.getState().hydrate([]);
    window.location.hash = '#datasets/dataset-99';

    applyView({ kind: 'dataset', datasetId: 99 });

    expect(useAppStore.getState().activeModal).toBe('datasets');
    expect(useDatasetStore.getState().selectedId).toBeNull();
    expect(window.location.hash).toBe('#datasets');
  });

  test('restoring the new-dataset form opens the manager on its create view', () => {
    applyView({ kind: 'dataset-new' });
    expect(useAppStore.getState().activeModal).toBe('datasets');
    expect(useDatasetStore.getState().view).toBe('new');
  });

  test('restoring the Chart Builder loads its dataset and opens the builder', () => {
    useDatasetStore.getState().hydrate([seedDataset(7, 'Sales')]);

    applyView({ kind: 'dataset-build', datasetId: 7 });

    expect(useAppStore.getState().activeModal).toBe('chartBuilder');
    expect(useChartBuilderStore.getState().datasetId).toBe(7);
  });
});

describe('round-trip: applyView then deriveViewState is identity', () => {
  test('every store-representable view survives the round trip', () => {
    useSnippetStore.getState().hydrate([createSnippet({ id: 's1', now: T })], null);
    useDatasetStore.getState().hydrate([seedDataset(7, 'Sales')]);

    const views = [
      { kind: 'snippets' as const },
      { kind: 'snippet' as const, snippetId: 's1' },
      { kind: 'datasets' as const },
      { kind: 'dataset' as const, datasetId: 7 },
      { kind: 'dataset-new' as const },
      { kind: 'dataset-build' as const, datasetId: 7 },
    ];

    for (const view of views) {
      applyView(view);
      expect(deriveViewState()).toEqual(view);
    }
  });
});
