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';
import { detectThemeCapabilities } from '../theme-capabilities.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 BARE_PAGE = `
export function FooListPage() {
  return (
    <div className="space-y-6"><h1>Foo</h1></div>
  );
}
`;

describe('theme-capabilities — project-aware detection', () => {
  let tmpDir: string;
  beforeEach(() => { tmpDir = mkdtempSync(path.join(tmpdir(), 'ui-polish-caps-')); });
  afterEach(() => { rmSync(tmpDir, { recursive: true, force: true }); });

  it('seeds platform helper classes from the tokens.json baseline (always present)', async () => {
    const tokens = await loadTokens(tokensFile);
    const caps = await detectThemeCapabilities(tmpDir, tokens);
    expect(caps.helperClasses.has('btn-primary')).toBe(true);
    expect(caps.helperClasses.has('badge-accent')).toBe(true);
    // No component on disk yet.
    expect(caps.hasComponent('PageTemplate')).toBe(false);
  });

  it('unions the project\'s own CSS — custom props + class selectors', async () => {
    writeFile(tmpDir, 'src/styles/theme.css',
      `:root { --accent-bg: #eef2ff; --accent-text: #4338ca; --accent-border: #c7d2fe; }\n.my-custom-chip { color: red; }`);
    const tokens = await loadTokens(tokensFile);
    const caps = await detectThemeCapabilities(tmpDir, tokens);
    expect(caps.tokens.has('--accent-bg')).toBe(true);
    expect(caps.tokens.has('--accent-text')).toBe(true);
    expect(caps.helperClasses.has('my-custom-chip')).toBe(true);
  });

  it('detects components present under src/components', async () => {
    writeFile(tmpDir, 'src/components/ui/PageTemplate.tsx', `export function PageTemplate() { return null; }`);
    const tokens = await loadTokens(tokensFile);
    const caps = await detectThemeCapabilities(tmpDir, tokens);
    expect(caps.hasComponent('PageTemplate')).toBe(true);
  });
});

describe('R1 anatomy — project-aware severity', () => {
  let tmpDir: string;
  beforeEach(() => { tmpDir = mkdtempSync(path.join(tmpdir(), 'ui-polish-r1-')); });
  afterEach(() => { rmSync(tmpDir, { recursive: true, force: true }); });

  it('downgrades to INFO (never blocks) when the project ships no PageTemplate component', async () => {
    writeFile(tmpDir, 'src/pages/test/FooListPage.tsx', BARE_PAGE);
    const tokens = await loadTokens(tokensFile);
    const report = await audit(
      { projectPath: tmpDir, mode: 'audit', rules: ['R1'], paths: [], urls: [], regenerateThreshold: 0 },
      tokens,
    );
    expect(report.findings).toHaveLength(1);
    expect(report.findings[0].ruleId).toBe('R1-pagetemplate');
    expect(report.findings[0].severity).toBe('info');
    expect(report.findings[0].autoFixable).toBe(false);
    expect(report.counts.errors).toBe(0);
  });

  it('stays an ERROR when the project DOES define PageTemplate but a page skips it', async () => {
    writeFile(tmpDir, 'src/components/ui/PageTemplate.tsx', `export function PageTemplate() { return null; }`);
    writeFile(tmpDir, 'src/pages/test/FooListPage.tsx', BARE_PAGE);
    const tokens = await loadTokens(tokensFile);
    const report = await audit(
      { projectPath: tmpDir, mode: 'audit', rules: ['R1'], paths: [], urls: [], regenerateThreshold: 0 },
      tokens,
    );
    // Only the page is audited (PageTemplate.tsx lives under src/components, not src/pages).
    expect(report.findings).toHaveLength(1);
    expect(report.findings[0].severity).toBe('error');
    expect(report.counts.errors).toBe(1);
  });

  it('apply — never injects a phantom PageTemplate import when the component is absent', async () => {
    const rel = 'src/pages/test/FooListPage.tsx';
    writeFile(tmpDir, rel, BARE_PAGE);
    const tokens = await loadTokens(tokensFile);
    await apply(
      { projectPath: tmpDir, mode: 'apply', rules: ['R1'], paths: [rel], urls: [], regenerateThreshold: 0 },
      tokens,
    );
    const out = readFileSync(path.join(tmpDir, rel), 'utf-8');
    expect(out).not.toContain('@/components/ui/PageTemplate'); // no phantom import → build stays green
    expect(out).not.toContain('<PageTemplate'); // page not wrapped
  });
});
