/**
 * Parity gate for the shared graph-style lib. Asserts the small set of
 * load-bearing fixtures every UI and plugin caller relies on. Richer
 * coverage lives in the UI's existing tests under
 * platform/ui/app/lib/__tests__/graph-labels.test.ts and
 * platform/ui/app/graph/__tests__/*; those tests now exercise the
 * re-exported symbols and pass unchanged if extraction was faithful.
 */

import { describe, it, expect } from "vitest";
import {
  GRAPH_LABEL_COLOURS,
  FALLBACK_LABEL_COLOUR,
  pickDisplayLabel,
  resolveNodeColour,
  pickShortLabel,
  pickDisplayName,
} from "../index.js";

describe("palette invariants", () => {
  it("registers every label family with a hex colour", () => {
    for (const [label, colour] of Object.entries(GRAPH_LABEL_COLOURS)) {
      expect(colour, `${label} colour`).toMatch(/^#[0-9A-Fa-f]{6}$/);
    }
  });

  it("FALLBACK_LABEL_COLOUR is a hex", () => {
    expect(FALLBACK_LABEL_COLOUR).toMatch(/^#[0-9A-Fa-f]{6}$/);
  });

  it("UserMessage and Preference deliberately share a hue (Person-family cue)", () => {
    expect(GRAPH_LABEL_COLOURS.UserMessage).toBe(GRAPH_LABEL_COLOURS.Preference);
  });
});

describe("pickDisplayLabel", () => {
  it("returns the first registered sublabel", () => {
    expect(pickDisplayLabel(["Conversation", "AdminConversation"])).toBe(
      "AdminConversation",
    );
  });

  it("falls back to labels[0] when no sublabel is registered", () => {
    expect(pickDisplayLabel(["Person", "UnregisteredSublabel"])).toBe("Person");
  });

  it("returns null on empty labels", () => {
    expect(pickDisplayLabel([])).toBeNull();
  });
});

describe("resolveNodeColour", () => {
  it("counts drift candidates", () => {
    const r = resolveNodeColour(["Conversation", "PublicConversation", "AssistantMessage"]);
    expect(r.driftCandidates).toBe(2);
    expect(r.colour).toBe(GRAPH_LABEL_COLOURS.PublicConversation);
  });
});

describe("pickShortLabel", () => {
  it("Person composes from given+family", () => {
    expect(
      pickShortLabel({
        id: "x",
        labels: ["Person"],
        properties: { givenName: "Dan", familyName: "Brett" },
      }),
    ).toBe("Dan Brett");
  });

  it("Message renders role + HH:mm:ss", () => {
    expect(
      pickShortLabel({
        id: "x",
        labels: ["Message"],
        properties: { role: "user", createdAt: "2026-05-25T14:33:42Z" },
      }),
    ).toBe("user 14:33:42");
  });

  it("Conversation falls back to Conv <id8>", () => {
    expect(
      pickShortLabel({
        id: "x",
        labels: ["Conversation"],
        properties: { sessionId: "abcdef0123456789" },
      }),
    ).toBe("Conv abcdef01");
  });

  it("truncates over-cap labels to 24 chars + ellipsis", () => {
    const longName = "This is a very long string that exceeds twenty-four chars";
    const out = pickShortLabel({
      id: "x",
      labels: ["LocalBusiness"],
      properties: { name: longName },
    });
    expect(out.length).toBeLessThanOrEqual(25); // 24 + '…'
    expect(out.endsWith("…")).toBe(true);
  });
});

describe("pickDisplayName", () => {
  it("untruncated counterpart to pickShortLabel", () => {
    const longName = "This is a very long string that exceeds twenty-four chars";
    expect(
      pickDisplayName({
        id: "x",
        labels: ["LocalBusiness"],
        properties: { name: longName },
      }),
    ).toBe(longName);
  });
});
