import { When, Then } from "@cucumber/cucumber";
import { fixture } from "@hooks/pageFixture";

/**
 * VRT Step Definitions
 *
 * These steps can be added to any feature file to capture visual snapshots
 * at specific points during test execution.
 *
 * Environment variables:
 *   VRT_MODE=baseline  — Save screenshots as reference baselines
 *   VRT_MODE=test      — Compare screenshots against baselines
 *   VRT_MODE=off       — Skip VRT (default)
 *   VRT_SPRINT=sprint-1 — Sprint label for baseline organisation
 *   VRT_THRESHOLD=0.1  — Per-pixel colour tolerance
 *   VRT_FAILURE_THRESHOLD=0.1 — Max % mismatch before failure
 */

// ─── Generic capture step ─────────────────────────────────────────────

When(
  "capture visual snapshot {string}",
  async function (snapshotName: string): Promise<void> {
    const currentFixture = fixture();
    if (!currentFixture.vrtCapture?.isActive) return;

    await currentFixture.vrtCapture.capture(currentFixture.page, snapshotName);
    currentFixture.logger.info(`[VRT] Captured snapshot: ${snapshotName}`);
  },
);

// ─── Capture with full-page option ────────────────────────────────────

When(
  "capture full page visual snapshot {string}",
  async function (snapshotName: string): Promise<void> {
    const currentFixture = fixture();
    if (!currentFixture.vrtCapture?.isActive) return;

    await currentFixture.vrtCapture.capture(currentFixture.page, snapshotName, {
      fullPage: true,
    });
    currentFixture.logger.info(
      `[VRT] Captured full-page snapshot: ${snapshotName}`,
    );
  },
);

// ─── Capture with custom masking ──────────────────────────────────────

When(
  "capture visual snapshot {string} masking {string}",
  async function (
    snapshotName: string,
    maskSelectorsRaw: string,
  ): Promise<void> {
    const currentFixture = fixture();
    if (!currentFixture.vrtCapture?.isActive) return;

    const maskSelectors = maskSelectorsRaw.split(",").map((s) => s.trim());
    await currentFixture.vrtCapture.capture(currentFixture.page, snapshotName, {
      maskSelectors,
    });
    currentFixture.logger.info(
      `[VRT] Captured snapshot: ${snapshotName} (with custom masks)`,
    );
  },
);

// ─── Capture after waiting for a selector ─────────────────────────────

When(
  "capture visual snapshot {string} after {string} is visible",
  async function (snapshotName: string, waitSelector: string): Promise<void> {
    const currentFixture = fixture();
    if (!currentFixture.vrtCapture?.isActive) return;

    // Wait for the element to be visible before capturing
    await currentFixture.page
      .locator(waitSelector)
      .waitFor({ state: "visible", timeout: 10_000 });

    await currentFixture.vrtCapture.capture(currentFixture.page, snapshotName);
    currentFixture.logger.info(
      `[VRT] Captured snapshot: ${snapshotName} (after ${waitSelector} visible)`,
    );
  },
);

// ─── Assertion: all VRT snapshots passed ──────────────────────────────

Then(
  "all visual snapshots should match baselines",
  async function (): Promise<void> {
    const currentFixture = fixture();
    if (!currentFixture.vrtCapture?.isActive) return;

    const summary = currentFixture.vrtCapture.getSummary();
    currentFixture.logger.info(
      `[VRT] Summary — Total: ${summary.total}, Passed: ${summary.passed}, Failed: ${summary.failed}, New: ${summary.newSnapshots}`,
    );

    if (summary.failed > 0) {
      const failures = currentFixture.vrtCapture.diffResults
        .filter((r) => !r.passed)
        .map(
          (r) =>
            `  - ${r.snapshotName}: ${r.mismatchPercentage.toFixed(3)}% mismatch (diff: ${r.diffPath})`,
        )
        .join("\n");

      throw new Error(
        `[VRT] ${summary.failed} visual regression(s) detected:\n${failures}`,
      );
    }
  },
);

// ─── Assertion: specific snapshot should match ────────────────────────

Then(
  "visual snapshot {string} should match baseline",
  async function (snapshotName: string): Promise<void> {
    const currentFixture = fixture();
    if (!currentFixture.vrtCapture?.isActive) return;

    const result = currentFixture.vrtCapture.diffResults.find((r) =>
      r.snapshotName.includes(
        snapshotName.replace(/[^a-zA-Z0-9_-]/g, "_").toLowerCase(),
      ),
    );

    if (!result) {
      throw new Error(`[VRT] No capture found for snapshot: ${snapshotName}`);
    }

    if (!result.passed) {
      throw new Error(
        `[VRT] Visual regression detected for "${snapshotName}": ` +
          `${result.mismatchPercentage.toFixed(3)}% mismatch (diff: ${result.diffPath})`,
      );
    }
  },
);
