import { readFileSync } from "node:fs";
import { dirname, join } from "node:path";
import { fileURLToPath } from "node:url";
import { MATRIX_CELL_VERSION } from "../../../schema/src/records/context.js";
import type { MatrixCell } from "../../../schema/src/records/context.js";
import type { GeometryFixture, GeometryRuleId } from "../../src/geometry/types.js";

const FIXTURES_DIR = join(dirname(fileURLToPath(import.meta.url)), "html");

function readHtml(name: string): string {
  return readFileSync(join(FIXTURES_DIR, name), "utf8");
}

function baseCell(overrides: Partial<MatrixCell> = {}): MatrixCell {
  return {
    schemaVersion: MATRIX_CELL_VERSION,
    id: "geometry-cell-fixture",
    creationSource: {
      runId: "geometry-fixture-run",
      component: "orchestrator",
      componentId: "geometry-fixtures",
    },
    routeId: "geometry-fixture",
    url: "/fixture",
    role: "anonymous",
    locale: "en-US",
    viewport: { width: 800, height: 600, deviceScaleFactor: 1 },
    state: {},
    actions: [],
    seed: "",
    ...overrides,
  };
}

function fixture(
  ruleId: GeometryRuleId,
  variant: GeometryFixture["variant"],
  htmlFile: string,
  options: {
    cell?: Partial<MatrixCell>;
    intentionalContractId?: string;
  } = {},
): GeometryFixture {
  return {
    fixtureId: `${ruleId.toLowerCase()}-${variant}`,
    ruleId,
    variant,
    route: "/fixture",
    html: readHtml(htmlFile),
    ...(options.cell === undefined ? {} : { cell: options.cell }),
    ...(options.intentionalContractId === undefined
      ? {}
      : { intentionalContractId: options.intentionalContractId }),
  };
}

export const geometryFixtureGallery: GeometryFixture[] = [
  fixture("UI-020", "positive", "ui-020-positive.html", {
    cell: { state: { uiGeometryTolerancePx: "2" } },
  }),
  fixture("UI-020", "negative", "ui-020-negative.html"),
  fixture("UI-020", "intentional-exception", "ui-020-intentional-exception.html", {
    intentionalContractId: "geometry-ui-020-exception",
  }),
  fixture("UI-020", "rtl", "ui-020-rtl-positive.html", {
    cell: { locale: "ar-SA", id: "ui-020-rtl", state: { uiGeometryTolerancePx: "2" } },
  }),
  fixture("UI-020", "changed-fingerprint", "ui-020-changed-fingerprint.html", {
    cell: { state: { uiGeometryTolerancePx: "2" } },
  }),

  fixture("UI-021", "positive", "ui-021-positive.html"),
  fixture("UI-021", "negative", "ui-021-negative.html"),
  fixture("UI-021", "intentional-exception", "ui-021-intentional-exception.html"),

  fixture("UI-022", "positive", "ui-022-positive.html"),
  fixture("UI-022", "negative", "ui-022-negative.html"),
  fixture("UI-022", "intentional-exception", "ui-022-intentional-exception.html", {
    intentionalContractId: "geometry-ui-022-exception",
  }),

  fixture("UI-023", "positive", "ui-023-positive.html"),
  fixture("UI-023", "negative", "ui-023-negative.html"),
  fixture("UI-023", "intentional-exception", "ui-023-intentional-exception.html", {
    intentionalContractId: "geometry-ui-023-exception",
  }),

  fixture("UI-024", "positive", "ui-024-positive.html"),
  fixture("UI-024", "negative", "ui-024-negative.html"),
  fixture("UI-024", "intentional-exception", "ui-024-intentional-exception.html"),
  fixture("UI-024", "rtl", "ui-024-rtl-positive.html", {
    cell: { locale: "ar-SA", id: "ui-024-rtl" },
  }),
];

export function cellForFixture(entry: GeometryFixture): MatrixCell {
  return baseCell({
    id: entry.fixtureId,
    routeId: entry.fixtureId,
    url: entry.route,
    ...(entry.cell ?? {}),
  });
}

export function fixturesForRule(ruleId: GeometryRuleId): GeometryFixture[] {
  return geometryFixtureGallery.filter((entry) => entry.ruleId === ruleId);
}

export function positiveFixture(ruleId: GeometryRuleId): GeometryFixture {
  const match = fixturesForRule(ruleId).find((entry) => entry.variant === "positive");
  if (match === undefined) {
    throw new Error(`positive fixture missing for ${ruleId}`);
  }
  return match;
}

export function negativeFixture(ruleId: GeometryRuleId): GeometryFixture {
  const match = fixturesForRule(ruleId).find((entry) => entry.variant === "negative");
  if (match === undefined) {
    throw new Error(`negative fixture missing for ${ruleId}`);
  }
  return match;
}
