import { rmSync } from "node:fs";
import { mkdtemp } from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { afterEach, describe, expect, test } from "vitest";
import { dimensionLabDashboardFixture } from "$lib/dashboard-seed/dimensionlab";
import { genericDashboardFixture } from "@dimensionlab/dashboard-model/fixtures";
import { createDashboardStore, type DashboardStore } from "./db/dashboard-store";
import { loadDashboardRuntime } from "./dashboard";

const stores: DashboardStore[] = [];
const tempRoots: string[] = [];

afterEach(() => {
  stores.splice(0).forEach((store) => store.close());
  tempRoots.splice(0).forEach((path) => rmSync(path, { force: true, recursive: true }));
});

describe("dashboard runtime loader", () => {
  test("seeds and loads the active dashboard from sqlite", async () => {
    const store = await createTestStore();

    const runtime = loadDashboardRuntime(store, { seedIfEmpty: true });

    expect(runtime.state).toBe("ready");
    if (runtime.state !== "ready") throw new Error("expected ready dashboard");
    expect(runtime.document.metadata.title).toBe(dimensionLabDashboardFixture.metadata.title);
    expect(runtime.document.metadata.subtitle).toBe(dimensionLabDashboardFixture.metadata.subtitle);
    expect(runtime.schemaVersion).toBe(dimensionLabDashboardFixture.schemaVersion);
    expect(runtime.currentRevisionId).toBe(store.getActiveDashboard()?.currentRevisionId);
    expect(store.listRevisions()).toHaveLength(1);
  });

  test("loads an existing active dashboard without reseeding", async () => {
    const store = await createTestStore();
    const seed = store.commitDashboard(genericDashboardFixture, {
      actor: "test",
      message: "existing dashboard",
    });

    const runtime = loadDashboardRuntime(store);

    expect(runtime.state).toBe("ready");
    if (runtime.state !== "ready") throw new Error("expected ready dashboard");
    expect(runtime.currentRevisionId).toBe(seed.id);
    expect(runtime.document.metadata.title).toBe(genericDashboardFixture.metadata.title);
    expect(store.listRevisions()).toHaveLength(1);
  });

  test("refreshes an existing initial seed when the bundled seed changes", async () => {
    const store = await createTestStore();
    const oldSeed = olderDimensionLabSeed();
    store.seedDashboardIfEmpty(oldSeed, {
      actor: "initial-seed",
      message: "load initial dashboard document",
    });

    const runtime = loadDashboardRuntime(store, {
      refreshSeedDocument: true,
      seedDocument: dimensionLabDashboardFixture,
      seedIfEmpty: true,
    });

    expect(runtime.state).toBe("ready");
    if (runtime.state !== "ready") throw new Error("expected ready dashboard");
    expect(runtime.document.statusStrips[0]?.items.map((item) => item.id)).toContain(
      "auto-refresh",
    );
    expect(runtime.document.serviceGroups.flatMap((group) => group.services).map((service) => service.id)).toContain(
      "prompt-registry",
    );
    expect(store.listRevisions()).toHaveLength(2);
    expect(store.getActiveDashboard()?.revision.actor).toBe("initial-seed");
  });

  test("does not refresh a dashboard after a user-authored revision", async () => {
    const store = await createTestStore();
    const oldSeed = olderDimensionLabSeed();
    store.seedDashboardIfEmpty(oldSeed, {
      actor: "initial-seed",
      message: "load initial dashboard document",
    });
    store.commitDashboard(
      {
        ...oldSeed,
        metadata: {
          ...oldSeed.metadata,
          title: "Custom Dashboard",
        },
      },
      {
        actor: "agent",
        message: "customize dashboard",
      },
    );

    const runtime = loadDashboardRuntime(store, {
      refreshSeedDocument: true,
      seedDocument: dimensionLabDashboardFixture,
      seedIfEmpty: true,
    });

    expect(runtime.state).toBe("ready");
    if (runtime.state !== "ready") throw new Error("expected ready dashboard");
    expect(runtime.document.metadata.title).toBe("Custom Dashboard");
    expect(runtime.document.statusStrips[0]?.items.map((item) => item.id)).not.toContain(
      "auto-refresh",
    );
    expect(store.listRevisions()).toHaveLength(2);
  });

  test("returns empty state when no dashboard is active and seeding is disabled", async () => {
    const store = await createTestStore();

    const runtime = loadDashboardRuntime(store);

    expect(runtime.state).toBe("empty");
    if (runtime.state !== "empty") throw new Error("expected empty dashboard");
    expect(runtime.title).toBe("No Dashboard Model");
    expect(store.listRevisions()).toHaveLength(0);
  });
});

async function createTestStore() {
  const root = await mkdtemp(join(tmpdir(), "dimensionlab-dashboard-runtime-"));
  tempRoots.push(root);
  const store = createDashboardStore({
    databaseUrl: `file:${join(root, "dashboard.sqlite")}`,
  });
  stores.push(store);

  return store;
}

function olderDimensionLabSeed() {
  const document = structuredClone(dimensionLabDashboardFixture);
  document.statusStrips = document.statusStrips.map((strip) => ({
    ...strip,
    items: strip.items.filter((item) => item.id !== "auto-refresh"),
  }));
  document.serviceGroups = document.serviceGroups.map((group) =>
    group.id === "ai-automation"
      ? {
          ...group,
          services: group.services.filter((service) => service.id !== "prompt-registry"),
        }
      : group,
  );
  return document;
}
