import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import { mkdtempSync, mkdirSync, writeFileSync, rmSync, readFileSync } from 'node:fs';
import { tmpdir } from 'node:os';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import { audit, loadTokens } from '../audit.js';
import { apply } from '../apply.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');
}

const INLINE_CTA =
  'flex items-center gap-1.5 px-3 py-2 rounded-[var(--radius-button)] bg-[var(--color-accent-500)] text-white hover:bg-[var(--color-accent-600)] transition-colors';

describe('R21-cta-inline-bypass', () => {
  let tmpDir: string;
  beforeEach(() => { tmpDir = mkdtempSync(path.join(tmpdir(), 'ui-polish-r21-')); });
  afterEach(() => { rmSync(tmpDir, { recursive: true, force: true }); });

  it('FIRES (error) — inline accent-fill CTA on a <button> without the btn helper', async () => {
    writeFile(tmpDir, 'src/pages/test/FooListPage.tsx', `
export function FooListPage() {
  return (
    <button type="button" className="${INLINE_CTA}">Create</button>
  );
}
`);
    const tokens = await loadTokens(tokensFile);
    const report = await audit(
      { projectPath: tmpDir, mode: 'audit', rules: ['R21'], paths: [], urls: [], regenerateThreshold: 0 },
      tokens,
    );
    expect(report.findings).toHaveLength(1);
    expect(report.findings[0].ruleId).toBe('R21-cta-inline-bypass');
    expect(report.findings[0].severity).toBe('error');
  });

  it('SILENT — a button already on .btn .btn-primary', async () => {
    writeFile(tmpDir, 'src/pages/test/FooListPage.tsx', `
export function FooListPage() {
  return (<button type="button" className="btn btn-primary">Create</button>);
}
`);
    const tokens = await loadTokens(tokensFile);
    const report = await audit(
      { projectPath: tmpDir, mode: 'audit', rules: ['R21'], paths: [], urls: [], regenerateThreshold: 0 },
      tokens,
    );
    expect(report.findings).toHaveLength(0);
  });

  it('apply — rewrites the inline CTA to .btn .btn-primary, keeps genuine extras, drops the colour identity', async () => {
    const rel = 'src/pages/test/FooListPage.tsx';
    writeFile(tmpDir, rel, `
export function FooListPage() {
  return (
    <button type="button" className="${INLINE_CTA} w-full">Create</button>
  );
}
`);
    const tokens = await loadTokens(tokensFile);
    await apply(
      { projectPath: tmpDir, mode: 'apply', rules: ['R21'], paths: [rel], urls: [], regenerateThreshold: 0 },
      tokens,
    );
    const out = readFileSync(path.join(tmpDir, rel), 'utf-8');
    expect(out).toContain('btn btn-primary');
    expect(out).not.toContain('bg-[var(--color-accent-500)]');
    expect(out).not.toContain('text-white');
    expect(out).toContain('w-full'); // genuinely-extra utility preserved
    // Re-audit: the CTA is now conformant.
    const report = await audit(
      { projectPath: tmpDir, mode: 'audit', rules: ['R21'], paths: [rel], urls: [], regenerateThreshold: 0 },
      tokens,
    );
    expect(report.findings).toHaveLength(0);
  });
});

describe('R22-soft-accent-bypass', () => {
  let tmpDir: string;
  beforeEach(() => { tmpDir = mkdtempSync(path.join(tmpdir(), 'ui-polish-r22-')); });
  afterEach(() => { rmSync(tmpDir, { recursive: true, force: true }); });

  it('FIRES (warning) — ad-hoc accent opacity tint instead of the soft-accent primitive', async () => {
    writeFile(tmpDir, 'src/pages/test/FooListPage.tsx', `
export function FooListPage() {
  return (<div className="bg-[var(--color-accent-500)]/10 text-[var(--color-accent-700)] rounded">tab</div>);
}
`);
    const tokens = await loadTokens(tokensFile);
    const report = await audit(
      { projectPath: tmpDir, mode: 'audit', rules: ['R22'], paths: [], urls: [], regenerateThreshold: 0 },
      tokens,
    );
    expect(report.findings).toHaveLength(1);
    expect(report.findings[0].ruleId).toBe('R22-soft-accent-bypass');
    expect(report.findings[0].severity).toBe('warning');
    expect(report.findings[0].snippet).toContain('/10');
  });

  it('SILENT — a full accent token without an opacity modifier (handled by R20/R21, not R22)', async () => {
    writeFile(tmpDir, 'src/pages/test/FooListPage.tsx', `
export function FooListPage() {
  return (<span className="badge-accent">tag</span>);
}
`);
    const tokens = await loadTokens(tokensFile);
    const report = await audit(
      { projectPath: tmpDir, mode: 'audit', rules: ['R22'], paths: [], urls: [], regenerateThreshold: 0 },
      tokens,
    );
    expect(report.findings).toHaveLength(0);
  });
});
