import type { Map as MapLibreMap } from "maplibre-gl";
import { describe, expect, it, vi } from "vitest";
import {
  applyLayerGroupStyle,
  resetLayerGroupStyle,
  validateLayerGroupStylePatch
} from "./layer-group-style";
import { SUPPLY_LAYER_VISUALS } from "./map-layer-visuals";
import {
  supplyPipeColorExpression,
  supplyPipeDashExpression
} from "./supply-style-expressions";

describe("layer group style validation", () => {
  it("accepts geometry-aware style patches", () => {
    expect(validateLayerGroupStylePatch("pipes", { color: "#0F766E", opacity: 0.5, widthMultiplier: 3, dash: "solid" })).toBe(true);
    expect(validateLayerGroupStylePatch("valves", { fillColor: "#8B5CF6", strokeColor: "#FFFFFF", radiusMultiplier: 0.5 })).toBe(true);
    expect(validateLayerGroupStylePatch("junctions", { fillColor: "#0369A1", strokeColor: "#FFFFFF", radiusMultiplier: 0.5 })).toBe(true);
    expect(validateLayerGroupStylePatch("reservoirs", { fillColor: "#0284C7", strokeColor: "#FFFFFF", radiusMultiplier: 0.5 })).toBe(true);
  });

  it("rejects cross-geometry fields and out-of-range values", () => {
    expect(validateLayerGroupStylePatch("pipes", { radiusMultiplier: 1 })).toBe(false);
    expect(validateLayerGroupStylePatch("junctions", { widthMultiplier: 1 })).toBe(false);
    expect(validateLayerGroupStylePatch("scada", { iconMultiplier: 2.1 })).toBe(false);
    expect(validateLayerGroupStylePatch("pipes", { color: "red" })).toBe(false);
    expect(validateLayerGroupStylePatch("unknown", {})).toBe(false);
  });

  it("restores the data-driven pipe color, dash, and widths", () => {
    const map = createStyleMap();

    resetLayerGroupStyle(map, "pipes");

    expect(map.setPaintProperty).toHaveBeenCalledWith("pipes-flow", "line-color", supplyPipeColorExpression);
    expect(map.setPaintProperty).toHaveBeenCalledWith("pipes-flow", "line-dasharray", supplyPipeDashExpression);
    expect(map.setPaintProperty).toHaveBeenCalledWith("pipes-casing", "line-width", SUPPLY_LAYER_VISUALS.pipes.casingWidth);
    expect(map.setPaintProperty).toHaveBeenCalledWith("pipes-flow", "line-width", SUPPLY_LAYER_VISUALS.pipes.width);
  });

  it("applies width multipliers from defaults instead of compounding", () => {
    const map = createStyleMap();

    applyLayerGroupStyle(map, "pipes", { widthMultiplier: 2 });
    applyLayerGroupStyle(map, "pipes", { widthMultiplier: 2 });

    const calls = map.setPaintProperty.mock.calls.filter(
      ([layerId, property]) => layerId === "pipes-flow" && property === "line-width"
    );
    expect(calls).toHaveLength(2);
    expect(calls[0]?.[2]).toEqual(["*", SUPPLY_LAYER_VISUALS.pipes.width, 2]);
    expect(calls[1]?.[2]).toEqual(calls[0]?.[2]);
  });

  it("keeps the reservoir core transparent when restoring its reference icon", () => {
    const map = createStyleMap();

    resetLayerGroupStyle(map, "reservoirs");

    expect(map.setPaintProperty).toHaveBeenCalledWith("reservoirs", "circle-opacity", 0);
  });
});

function createStyleMap() {
  return {
    getLayer: vi.fn(() => ({})),
    setPaintProperty: vi.fn()
  } as unknown as Pick<MapLibreMap, "getLayer" | "setPaintProperty"> & {
    setPaintProperty: ReturnType<typeof vi.fn>;
  } as MapLibreMap & {
    setPaintProperty: ReturnType<typeof vi.fn>;
  };
}
