import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import { mkdtempSync, mkdirSync, writeFileSync, rmSync } from 'node:fs';
import { tmpdir } from 'node:os';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import { audit, loadTokens } from '../audit.js';

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const tokensFile = path.resolve(__dirname, '../../../tokens.json');

function writeFile(root: string, rel: string, content: string): void {
  const abs = path.join(root, rel);
  mkdirSync(path.dirname(abs), { recursive: true });
  writeFileSync(abs, content, 'utf-8');
}

// A local theme that makes the token set authoritative (sentinels: accent ramp + surface).
const LOCAL_THEME = `:root {
  --color-accent-500: #8b5cf6;
  --color-accent-600: #7c3aed;
  --bg-card: #ffffff;
  --bg-app: #fafafa;
  --text-primary: #18181b;
  --border-color: #e4e4e7;
  --radius-button: 8px;
}`;

describe('R24-dangling-token-ref', () => {
  let tmpDir: string;
  beforeEach(() => { tmpDir = mkdtempSync(path.join(tmpdir(), 'ui-polish-r24-')); });
  afterEach(() => { rmSync(tmpDir, { recursive: true, force: true }); });

  it('FIRES (warning) — references a token not defined in the project theme; ignores defined ones', async () => {
    writeFile(tmpDir, 'src/styles/theme.css', LOCAL_THEME);
    writeFile(tmpDir, 'src/pages/test/FooListPage.tsx', `
export function FooListPage() {
  return (
    <div className="bg-[var(--bg-card)] border border-[var(--border-primary)] text-[var(--text-primary)]">x</div>
  );
}
`);
    const tokens = await loadTokens(tokensFile);
    const report = await audit(
      { projectPath: tmpDir, mode: 'audit', rules: ['R24'], paths: [], urls: [], regenerateThreshold: 0 },
      tokens,
    );
    // Only --border-primary is undefined; --bg-card and --text-primary are in the theme.
    expect(report.findings).toHaveLength(1);
    expect(report.findings[0].ruleId).toBe('R24-dangling-token-ref');
    expect(report.findings[0].severity).toBe('warning');
    expect(report.findings[0].snippet).toContain('--border-primary');
  });

  it('SILENT — when the theme is NOT local-authoritative (no sentinels), it cannot verify and stays quiet', async () => {
    // No local theme CSS → tokensComplete is false → never flags (avoids false positives
    // when the theme is imported solely from the platform package).
    writeFile(tmpDir, 'src/pages/test/FooListPage.tsx', `
export function FooListPage() {
  return (<div className="border-[var(--totally-made-up-token)]">x</div>);
}
`);
    const tokens = await loadTokens(tokensFile);
    const report = await audit(
      { projectPath: tmpDir, mode: 'audit', rules: ['R24'], paths: [], urls: [], regenerateThreshold: 0 },
      tokens,
    );
    expect(report.findings).toHaveLength(0);
  });

  it('SILENT — package-owned token families (--sl-*, --tw-*) and fallback refs are not flagged', async () => {
    writeFile(tmpDir, 'src/styles/theme.css', LOCAL_THEME);
    writeFile(tmpDir, 'src/pages/test/FooListPage.tsx', `
export function FooListPage() {
  return (
    <div className="bg-[var(--sl-color-primary-500)] text-[var(--unknown,#fff)] ring-[var(--tw-ring-color)]">x</div>
  );
}
`);
    const tokens = await loadTokens(tokensFile);
    const report = await audit(
      { projectPath: tmpDir, mode: 'audit', rules: ['R24'], paths: [], urls: [], regenerateThreshold: 0 },
      tokens,
    );
    // --sl-* and --tw-* are allowlisted; --unknown has a fallback so it is not a hard dependency.
    expect(report.findings).toHaveLength(0);
  });
});
