import { createDefaultLayerStyleState } from "./styleEditorPresets";
import {
  buildDynamicStyleTemplate,
  buildStyleVariables,
  getDefaultCustomBreaks,
  hydrateStoredLayerStyleStates,
  resolveLayerStyle,
  requiresStyleApply,
  selectStoredLayerStyles,
  validateStyleConfig,
} from "./styleEditorUtils";

describe("styleEditorUtils", () => {
  it("uses N intervals, N+1 boundaries and N visual values", () => {
    const styleConfig = {
      ...createDefaultLayerStyleState("pipes").styleConfig,
      classificationMethod: "pretty_breaks" as const,
      segments: 4,
    };
    const resolved = resolveLayerStyle({
      layerType: "linestring",
      styleConfig,
      values: [0, 1, 2, 3, 4, 5],
    });

    expect(resolved?.boundaries).toHaveLength(5);
    expect(resolved?.colors).toHaveLength(4);
    expect(resolved?.dimensions).toHaveLength(4);
    expect(resolved?.labels).toHaveLength(4);
  });

  it("accepts signed custom boundaries and rejects unordered boundaries", () => {
    const base = createDefaultLayerStyleState("junctions").styleConfig;
    const valid = {
      ...base,
      segments: 3,
      customBreaks: [-5, 0, 5, 10],
      customColors: base.customColors?.slice(0, 3),
    };
    expect(validateStyleConfig(valid)).toEqual({ valid: true, errors: [] });
    expect(
      validateStyleConfig({ ...valid, customBreaks: [-5, 0, 0, 10] }).valid,
    ).toBe(false);
  });

  it("creates deterministic defaults and collapses constant data labels", () => {
    const defaults = getDefaultCustomBreaks({
      segments: 3,
      property: "pressure",
      layerId: "junctions",
      currentJunctionCalData: [{ value: 20 }, { value: 20 }],
    });
    expect(defaults).toHaveLength(4);
    expect(
      defaults.every(
        (value, index) => index === 0 || value > defaults[index - 1],
      ),
    ).toBe(true);

    const styleConfig = {
      ...createDefaultLayerStyleState("junctions").styleConfig,
      classificationMethod: "pretty_breaks" as const,
      segments: 3,
    };
    const resolved = resolveLayerStyle({
      layerType: "point",
      styleConfig,
      values: [20, 20],
    });
    expect(resolved?.isConstant).toBe(true);
    expect(resolved?.labels).toEqual(["20"]);
  });

  it("generates variable-only visual templates with shader-safe names", () => {
    const styleConfig = createDefaultLayerStyleState("pipes").styleConfig;
    const resolved = resolveLayerStyle({
      layerType: "linestring",
      styleConfig,
      values: [],
    });
    expect(resolved).not.toBeNull();
    const template = buildDynamicStyleTemplate({
      layerType: "linestring",
      property: styleConfig.property,
      classCount: styleConfig.segments,
    });
    const variables = buildStyleVariables(styleConfig, resolved!);
    const serialized = JSON.stringify({ template, variables });
    expect(serialized).toContain("tj_color_0");
    expect(serialized).not.toContain("__");
  });

  it("requires Apply only for structural changes", () => {
    const applied = createDefaultLayerStyleState("pipes").styleConfig;
    expect(requiresStyleApply(applied, { ...applied, opacity: 0.4 })).toBe(false);
    expect(
      requiresStyleApply(applied, { ...applied, minStrokeWidth: 1 }),
    ).toBe(false);
    expect(
      requiresStyleApply(applied, { ...applied, property: "flow" }),
    ).toBe(true);
    expect(
      requiresStyleApply(applied, {
        ...applied,
        customBreaks: [...(applied.customBreaks || []), 2],
      }),
    ).toBe(true);
  });

  it("hydrates workspace settings as inactive drafts", () => {
    const storedPipeStyle = {
      ...createDefaultLayerStyleState("pipes").styleConfig,
      property: "flow",
      showLabels: false,
    };
    const restored = hydrateStoredLayerStyleStates(
      {
        version: 2,
        layers: { pipes: storedPipeStyle },
      },
      2,
    );

    expect(restored.find((state) => state.layerId === "pipes")?.styleConfig).toEqual(
      storedPipeStyle,
    );
    expect(restored.every((state) => !state.isActive)).toBe(true);
    expect(selectStoredLayerStyles(restored).pipes).toEqual(storedPipeStyle);
  });
});
