import type { FeatureCollection } from "geojson";
import type { Map as MapLibreMap } from "maplibre-gl";
import { describe, expect, it, vi } from "vitest";
import { WorkbenchMapController } from "./workbench-map-controller";

describe("WorkbenchMapController", () => {
  it("locates points with zoom 18 and keeps selected state untouched", async () => {
    const map = createMap();
    const controller = createController(map, pointCollection);
    await controller.locateAndHighlight({ sourceId: "junctions", featureId: "J-1" });
    expect(map.easeTo).toHaveBeenCalledWith(expect.objectContaining({ center: [120.7, 28], zoom: 18 }));
    expect(map.setFeatureState).toHaveBeenCalledWith(expect.objectContaining({ source: "junctions", id: "J-1" }), { highlighted: true });
    controller.clearHighlight();
    expect(map.removeFeatureState).toHaveBeenCalledWith(expect.anything(), "highlighted");
    expect(map.removeFeatureState).not.toHaveBeenCalledWith(expect.anything(), "selected");
  });

  it("fits line bounds and uses responsive workbench padding", async () => {
    const map = createMap();
    const padding = { top: 50, right: 420, bottom: 50, left: 320 };
    const controller = createController(map, lineCollection, padding);
    await controller.locateAndHighlight({ sourceId: "pipes", featureId: "P-1" });
    expect(map.fitBounds).toHaveBeenCalledWith([[120, 28], [121, 29]], expect.objectContaining({ padding, maxZoom: 18 }));
  });

  it("does not clear the last valid highlight when a target is missing", async () => {
    const map = createMap();
    let collection = pointCollection;
    const controller = new WorkbenchMapController({
      getMap: () => map as unknown as MapLibreMap,
      isReady: () => true,
      getPadding: () => ({ top: 0, right: 0, bottom: 0, left: 0 }),
      fetchFeatures: async () => collection
    });
    await controller.highlight({ sourceId: "junctions", featureId: "J-1" });
    collection = { type: "FeatureCollection", features: [] };
    await controller.highlight({ sourceId: "junctions", featureId: "missing" });
    expect(controller.getSnapshot().target).toEqual({ sourceId: "junctions", featureId: "J-1" });
    expect(controller.getSnapshot().errorCode).toBe("FEATURE_NOT_FOUND");
    expect(map.removeFeatureState).not.toHaveBeenCalled();
  });

  it("reports SCADA analysis as unavailable for the water-network data source", async () => {
    const map = createMap();
    const controller = createController(map, pointCollection);
    await expect(controller.renderScadaAnalysis([{ sensor_id: "MP01", level: "high" }])).rejects.toThrow("SCADA_FEATURES_NOT_FOUND");
    expect(controller.getSnapshot().errorCode).toBe("SCADA_FEATURES_NOT_FOUND");
  });
});

const pointCollection: FeatureCollection = { type: "FeatureCollection", features: [{ type: "Feature", geometry: { type: "Point", coordinates: [120.7, 28] }, properties: { id: "J-1" } }] };
const lineCollection: FeatureCollection = { type: "FeatureCollection", features: [{ type: "Feature", geometry: { type: "LineString", coordinates: [[120, 28], [121, 29]] }, properties: { id: "P-1" } }] };

function createMap() {
  return {
    easeTo: vi.fn(), fitBounds: vi.fn(), setFeatureState: vi.fn(), removeFeatureState: vi.fn(),
    getSource: vi.fn(), getLayer: vi.fn(), addLayer: vi.fn(), setPaintProperty: vi.fn(), setLayoutProperty: vi.fn(), removeControl: vi.fn()
  };
}

function createController(map: ReturnType<typeof createMap>, collection: FeatureCollection, padding = { top: 48, right: 48, bottom: 48, left: 48 }) {
  return new WorkbenchMapController({
    getMap: () => map as unknown as MapLibreMap,
    isReady: () => true,
    getPadding: () => padding,
    fetchFeatures: vi.fn(async () => collection)
  });
}
