import { describe, it, expect } from 'vitest';
import { generate } from '../generate.js';
import { ScaffoldDashboardPrimitivesInputSchema } from '../types.js';

function files() {
  return generate(ScaffoldDashboardPrimitivesInputSchema.parse({ projectPath: '/p', appCode: 'demo' }));
}
function content(path: string): string {
  const f = files().find((x) => x.path === path);
  if (!f) throw new Error(`missing generated file: ${path}`);
  return f.content;
}

// Saturated Tailwind color classes (and dark: prefix) must NEVER appear — colors
// come from tokens (var(--…)) only. `bg-[var(--bg-card)]` is fine (not a match).
const FORBIDDEN_PALETTE = /\b(bg|text|border|ring|fill|stroke|from|via|to)-(red|orange|amber|yellow|lime|green|emerald|teal|cyan|sky|blue|indigo|violet|purple|fuchsia|pink|rose|gray|slate|zinc|neutral|stone)-\d{2,3}\b/;
const DARK_PREFIX = /\bdark:/;

const TSX = [
  'src/components/dashboard/KpiCard.tsx',
  'src/components/dashboard/ChartCard.tsx',
  'src/components/dashboard/ListWidget.tsx',
  'src/components/dashboard/DashboardGrid.tsx',
  'src/components/dashboard/WidgetRenderer.tsx',
];

describe('scaffold-dashboard-primitives — emitted files', () => {
  it('emits the 7 primitives + 4 locale files with correct strategies', () => {
    const paths = files().map((f) => `${f.path} [${f.strategy}]`);
    expect(paths).toEqual([
      'src/components/dashboard/types.ts [overwrite]',
      'src/components/dashboard/useDatavizPalette.ts [overwrite]',
      'src/components/dashboard/KpiCard.tsx [overwrite]',
      'src/components/dashboard/ChartCard.tsx [overwrite]',
      'src/components/dashboard/ListWidget.tsx [overwrite]',
      'src/components/dashboard/DashboardGrid.tsx [overwrite]',
      'src/components/dashboard/WidgetRenderer.tsx [overwrite]',
      'src/i18n/locales/fr/common.json [deep-merge-json]',
      'src/i18n/locales/en/common.json [deep-merge-json]',
      'src/i18n/locales/it/common.json [deep-merge-json]',
      'src/i18n/locales/de/common.json [deep-merge-json]',
    ]);
  });

  it('every .tsx carries the AUTO-GENERATED @customised header', () => {
    for (const p of TSX) expect(content(p), p).toContain('@customised');
  });
});

describe('theme compliance — tokens only, no hardcoded palette', () => {
  it('no saturated Tailwind color class and no dark: prefix in any primitive', () => {
    for (const p of [...TSX, 'src/components/dashboard/types.ts', 'src/components/dashboard/useDatavizPalette.ts']) {
      expect(FORBIDDEN_PALETTE.test(content(p)), `palette in ${p}`).toBe(false);
      expect(DARK_PREFIX.test(content(p)), `dark: in ${p}`).toBe(false);
    }
  });

  it('KpiCard reads the --kpi-* tokens', () => {
    const c = content('src/components/dashboard/KpiCard.tsx');
    expect(c).toContain('var(--kpi-value)');
    expect(c).toContain('var(--kpi-label)');
    expect(c).toContain('var(--kpi-trend-up)');
    expect(c).toContain('var(--kpi-trend-down)');
  });

  it('ChartCard pulls categorical colors from the palette hook + reads --chart-* tokens', () => {
    const c = content('src/components/dashboard/ChartCard.tsx');
    expect(c).toContain("import { useDatavizPalette } from './useDatavizPalette'");
    expect(c).toContain('palette[i % palette.length]');
    expect(c).toContain('var(--chart-grid)');
    expect(c).toContain('var(--chart-axis)');
    expect(c).toContain('var(--chart-tooltip-bg)');
  });

  it('useDatavizPalette reads --dataviz-1..8 from the document root', () => {
    const c = content('src/components/dashboard/useDatavizPalette.ts');
    expect(c).toContain("getPropertyValue('--dataviz-' + i)");
    expect(c).toContain('getComputedStyle(document.documentElement)');
  });
});

describe('the shared contract', () => {
  it('types.ts defines DashboardWidget + WidgetResult + the 6 widget types', () => {
    const c = content('src/components/dashboard/types.ts');
    expect(c).toContain('interface DashboardWidget');
    expect(c).toContain('interface WidgetResult');
    for (const t of ['kpi', 'counter', 'chart-line', 'chart-bar', 'chart-pie', 'list']) {
      expect(c, t).toContain(`'${t}'`);
    }
  });

  it('WidgetRenderer maps all 6 types and degrades unknown to a placeholder', () => {
    const c = content('src/components/dashboard/WidgetRenderer.tsx');
    expect(c).toContain('<KpiCard');
    expect(c).toContain('<ChartCard');
    expect(c).toContain('<ListWidget');
    expect(c).toContain("case 'chart-pie'");
    expect(c).toContain('unknownWidget');
    // span comes from widget.col, clamped 1..12
    expect(c).toContain("'span ' + span + ' / span ' + span");
  });
});

describe('i18n', () => {
  it('each locale carries a parseable dashboard namespace', () => {
    for (const loc of ['fr', 'en', 'it', 'de']) {
      const json = JSON.parse(content(`src/i18n/locales/${loc}/common.json`));
      expect(json.dashboard, loc).toBeDefined();
      expect(typeof json.dashboard.noData, loc).toBe('string');
      expect(typeof json.dashboard.unknownWidget, loc).toBe('string');
    }
  });
});
