/**
 * r19.test.ts — R19-hex-in-inline-style rule tests.
 *
 * R19 detects hex/rgb/rgba colors in inline style={{ }} props. These bypass
 * the design token system and do not respond to theme/dark mode changes.
 *
 * The test creates a tiny project tree under os.tmpdir and runs the audit
 * filtered to R19 only.
 */
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';
import type { TokensFile } from '../types.js';

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

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 tokensPath = path.resolve(__dirname, '../../../tokens.json');

let tokens: TokensFile;

beforeEach(async () => {
  tokens = await loadTokens(tokensPath);
});

describe('ui-polish / R19 — hex/rgb/rgba in inline style={{ }} props', () => {
  let root: string;

  beforeEach(() => {
    root = mkdtempSync(path.join(tmpdir(), 'audit-dev-r19-'));
  });

  afterEach(() => {
    rmSync(root, { recursive: true, force: true });
  });

  function baseArgs(projectPath: string) {
    return {
      projectPath,
      mode: 'audit' as const,
      rules: ['R19'],
      paths: [],
      urls: [],
      regenerateThreshold: 0,
    };
  }

  it('flags hex color in inline style backgroundColor property (BLOCKING)', async () => {
    const PAGE = `
import { FC } from 'react';

export const TestPage: FC = () => {
  return <div style={{ backgroundColor: '#6b7280' }}>Hello</div>;
};
`;
    writeFile(root, 'src/pages/test/TestPage.tsx', PAGE);
    const report = await audit(baseArgs(root), tokens);
    const errs = report.findings.filter((f) => f.ruleId === 'R19-hex-in-inline-style' && f.severity === 'warning');
    expect(errs.length).toBe(1);
    expect(errs[0].message).toContain('hardcoded color');
    expect(errs[0].snippet).toContain('#6b7280');
  });

  it('does NOT flag non-color style properties (width, height)', async () => {
    const PAGE = `
import { FC } from 'react';

export const TestPage: FC = () => {
  return <div style={{ width: '100px', height: '50px' }}>Hello</div>;
};
`;
    writeFile(root, 'src/pages/test/TestPage.tsx', PAGE);
    const report = await audit(baseArgs(root), tokens);
    const errs = report.findings.filter((f) => f.ruleId === 'R19-hex-in-inline-style');
    expect(errs.length).toBe(0);
  });

  it('flags rgb() color in inline style color property (BLOCKING)', async () => {
    const PAGE = `
import { FC } from 'react';

export const TestPage: FC = () => {
  return <span style={{ color: 'rgb(107, 114, 128)' }}>Text</span>;
};
`;
    writeFile(root, 'src/pages/test/TestPage.tsx', PAGE);
    const report = await audit(baseArgs(root), tokens);
    const errs = report.findings.filter((f) => f.ruleId === 'R19-hex-in-inline-style');
    expect(errs.length).toBe(1);
    expect(errs[0].message).toContain('hardcoded color');
    expect(errs[0].snippet).toContain('rgb');
  });

  it('flags rgba() color in inline style (BLOCKING)', async () => {
    const PAGE = `
import { FC } from 'react';

export const TestPage: FC = () => {
  return <button style={{ backgroundColor: 'rgba(107, 114, 128, 0.5)' }}>Click</button>;
};
`;
    writeFile(root, 'src/pages/test/TestPage.tsx', PAGE);
    const report = await audit(baseArgs(root), tokens);
    const errs = report.findings.filter((f) => f.ruleId === 'R19-hex-in-inline-style');
    expect(errs.length).toBe(1);
    expect(errs[0].snippet).toContain('rgba');
  });

  it('does NOT flag named color keywords (inherit, transparent)', async () => {
    const PAGE = `
import { FC } from 'react';

export const TestPage: FC = () => {
  return (
    <div style={{ color: 'inherit', backgroundColor: 'transparent' }}>
      OK
    </div>
  );
};
`;
    writeFile(root, 'src/pages/test/TestPage.tsx', PAGE);
    const report = await audit(baseArgs(root), tokens);
    const errs = report.findings.filter((f) => f.ruleId === 'R19-hex-in-inline-style');
    expect(errs.length).toBe(0);
  });

  it('flags hex color in borderColor property (BLOCKING)', async () => {
    const PAGE = `
import { FC } from 'react';

export const TestPage: FC = () => {
  return <div style={{ borderColor: '#e5e7eb' }}>Card</div>;
};
`;
    writeFile(root, 'src/pages/test/TestPage.tsx', PAGE);
    const report = await audit(baseArgs(root), tokens);
    const errs = report.findings.filter((f) => f.ruleId === 'R19-hex-in-inline-style');
    expect(errs.length).toBe(1);
  });

  it('flags hex in fill and stroke SVG properties (BLOCKING)', async () => {
    const PAGE = `
import { FC } from 'react';

export const TestPage: FC = () => {
  return (
    <svg>
      <circle style={{ fill: '#6b7280' }} />
    </svg>
  );
};
`;
    writeFile(root, 'src/pages/test/TestPage.tsx', PAGE);
    const report = await audit(baseArgs(root), tokens);
    const errs = report.findings.filter((f) => f.ruleId === 'R19-hex-in-inline-style');
    expect(errs.length).toBe(1);
  });

  it('flags multiple hex colors in one style block', async () => {
    const PAGE = `
import { FC } from 'react';

export const TestPage: FC = () => {
  return (
    <div style={{
      backgroundColor: '#6b7280',
      borderColor: '#e5e7eb',
      color: '#1f2937'
    }}>
      Multiple colors
    </div>
  );
};
`;
    writeFile(root, 'src/pages/test/TestPage.tsx', PAGE);
    const report = await audit(baseArgs(root), tokens);
    const errs = report.findings.filter((f) => f.ruleId === 'R19-hex-in-inline-style');
    // Only one finding per style block (first color match)
    expect(errs.length).toBeGreaterThan(0);
  });

  it('ignores style blocks without color properties', async () => {
    const PAGE = `
import { FC } from 'react';

export const TestPage: FC = () => {
  return (
    <div style={{
      padding: '1rem',
      margin: '2rem',
      display: 'flex'
    }}>
      No colors here
    </div>
  );
};
`;
    writeFile(root, 'src/pages/test/TestPage.tsx', PAGE);
    const report = await audit(baseArgs(root), tokens);
    const errs = report.findings.filter((f) => f.ruleId === 'R19-hex-in-inline-style');
    expect(errs.length).toBe(0);
  });

  it('flags hex in boxShadow property (BLOCKING)', async () => {
    const PAGE = `
import { FC } from 'react';

export const TestPage: FC = () => {
  return (
    <div style={{ boxShadow: '0 0 10px #6b7280' }}>
      Shadowed
    </div>
  );
};
`;
    writeFile(root, 'src/pages/test/TestPage.tsx', PAGE);
    const report = await audit(baseArgs(root), tokens);
    const errs = report.findings.filter((f) => f.ruleId === 'R19-hex-in-inline-style');
    expect(errs.length).toBe(1);
  });

  it('does NOT flag style blocks with only non-color properties mixed with color-named keywords', async () => {
    const PAGE = `
import { FC } from 'react';

export const TestPage: FC = () => {
  return (
    <div style={{
      width: '100px',
      color: 'currentColor',
      padding: '8px'
    }}>
      Safe
    </div>
  );
};
`;
    writeFile(root, 'src/pages/test/TestPage.tsx', PAGE);
    const report = await audit(baseArgs(root), tokens);
    const errs = report.findings.filter((f) => f.ruleId === 'R19-hex-in-inline-style');
    expect(errs.length).toBe(0);
  });

  it('returns empty findings when there are no pages on disk', async () => {
    // No pages written — empty project
    const report = await audit(baseArgs(root), tokens);
    const findings = report.findings.filter((f) => f.ruleId === 'R19-hex-in-inline-style');
    expect(findings.length).toBe(0);
  });

  it('flags 3-digit hex colors (#fff)', async () => {
    const PAGE = `
import { FC } from 'react';

export const TestPage: FC = () => {
  return <div style={{ backgroundColor: '#fff' }}>White</div>;
};
`;
    writeFile(root, 'src/pages/test/TestPage.tsx', PAGE);
    const report = await audit(baseArgs(root), tokens);
    const errs = report.findings.filter((f) => f.ruleId === 'R19-hex-in-inline-style');
    expect(errs.length).toBe(1);
    expect(errs[0].snippet).toContain('#fff');
  });

  it('flags 8-digit hex colors with alpha (#rrggbbaa)', async () => {
    const PAGE = `
import { FC } from 'react';

export const TestPage: FC = () => {
  return <div style={{ backgroundColor: '#6b728080' }}>Transparent</div>;
};
`;
    writeFile(root, 'src/pages/test/TestPage.tsx', PAGE);
    const report = await audit(baseArgs(root), tokens);
    const errs = report.findings.filter((f) => f.ruleId === 'R19-hex-in-inline-style');
    expect(errs.length).toBe(1);
  });

  it('reports correct line number for style block violation', async () => {
    const PAGE = `import { FC } from 'react';

export const TestPage: FC = () => {
  const heading = 'test';
  return (
    <div style={{ backgroundColor: '#6b7280' }}>
      {heading}
    </div>
  );
};
`;
    writeFile(root, 'src/pages/test/TestPage.tsx', PAGE);
    const report = await audit(baseArgs(root), tokens);
    const errs = report.findings.filter((f) => f.ruleId === 'R19-hex-in-inline-style');
    expect(errs.length).toBe(1);
    expect(errs[0].line).toBe(6); // Line where style={{ is
  });
});
