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 { LayoutFixture, LayoutRuleId, TransitionCheckpointKind } from "../../src/layout/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: "layout-cell-fixture",
    creationSource: {
      runId: "layout-fixture-run",
      component: "orchestrator",
      componentId: "layout-fixtures",
    },
    routeId: "layout-fixture",
    url: "/fixture",
    role: "anonymous",
    locale: "en-US",
    viewport: { width: 800, height: 600, deviceScaleFactor: 1 },
    state: {},
    actions: [],
    seed: "",
    ...overrides,
  };
}

function settledCell(overrides: Partial<MatrixCell> = {}): Partial<MatrixCell> {
  return {
    state: { uiCompletionSignal: "#ready" },
    ...overrides,
  };
}

function checkpointAction(
  id: string,
  target: string,
  settleMs = "150",
): MatrixCell["actions"][number] {
  return {
    id,
    kind: "click",
    target,
    params: { checkpoint: "true", settleMs },
  };
}

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

export const layoutFixtureGallery: LayoutFixture[] = [
  fixture("UI-030", "positive", "ui-030-positive.html", {
    cell: settledCell(),
  }),
  fixture("UI-030", "negative", "ui-030-negative.html", {
    cell: settledCell(),
  }),
  fixture("UI-030", "intentional-exception", "ui-030-intentional-exception.html", {
    cell: settledCell(),
    intentionalContractId: "layout-ui-030-exception",
  }),
  fixture("UI-030", "rtl", "ui-030-rtl-positive.html", {
    cell: settledCell({ locale: "ar-SA", id: "ui-030-rtl" }),
  }),
  fixture("UI-030", "changed-fingerprint", "ui-030-changed-fingerprint.html", {
    cell: settledCell({ id: "ui-030-changed-fingerprint" }),
  }),

  fixture("UI-031", "positive", "ui-031-positive.html", {
    cell: settledCell(),
  }),
  fixture("UI-031", "negative", "ui-031-negative.html", {
    cell: settledCell(),
  }),
  fixture("UI-031", "intentional-exception", "ui-031-intentional-exception.html", {
    cell: settledCell(),
    intentionalContractId: "layout-ui-031-exception",
  }),
  fixture("UI-031", "rtl", "ui-031-rtl-positive.html", {
    cell: settledCell({ locale: "ar-SA", id: "ui-031-rtl" }),
  }),
  fixture("UI-031", "changed-fingerprint", "ui-031-changed-fingerprint.html", {
    cell: settledCell({ id: "ui-031-changed-fingerprint" }),
  }),

  fixture("UI-032", "positive", "ui-032-spinner-positive.html", {
    checkpointKind: "spinner-to-content-replacement",
    cell: {
      actions: [checkpointAction("load", "#load")],
    },
  }),
  fixture("UI-032", "negative", "ui-032-negative.html", {
    cell: {
      actions: [checkpointAction("load", "#load")],
    },
  }),
  fixture("UI-032", "intentional-exception", "ui-032-intentional-exception.html", {
    checkpointKind: "spinner-to-content-replacement",
    intentionalContractId: "layout-ui-032-exception",
    cell: {
      actions: [checkpointAction("load", "#load")],
    },
  }),
  fixture("UI-032", "rtl", "ui-032-rtl-positive.html", {
    checkpointKind: "focus-loss",
    cell: {
      locale: "ar-SA",
      id: "ui-032-rtl",
      actions: [
        { id: "focus-name", kind: "focus", target: "#name" },
        checkpointAction("save", "#save", "50"),
      ],
    },
  }),
  fixture("UI-032", "changed-fingerprint", "ui-032-changed-fingerprint.html", {
    checkpointKind: "state-swap-instead-of-update",
    cell: {
      id: "ui-032-changed-fingerprint",
      actions: [checkpointAction("increment", "#increment", "50")],
    },
  }),

  {
    fixtureId: "ui-032-state-swap-positive",
    ruleId: "UI-032",
    variant: "positive",
    route: "/fixture",
    html: readHtml("ui-032-state-swap-positive.html"),
    checkpointKind: "state-swap-instead-of-update",
    cell: {
      actions: [checkpointAction("increment", "#increment", "50")],
    },
  },
  {
    fixtureId: "ui-032-focus-loss-positive",
    ruleId: "UI-032",
    variant: "positive",
    route: "/fixture",
    html: readHtml("ui-032-focus-loss-positive.html"),
    checkpointKind: "focus-loss",
    cell: {
      actions: [
        { id: "focus-name", kind: "focus", target: "#name" },
        checkpointAction("save", "#save", "50"),
      ],
    },
  },
  {
    fixtureId: "ui-032-scroll-jump-positive",
    ruleId: "UI-032",
    variant: "positive",
    route: "/fixture",
    html: readHtml("ui-032-scroll-jump-positive.html"),
    checkpointKind: "scroll-jump",
    cell: {
      actions: [checkpointAction("jump", "#jump", "50")],
    },
  },
  {
    fixtureId: "ui-032-stale-ui-positive",
    ruleId: "UI-032",
    variant: "positive",
    route: "/fixture",
    html: readHtml("ui-032-stale-ui-positive.html"),
    checkpointKind: "stale-ui-after-mutation",
    cell: {
      state: { expectedMutationVersion: "2" },
      actions: [checkpointAction("mutate", "#mutate", "50")],
    },
  },
  {
    fixtureId: "ui-032-optimistic-rollback-positive",
    ruleId: "UI-032",
    variant: "positive",
    route: "/fixture",
    html: readHtml("ui-032-optimistic-rollback-positive.html"),
    checkpointKind: "missing-optimistic-rollback",
    cell: {
      state: { optimisticBaselineValue: "saved" },
      actions: [checkpointAction("optimistic", "#optimistic", "200")],
    },
  },
];

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

export function fixturesForRule(ruleId: LayoutRuleId): LayoutFixture[] {
  return layoutFixtureGallery.filter((entry) => entry.ruleId === ruleId);
}

export function positiveFixture(ruleId: LayoutRuleId): LayoutFixture {
  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: LayoutRuleId): LayoutFixture {
  const match = fixturesForRule(ruleId).find((entry) => entry.variant === "negative");
  if (match === undefined) {
    throw new Error(`negative fixture missing for ${ruleId}`);
  }
  return match;
}

export function checkpointFixture(kind: TransitionCheckpointKind): LayoutFixture {
  const match = layoutFixtureGallery.find((entry) => entry.checkpointKind === kind);
  if (match === undefined) {
    throw new Error(`checkpoint fixture missing for ${kind}`);
  }
  return match;
}
