"""
VRT (Visual Regression Testing) scaffold.

Enabled via `stlc-migrate --features=vrt`, or auto-detected when the source
project already uses VRT (vrt:* npm scripts or VRT_MODE in any .env file).

When enabled, the migration drops:
  • src/helper/vrt/vrtCapture.util.ts   — pixelmatch capture + diff
  • src/helper/vrt/vrtReport.util.ts    — HTML report generator
  • src/test/steps/vrt.steps.ts         — Cucumber step defs for VRT

And the surrounding wiring:
  • VRT block kept in `.env.example` (suppressed when VRT is off)
  • Scaffolded `pageFixture.ts` gains a `vrtCapture` field and `logger`
  • Scaffolded `hooks.ts` initialises VRTCapture per scenario + generates a
    report in AfterAll
  • `merge_package_json` adds `vrt:baseline` / `vrt:test` scripts and the
    `pngjs` / `pixelmatch` / `fs-extra` runtime deps (+ `@types/*` companions)

Operator-side caveat: when the source ships its own `hooks.ts` /
`pageFixture.ts`, those files are not rewritten — the operator must wire
VRTCapture in themselves. The MIGRATION-REPORT flags this case.
"""
from __future__ import annotations

import json
from pathlib import Path

_VRT_ASSETS_DIR = Path(__file__).parent / "vrt_assets"

# Filename → target path under helix root.
_VRT_FILES: dict[str, str] = {
    "vrtCapture.util.ts": "src/helper/vrt/vrtCapture.util.ts",
    "vrtReport.util.ts":  "src/helper/vrt/vrtReport.util.ts",
    "vrt.steps.ts":       "src/test/steps/vrt.steps.ts",
}


def autodetect_vrt(source_dir: str | Path) -> bool:
    """
    Return True when the source project already uses VRT — either via
    `vrt:*` npm scripts in package.json, or any `VRT_*` reference in a
    sibling .env / .env.example file.
    """
    root = Path(source_dir)
    pkg = root / "package.json"
    if pkg.exists():
        try:
            data = json.loads(pkg.read_text(encoding="utf-8"))
            scripts = (data.get("scripts") or {})
            if any(name.startswith("vrt:") for name in scripts):
                return True
            if any("VRT_MODE" in cmd or "vrt:" in cmd for cmd in scripts.values()):
                return True
        except Exception:
            pass
    for env_file in list(root.glob(".env*")) + list(root.glob("**/.env*"))[:50]:
        try:
            if "VRT_MODE" in env_file.read_text(encoding="utf-8"):
                return True
        except Exception:
            continue
    return False


def parse_features(raw: str | None) -> set[str]:
    """Parse the CSV `--features` argument into a normalised set."""
    if not raw:
        return set()
    return {tok.strip().lower() for tok in raw.split(",") if tok.strip()}


def scaffold_vrt(
    root: Path,
    written: list[dict],
    conflict_strategy: str,
) -> None:
    """
    Drop the three VRT `.ts` files into the helix tree.

    Honors `--conflict overwrite` — existing files are only refreshed when
    overwrite is on. Source rows are added to `written` so they appear in
    MIGRATION-REPORT.md.
    """
    overwrite = conflict_strategy == "overwrite"
    for asset_name, rel_target in _VRT_FILES.items():
        asset = _VRT_ASSETS_DIR / asset_name
        if not asset.exists():
            continue  # ship-time asset missing — silently skip
        target = root / rel_target
        if target.exists() and not overwrite:
            continue
        target.parent.mkdir(parents=True, exist_ok=True)
        target.write_text(asset.read_text(encoding="utf-8"), encoding="utf-8")
        written.append({
            "source":       f"(vrt scaffold) {asset_name}",
            "target":       rel_target,
            "role":         "vrt",
            "change_count": 0,
        })


# ──────────────────────────────────────────────────────────────────────────────
# pageFixture.ts / hooks.ts templates (VRT-enabled variants)
# ──────────────────────────────────────────────────────────────────────────────
# These are used by `_scaffold_page_fixture` in `_migrate.py` when VRT is on
# AND the migration is responsible for emitting the fixture/hooks files (i.e.
# the source didn't ship its own). When the source already has hooks files,
# the migration leaves them alone; MIGRATION-REPORT.md tells the operator to
# wire `VRTCapture` themselves — see the snippet below.

PAGE_FIXTURE_VRT_TS = '''\
import { Page, Browser, BrowserContext } from "@playwright/test";
import { Logger } from "winston";
import { LocatorRepository } from "@utils/locators/LocatorRepository";
import { LocatorHealer } from "@utils/locators/LocatorHealer";
import { TimingHealer } from "@utils/locators/TimingHealer";
import { VisualIntentChecker } from "@utils/locators/VisualIntentChecker";
import { VRTCapture } from "@helper/vrt/vrtCapture.util";

export interface PageFixture {
  page: Page;
  browser?: Browser;
  context?: BrowserContext;
  logger: Logger;
  locatorRepository: LocatorRepository;
  locatorHealer: LocatorHealer;
  locatorTiming: TimingHealer;
  locatorVisual: VisualIntentChecker;
  vrtCapture?: VRTCapture;
}

export interface FixtureServices {
  locatorRepository: LocatorRepository;
  locatorHealer: LocatorHealer;
  locatorTiming: TimingHealer;
  locatorVisual: VisualIntentChecker;
}

export function buildFixtureServices(page: Page, logger: Logger, scenarioName?: string): FixtureServices {
  const locatorRepository = new LocatorRepository();
  const locatorHealer = new LocatorHealer(page, logger, locatorRepository);
  locatorHealer.currentScenario = scenarioName;

  return {
    locatorRepository,
    locatorHealer,
    locatorTiming: new TimingHealer(page, logger),
    locatorVisual: new VisualIntentChecker(page, logger),
  };
}

let _current: PageFixture | undefined;

export function setFixture(f: PageFixture): void {
  _current = f;
}

export function fixture(): PageFixture {
  if (!_current) throw new Error("PageFixture not initialised — Before hook must call setFixture(...)");
  return _current;
}
'''

HOOKS_VRT_TS = '''\
import { Before, After, BeforeAll, AfterAll } from "@cucumber/cucumber";
import { chromium, Browser, Page } from "@playwright/test";
import { createLogger, format, transports, Logger } from "winston";
import { setFixture, fixture, buildFixtureServices } from "./pageFixture";
import { VRTCapture } from "@helper/vrt/vrtCapture.util";
import { VRTReportGenerator } from "@helper/vrt/vrtReport.util";

let browser: Browser;
let page:    Page;
let logger:  Logger;

BeforeAll(async () => {
  logger = createLogger({
    level:  process.env.LOG_LEVEL || "info",
    format: format.combine(format.timestamp(), format.simple()),
    transports: [new transports.Console()],
  });
  browser = await chromium.launch({ headless: process.env.HEADLESS !== "false" });
});

Before(async function (scenario) {
  const context = await browser.newContext();
  page = await context.newPage();

  const scenarioName = scenario?.pickle?.name || "scenario";
  const vrtScenarioName = scenarioName.replace(/[^a-zA-Z0-9_-]/g, "_").toLowerCase();
  const vrtCapture = new VRTCapture(logger, vrtScenarioName, process.env.VRT_SPRINT);
  if (vrtCapture.isActive) {
    logger.info(`[VRT] Initialized — mode=${process.env.VRT_MODE}, sprint=${process.env.VRT_SPRINT || "default"}`);
  }
  const services = buildFixtureServices(page, logger, scenarioName);

  setFixture({
    page,
    browser,
    context,
    logger,
    ...services,
    vrtCapture,
  });
});

After(async function () {
  const fx = fixture();
  if (fx.vrtCapture?.isActive && fx.vrtCapture.diffResults.length > 0) {
    VRTReportGenerator.registerScenarioResults(
      this?.pickle?.name || "scenario",
      fx.vrtCapture.diffResults,
    );
    const summary = fx.vrtCapture.getSummary();
    logger.info(
      `[VRT] Scenario results — Total: ${summary.total}, Passed: ${summary.passed}, Failed: ${summary.failed}, New: ${summary.newSnapshots}`,
    );
  }
  await page.context().close();
});

AfterAll(async () => {
  const vrtReportPath = VRTReportGenerator.generate();
  if (vrtReportPath) {
    console.log(`[VRT] Report generated: ${vrtReportPath}`);
    VRTReportGenerator.clear();
  }
  await browser.close();
});
'''


# Snippet emitted in MIGRATION-REPORT.md so operators with existing hooks
# can wire VRTCapture in themselves.
HOOKS_WIRING_SNIPPET = '''\
// In hooks.ts — alongside your existing Before/After:
import { VRTCapture } from "@helper/vrt/vrtCapture.util";
import { VRTReportGenerator } from "@helper/vrt/vrtReport.util";
import { buildFixtureServices } from "./pageFixture";

Before(async function (scenario) {
  // ... existing setup ...
  const scenarioName = (scenario?.pickle?.name || "scenario")
    .replace(/[^a-zA-Z0-9_-]/g, "_").toLowerCase();
  Object.assign(fixture(), buildFixtureServices(fixture().page, fixture().logger, scenarioName));
  fixture().vrtCapture = new VRTCapture(fixture().logger, scenarioName, process.env.VRT_SPRINT);
});

After(async function () {
  const fx = fixture();
  if (fx.vrtCapture?.isActive && fx.vrtCapture.diffResults.length > 0) {
    VRTReportGenerator.registerScenarioResults(
      this?.pickle?.name || "scenario",
      fx.vrtCapture.diffResults,
    );
  }
  // ... existing teardown ...
});

AfterAll(async () => {
  const reportPath = VRTReportGenerator.generate();
  if (reportPath) VRTReportGenerator.clear();
  // ... existing teardown ...
});

// In pageFixture.ts — extend the PageFixture interface:
import { LocatorRepository } from "@utils/locators/LocatorRepository";
import { LocatorHealer } from "@utils/locators/LocatorHealer";
import { TimingHealer } from "@utils/locators/TimingHealer";
import { VisualIntentChecker } from "@utils/locators/VisualIntentChecker";
import { VRTCapture } from "@helper/vrt/vrtCapture.util";
export interface PageFixture {
  // ... existing fields ...
  locatorRepository: LocatorRepository;
  locatorHealer: LocatorHealer;
  locatorTiming: TimingHealer;
  locatorVisual: VisualIntentChecker;
  vrtCapture?: VRTCapture;
}
'''
