/**
 * shared-scan.test.ts — Test that when --page is specified, the audit scans
 * 1st-level local imports (@/components/**, @/features/**) so violations in
 * shared components are visible.
 */

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);

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');
}

describe('ui-polish — shared component scanning', () => {
  let tmpDir: string;

  beforeEach(() => {
    tmpDir = mkdtempSync(path.join(tmpdir(), 'ui-polish-test-'));
  });

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

  it('violations in imported shared component are visible when scanning a page', async () => {
    const tokensPath = path.resolve(__dirname, '../../../tokens.json');
    const tokens = await loadTokens(tokensPath);

    // Setup: Create a page that imports a shared component
    writeFile(
      tmpDir,
      'src/pages/crm/contacts/ContactListPage.tsx',
      `import { PageTemplate } from '@/components/ui/PageTemplate';
import { ContactCard } from '@/components/crm/ContactCard';

export function ContactListPage() {
  return (
    <PageTemplate title="Contacts">
      <ContactCard />
    </PageTemplate>
  );
}
`,
    );

    // Setup: Create a shared component with a hardcoded color (R14 violation)
    writeFile(
      tmpDir,
      'src/components/crm/ContactCard.tsx',
      `export function ContactCard() {
  return (
    <div className="bg-blue-100 border border-blue-300 rounded-lg p-4">
      <span className="text-blue-700">Contact name</span>
    </div>
  );
}
`,
    );

    // Run audit with --page pointing to the ContactListPage
    const report = await audit(
      {
        projectPath: tmpDir,
        mode: 'audit' as const,
        rules: ['R14'],
        paths: ['src/pages/crm/contacts/ContactListPage.tsx'],
        urls: [],
        regenerateThreshold: 0,
      },
      tokens,
    );

    // Assert: findings from ContactCard (the shared component) are visible
    const contactCardFindings = report.findings.filter((f) =>
      f.file.includes('ContactCard.tsx'),
    );
    expect(contactCardFindings.length).toBeGreaterThan(0);
    expect(contactCardFindings[0].ruleId).toBe('R14-no-hardcoded-colors');

    // Assert: filesInspected includes both the page and the shared component
    expect(report.filesInspected).toBeGreaterThanOrEqual(2);

    // Assert: the violations are for the hardcoded blue colors
    expect(contactCardFindings.some((f) => f.snippet?.includes('bg-blue'))).toBe(true);
    expect(contactCardFindings.some((f) => f.snippet?.includes('text-blue'))).toBe(true);
  });

  it('without --page, shared components under src/components are NOT discovered', async () => {
    const tokensPath = path.resolve(__dirname, '../../../tokens.json');
    const tokens = await loadTokens(tokensPath);

    // Setup: Create a shared component with a hardcoded color (R14 violation)
    writeFile(
      tmpDir,
      'src/components/crm/ContactCard.tsx',
      `export function ContactCard() {
  return (
    <div className="bg-red-100 border border-red-300 rounded-lg p-4">
      <span className="text-red-700">Contact name</span>
    </div>
  );
}
`,
    );

    // Run audit WITHOUT --page (full discovery of pages)
    // Since we haven't created any actual pages under src/pages/, files will be empty
    const report = await audit(
      {
        projectPath: tmpDir,
        mode: 'audit' as const,
        rules: ['R14'],
        paths: [],
        urls: [],
        regenerateThreshold: 0,
      },
      tokens,
    );

    // Assert: no findings because the component under src/components/ is not discovered
    // (discovery only looks for files under src/pages/ and src/features/**/pages/)
    const contactCardFindings = report.findings.filter((f) =>
      f.file.includes('ContactCard.tsx'),
    );
    expect(contactCardFindings.length).toBe(0);
  });

  it('with --page, shared components are discovered and violations are reported', async () => {
    const tokensPath = path.resolve(__dirname, '../../../tokens.json');
    const tokens = await loadTokens(tokensPath);

    // Setup: Create a page and multiple shared components with violations
    writeFile(
      tmpDir,
      'src/pages/dashboard/DashboardPage.tsx',
      `import { PageTemplate } from '@/components/ui/PageTemplate';
import { StatCard } from '@/components/shared/StatCard';
import { MetricWidget } from '@/features/analytics/MetricWidget';

export function DashboardPage() {
  return (
    <PageTemplate title="Dashboard">
      <StatCard />
      <MetricWidget />
    </PageTemplate>
  );
}
`,
    );

    // Shared component 1: StatCard with hardcoded yellow
    writeFile(
      tmpDir,
      'src/components/shared/StatCard.tsx',
      `export function StatCard() {
  return (
    <div className="bg-yellow-100 p-4">
      <span className="text-yellow-600">Stat</span>
    </div>
  );
}
`,
    );

    // Shared component 2: MetricWidget with hardcoded green
    writeFile(
      tmpDir,
      'src/features/analytics/MetricWidget.tsx',
      `export function MetricWidget() {
  return (
    <div className="border-2 border-green-500">
      <span className="text-green-800">Metric</span>
    </div>
  );
}
`,
    );

    // Run audit with --page
    const report = await audit(
      {
        projectPath: tmpDir,
        mode: 'audit' as const,
        rules: ['R14'],
        paths: ['src/pages/dashboard/DashboardPage.tsx'],
        urls: [],
        regenerateThreshold: 0,
      },
      tokens,
    );

    // Assert: findings from both shared components are present
    const statCardFindings = report.findings.filter((f) =>
      f.file.includes('StatCard.tsx'),
    );
    const metricWidgetFindings = report.findings.filter((f) =>
      f.file.includes('MetricWidget.tsx'),
    );

    expect(statCardFindings.length).toBeGreaterThan(0);
    expect(metricWidgetFindings.length).toBeGreaterThan(0);

    // Assert: filesInspected is at least 3 (page + 2 shared components)
    expect(report.filesInspected).toBeGreaterThanOrEqual(3);
  });

  it('non-matching import paths are safely skipped', async () => {
    const tokensPath = path.resolve(__dirname, '../../../tokens.json');
    const tokens = await loadTokens(tokensPath);

    // Setup: Create a page that imports from external libraries
    writeFile(
      tmpDir,
      'src/pages/home/HomePage.tsx',
      `import { PageTemplate } from '@/components/ui/PageTemplate';
import React from 'react';
import { useState } from 'react';

export function HomePage() {
  return (
    <PageTemplate title="Home">
      <div className="bg-red-500">Home page</div>
    </PageTemplate>
  );
}
`,
    );

    // Run audit with --page
    // The imports from 'react' and 'react' should be safely skipped by resolveLocalImports
    // Only @/components and @/features are followed
    const report = await audit(
      {
        projectPath: tmpDir,
        mode: 'audit' as const,
        rules: ['R14'],
        paths: ['src/pages/home/HomePage.tsx'],
        urls: [],
        regenerateThreshold: 0,
      },
      tokens,
    );

    // Assert: the HomePage has a hardcoded red violation
    const homePageFindings = report.findings.filter((f) =>
      f.file.includes('HomePage.tsx'),
    );
    expect(homePageFindings.length).toBeGreaterThan(0);

    // Assert: no crash, no error
    expect(report.projectPath).toBe(tmpDir);
  });
});
