// SPEC-597-EXEMPT: canonical mapping (npm-package↔framework, keyword catalogue)
// — must enumerate framework names by design; no detection logic to migrate.
// tools/generate-tests/generators/visual-regression-generator.ts — SPEC-058a Section C
// Generates visual regression and frontend screenshot test scaffolds.
const UI_FRAMEWORKS = [
    'react',
    'vue',
    'angular',
    'svelte',
    'next',
    'nextjs',
    'next.js',
    'nuxt',
    'sveltekit',
    'svelte-kit',
    'solid',
    'solidjs',
    'preact',
    'qwik',
    'remix',
    'gatsby',
    'astro',
];
const DARK_MODE_SIGNALS = [
    'tailwind',
    'shadcn',
    'radix',
    'mui',
    'chakra',
    'mantine',
    'daisy',
    'daisyui',
    'styled-components',
    'emotion',
];
const BP_MOBILE = { label: 'mobile', width: 375, height: 812 };
const BP_TABLET = { label: 'tablet', width: 768, height: 1024 };
const BP_DESKTOP = { label: 'desktop', width: 1280, height: 800 };
/**
 * Returns true when the project has at least one frontend/fullstack app with a UI framework.
 */
export function isVisualRegressionProject(knowledge) {
    const frontendApps = knowledge.apps.filter((app) => app.type === 'frontend');
    for (const app of frontendApps) {
        const fw = (app.framework ?? '').toLowerCase();
        if (UI_FRAMEWORKS.some((uif) => fw.includes(uif))) {
            return true;
        }
    }
    // Fall back to top-level framework when no frontend apps matched
    if (frontendApps.length === 0) {
        const topFw = (knowledge.framework ?? '').toLowerCase();
        return UI_FRAMEWORKS.some((uif) => topFw.includes(uif));
    }
    return false;
}
function hasDarkModeSupport(knowledge) {
    const stackLower = knowledge.stack.map((s) => s.toLowerCase());
    return DARK_MODE_SIGNALS.some((sig) => stackLower.some((s) => s.includes(sig)));
}
/**
 * Generate visual regression test definitions.
 */
export function generateVisualRegressionTestDefs(title, testDir, _testExt) {
    const defs = [
        {
            name: `${title} — Visual: screenshot baseline matches approved snapshot`,
            type: 'e2e',
            file: `${testDir}/visual/`,
            description: 'Capture full-page screenshot and compare against approved baseline snapshot — fails on unexpected visual changes',
            priority: 'critical',
            automatable: true,
        },
        {
            name: `${title} — Visual: responsive layout at 375px, 768px, 1280px`,
            type: 'e2e',
            file: `${testDir}/visual/`,
            description: 'Verify layout integrity across mobile (375px), tablet (768px), and desktop (1280px) breakpoints',
            priority: 'high',
            automatable: true,
        },
        {
            name: `${title} — Visual: component renders without layout shift`,
            type: 'unit',
            file: `${testDir}/visual/`,
            description: 'Component snapshot test — verify no unintended style or markup changes in isolated render',
            priority: 'medium',
            automatable: true,
        },
    ];
    // Dark mode def added unconditionally — caller controls knowledge, but we always include it
    // since isVisualRegressionProject already filtered for UI projects that commonly support dark mode
    defs.push({
        name: `${title} — Visual: dark mode toggle does not break layout`,
        type: 'e2e',
        file: `${testDir}/visual/`,
        description: 'Toggle dark/light mode and verify screenshot matches approved dark-mode snapshot without overflow or invisible text',
        priority: 'medium',
        automatable: true,
    });
    return defs;
}
// === Language-specific content generators ===
function generatePlaywrightTest(title, slug) {
    return `// Visual regression tests for ${title}
// Requires: @playwright/test with --update-snapshots for initial baseline
import { test, expect } from '@playwright/test';

const BASE_URL = process.env.BASE_URL ?? 'http://localhost:3000';

test.describe('${title} — Visual Regression', () => {
  test('full-page screenshot matches baseline', async ({ page }) => {
    await page.goto(BASE_URL);
    await page.waitForLoadState('networkidle');
    await expect(page).toHaveScreenshot('${slug}-baseline.png', {
      fullPage: true,
      maxDiffPixelRatio: 0.02,
    });
  });

  test('responsive — mobile 375px', async ({ page }) => {
    await page.setViewportSize({ width: ${BP_MOBILE.width}, height: ${BP_MOBILE.height} });
    await page.goto(BASE_URL);
    await page.waitForLoadState('networkidle');
    await expect(page).toHaveScreenshot('${slug}-mobile.png', {
      maxDiffPixelRatio: 0.02,
    });
  });

  test('responsive — tablet 768px', async ({ page }) => {
    await page.setViewportSize({ width: ${BP_TABLET.width}, height: ${BP_TABLET.height} });
    await page.goto(BASE_URL);
    await page.waitForLoadState('networkidle');
    await expect(page).toHaveScreenshot('${slug}-tablet.png', {
      maxDiffPixelRatio: 0.02,
    });
  });

  test('responsive — desktop 1280px', async ({ page }) => {
    await page.setViewportSize({ width: ${BP_DESKTOP.width}, height: ${BP_DESKTOP.height} });
    await page.goto(BASE_URL);
    await page.waitForLoadState('networkidle');
    await expect(page).toHaveScreenshot('${slug}-desktop.png', {
      maxDiffPixelRatio: 0.02,
    });
  });

  test('component renders without layout shift', async ({ page }) => {
    await page.goto(\`\${BASE_URL}/components\`);
    // TODO: navigate to your component preview/Storybook URL
    await page.waitForLoadState('networkidle');
    await expect(page).toHaveScreenshot('${slug}-component.png');
  });

  test('dark mode toggle does not break layout', async ({ page }) => {
    await page.goto(BASE_URL);
    await page.waitForLoadState('networkidle');
    // TODO: adjust selector to match your dark mode toggle
    await page.click('[data-testid="theme-toggle"], button[aria-label*="dark"], button[aria-label*="theme"]');
    await page.waitForTimeout(300); // allow CSS transition
    await expect(page).toHaveScreenshot('${slug}-dark-mode.png', {
      maxDiffPixelRatio: 0.02,
    });
  });
});
`;
}
function generatePytestPlaywrightTest(title, slug) {
    const pySlug = slug.replace(/-/g, '_');
    return `"""Visual regression tests for ${title} — pytest-playwright."""
# Requires: pytest-playwright + pytest-playwright-snapshot
# Install: pip install pytest-playwright playwright-pytest-snapshot
# Run: pytest --update-snapshots (first time to create baseline)
import pytest
from playwright.sync_api import Page, expect


BASE_URL = "http://localhost:3000"


@pytest.fixture(scope="session")
def base_url() -> str:
    import os
    return os.environ.get("BASE_URL", BASE_URL)


def test_${pySlug}_full_page_screenshot(page: Page, base_url: str, assert_snapshot: object) -> None:
    """Full-page screenshot matches approved baseline."""
    page.goto(base_url)
    page.wait_for_load_state("networkidle")
    assert_snapshot(page.screenshot(full_page=True), name="${slug}-baseline.png")


def test_${pySlug}_responsive_mobile(page: Page, base_url: str, assert_snapshot: object) -> None:
    """Layout intact at 375px (mobile)."""
    page.set_viewport_size({"width": ${BP_MOBILE.width}, "height": ${BP_MOBILE.height}})
    page.goto(base_url)
    page.wait_for_load_state("networkidle")
    assert_snapshot(page.screenshot(), name="${slug}-mobile.png")


def test_${pySlug}_responsive_tablet(page: Page, base_url: str, assert_snapshot: object) -> None:
    """Layout intact at 768px (tablet)."""
    page.set_viewport_size({"width": ${BP_TABLET.width}, "height": ${BP_TABLET.height}})
    page.goto(base_url)
    page.wait_for_load_state("networkidle")
    assert_snapshot(page.screenshot(), name="${slug}-tablet.png")


def test_${pySlug}_responsive_desktop(page: Page, base_url: str, assert_snapshot: object) -> None:
    """Layout intact at 1280px (desktop)."""
    page.set_viewport_size({"width": ${BP_DESKTOP.width}, "height": ${BP_DESKTOP.height}})
    page.goto(base_url)
    page.wait_for_load_state("networkidle")
    assert_snapshot(page.screenshot(), name="${slug}-desktop.png")


def test_${pySlug}_dark_mode(page: Page, base_url: str, assert_snapshot: object) -> None:
    """Dark mode toggle does not break layout."""
    page.goto(base_url)
    page.wait_for_load_state("networkidle")
    # TODO: adjust selector to match your dark mode toggle
    page.click('[data-testid="theme-toggle"]')
    page.wait_for_timeout(300)
    assert_snapshot(page.screenshot(), name="${slug}-dark-mode.png")
`;
}
function generateCypressVisualTest(title, slug) {
    return `// Visual regression tests for ${title} — Cypress + cypress-image-snapshot
// Install: npm install --save-dev cypress-image-snapshot
// Config: import 'cypress-image-snapshot/command' in cypress/support/commands.ts
describe('${title} — Visual Regression', () => {
  const BASE_URL = Cypress.env('BASE_URL') ?? 'http://localhost:3000';

  it('full-page screenshot matches baseline', () => {
    cy.visit(BASE_URL);
    cy.matchImageSnapshot('${slug}-baseline', { failureThreshold: 0.02 });
  });

  it('responsive — mobile 375px', () => {
    cy.viewport(${BP_MOBILE.width}, ${BP_MOBILE.height});
    cy.visit(BASE_URL);
    cy.matchImageSnapshot('${slug}-mobile', { failureThreshold: 0.02 });
  });

  it('responsive — tablet 768px', () => {
    cy.viewport(${BP_TABLET.width}, ${BP_TABLET.height});
    cy.visit(BASE_URL);
    cy.matchImageSnapshot('${slug}-tablet', { failureThreshold: 0.02 });
  });

  it('responsive — desktop 1280px', () => {
    cy.viewport(${BP_DESKTOP.width}, ${BP_DESKTOP.height});
    cy.visit(BASE_URL);
    cy.matchImageSnapshot('${slug}-desktop', { failureThreshold: 0.02 });
  });

  it('dark mode toggle does not break layout', () => {
    cy.visit(BASE_URL);
    // TODO: adjust selector to match your dark mode toggle
    cy.get('[data-testid="theme-toggle"]').click();
    cy.wait(300); // allow CSS transition
    cy.matchImageSnapshot('${slug}-dark-mode', { failureThreshold: 0.02 });
  });
});
`;
}
function generateVisualTestContent(title, slug, framework, language) {
    if (language === 'python') {
        return generatePytestPlaywrightTest(title, slug);
    }
    if (framework === 'cypress') {
        return generateCypressVisualTest(title, slug);
    }
    return generatePlaywrightTest(title, slug);
}
function getFileExtension(language) {
    const exts = {
        python: 'py',
        go: 'go',
        ruby: 'rb',
        java: 'java',
        javascript: 'test.ts',
        typescript: 'test.ts',
    };
    return exts[language] ?? 'test.ts';
}
/**
 * Generate visual regression test files for the given spec.
 */
export function generateVisualRegressionTestFiles(spec, testDir, framework, language, testExt, autoGenerate) {
    const ext = language === 'python' ? 'py' : getFileExtension(language);
    const resolvedFramework = framework === 'cypress' ? 'cypress' : 'playwright';
    const content = generateVisualTestContent(spec.title, spec.slug, framework, language);
    return [
        {
            path: `${testDir}/visual/${spec.slug}.visual.${ext === 'test.ts' ? testExt : ext}`,
            framework: resolvedFramework,
            content,
            ready: autoGenerate,
        },
    ];
}
// Re-export for dark mode detection utility (used in spec-dispatcher if needed)
export { hasDarkModeSupport };
//# sourceMappingURL=visual-regression-generator.js.map