import { renderToString } from "react-dom/server";
import { describe, expect, test } from "vitest";
import { genericDashboardFixture } from "@dimensionlab/dashboard-model/fixtures";
import { dimensionLabDashboardFixture } from "$lib/dashboard-seed/dimensionlab";
import {
  AppStateView,
  dashboardTileMatchKey,
  dashboardHydrationTiles,
  restoreDashboardTileSnapshots,
} from "./App";

describe("React app dashboard state view", () => {
  test("renders loading dashboard state", () => {
    const html = renderToString(
      <AppStateView
        dashboard={{
          state: "loading",
          title: "Loading Dashboard",
          subtitle: "Fetching active model",
          message: "Waiting for the active dashboard document.",
        }}
      />,
    );

    expect(html).toContain("Loading Dashboard");
    expect(html).toContain("Fetching active model");
  });

  test("renders an accessible theme toggle with the active theme", () => {
    const html = renderToString(
      <AppStateView
        dashboard={{
          state: "loading",
          title: "Loading Dashboard",
          subtitle: "Fetching active model",
          message: "Waiting for the active dashboard document.",
        }}
        theme="dark"
        onThemeChange={() => undefined}
      />,
    );

    expect(html).toContain('data-ui-theme-toggle="true"');
    expect(html).toContain('data-ui-theme-current="dark"');
    expect(html).toContain('aria-label="Light theme"');
    expect(html).toContain('aria-pressed="false"');
    expect(html).toContain("Theme");
    expect(html).toContain("Dark");
    expect(html).toContain("Light");
  });

  test("renders the dashboard shell while individual items hydrate", () => {
    const html = renderToString(
      <AppStateView
        dashboard={{
          state: "ready",
          document: genericDashboardFixture,
          schemaVersion: "dashboard.v1",
          currentRevisionId: "revision-1234567890",
        }}
        hydratingItemIds={new Set([
          "telemetry:service-uptime",
          "service:core-services:identity",
          "module:ambient",
          "status:runtime:status",
        ])}
      />,
    );

    expect(html).toContain("Operations Console");
    expect(html).toContain("Service Uptime");
    expect(html).toContain("Identity");
    expect(html).toContain("Environment");
    expect(html).not.toContain("Loading Dashboard");
    expect(html).toContain(
      'data-severity="loading" data-model-id="service-uptime"',
    );
    expect(html).toContain('data-severity="loading" data-model-id="identity"');
    expect(html).toContain('data-severity="loading" data-model-id="ambient"');
    expect(html).toContain('data-severity="loading" data-model-id="runtime:status"');
  });

  test("hydrates every status cell from the Dimension Lab shell", () => {
    expect(dashboardHydrationTiles(dimensionLabDashboardFixture)).toContainEqual({
      kind: "status",
      stripId: "footer-status",
      id: "auto-refresh",
    });
  });

  test("prioritizes status, telemetry, modules, then services for hydration", () => {
    const tiles = dashboardHydrationTiles(dimensionLabDashboardFixture);
    const kinds = tiles.map((tile) => tile.kind);
    const firstServiceIndex = kinds.indexOf("service");

    expect(kinds.slice(0, 5)).toEqual([
      "status",
      "status",
      "status",
      "status",
      "status",
    ]);
    expect(kinds.lastIndexOf("telemetry")).toBeLessThan(kinds.indexOf("module"));
    expect(kinds.lastIndexOf("module")).toBeLessThan(firstServiceIndex);
    expect(
      tiles.filter((tile) => tile.kind === "telemetry").map((tile) => tile.id),
    ).toEqual(
      dimensionLabDashboardFixture.telemetry
        .filter((card) => card.datasource?.type === "external")
        .map((card) => card.id),
    );
    expect(
      tiles.filter((tile) => tile.kind === "service").map((tile) => ({
        groupId: tile.groupId,
        id: tile.id,
      })),
    ).toEqual(
      dimensionLabDashboardFixture.serviceGroups.flatMap((group) =>
        group.services
          .filter((service) => service.datasource?.type === "external")
          .map((service) => ({
            groupId: group.id,
            id: service.id,
          }))
      ),
    );
  });

  test("applies restored tile snapshots without marking them as loading", () => {
    const restored = restoreDashboardTileSnapshots(
      {
        state: "ready",
        document: dimensionLabDashboardFixture,
        schemaVersion: "dashboard.v1",
        currentRevisionId: "revision-a",
      },
      [
        {
          ageMs: 60_000,
          response: {
            state: "ready",
            tile: { kind: "telemetry", id: "infra-ram" },
            item: {
              ...dimensionLabDashboardFixture.telemetry[0],
              detail: "cached - stale 60s",
              severity: "stale",
            },
          },
        },
      ],
    );

    expect(restored.restoredItemIds).toEqual(new Set(["telemetry:infra-ram"]));
    if (restored.dashboard.state !== "ready") {
      throw new Error("Expected dashboard to be ready");
    }
    expect(restored.dashboard.document.telemetry[0]).toMatchObject({
      id: "infra-ram",
      detail: "cached - stale 60s",
      severity: "stale",
    });
  });

  test("uses structured tile match keys for delimiter-bearing ids", () => {
    expect(
      dashboardTileMatchKey({ kind: "service", groupId: "a:b", id: "c" }),
    ).not.toBe(
      dashboardTileMatchKey({ kind: "service", groupId: "a", id: "b:c" }),
    );
    expect(
      dashboardTileMatchKey({ kind: "status", stripId: "a:b", id: "c" }),
    ).not.toBe(
      dashboardTileMatchKey({ kind: "status", stripId: "a", id: "b:c" }),
    );
  });
});
