import React, { useState, useEffect, useMemo } from "react";
import { useData, useMap } from "../MapComponent";
import { Checkbox, FormControlLabel } from "@mui/material";
import WebGLVectorTileLayer from "ol/layer/WebGLVectorTile";
import VectorLayer from "ol/layer/Vector";
import VectorTileLayer from "ol/layer/VectorTile";
import { DeckLayer } from "@utils/layers";
import type { Map as OlMap } from "ol";

// 定义统一的图层项接口
interface LayerItem {
  id: string;
  name: string;
  visible: boolean;
  type: "ol" | "deck";
  layerRef: any; // OpenLayers Layer 实例或 deck.gl layer 对象
}

const LAYER_ORDER = [
  "junctions",
  "reservoirs",
  "tanks",
  "pipes",
  "pumps",
  "valves",
  "scada",
  "waterflowLayer",
  "junctionContourLayer",
];

const LayerControl: React.FC = () => {
  const map = useMap();
  const data = useData();
  const maps: OlMap[] = data?.maps?.length ? data.maps : map ? [map] : [];
  const [refreshKey, setRefreshKey] = useState(0);
  const deckLayer = data?.deckLayer;
  const deckLayers = data?.deckLayers ?? (deckLayer ? [deckLayer] : []);
  const isContourLayerAvailable = data?.isContourLayerAvailable;
  const isWaterflowLayerAvailable = data?.isWaterflowLayerAvailable;
  const showContourLayer = data?.showContourLayer;
  const showWaterflowLayer = data?.showWaterflowLayer;
  const setShowWaterflowLayer = data?.setShowWaterflowLayer;
  const setShowContourLayer = data?.setShowContourLayer;

  const layerItems = useMemo(() => {
    void refreshKey;

    if (!map || !data) return [];

    const items: LayerItem[] = [];
    const upsertLayerItem = (nextItem: LayerItem) => {
      const index = items.findIndex((item) => item.id === nextItem.id);
      if (index >= 0) {
        items[index] = nextItem;
        return;
      }
      items.push(nextItem);
    };

    map.getLayers().getArray().forEach((layer) => {
      if (
        layer instanceof WebGLVectorTileLayer ||
        layer instanceof VectorTileLayer ||
        layer instanceof VectorLayer
      ) {
        const value = layer.get("value");
        const name = layer.get("name");
        if (value) {
          upsertLayerItem({
            id: value,
            name: name || value,
            visible: layer.getVisible(),
            type: "ol",
            layerRef: layer,
          });
        }
      }
    });

    if (deckLayer && deckLayer instanceof DeckLayer) {
      deckLayer.getDeckLayers().forEach((layer: any) => {
        if (!layer?.id) return;
        if (layer.id !== "junctionContourLayer" && layer.id !== "waterflowLayer") {
          return;
        }
        if (
          (layer.id === "junctionContourLayer" && !isContourLayerAvailable) ||
          (layer.id === "waterflowLayer" && !isWaterflowLayerAvailable)
        ) {
          return;
        }

        upsertLayerItem({
          id: layer.props.id,
          name: layer.props.name,
          visible:
            deckLayer.getDeckLayerVisible(layer.id) ?? layer.props?.visible ?? true,
          type: "deck",
          layerRef: layer,
        });
      });
    }

    if (isWaterflowLayerAvailable) {
      upsertLayerItem({
        id: "waterflowLayer",
        name: "水流",
        visible:
          deckLayer?.getDeckLayerVisible("waterflowLayer") ?? showWaterflowLayer ?? false,
        type: "deck",
        layerRef: deckLayer?.getDeckLayerById("waterflowLayer") ?? null,
      });
    }

    if (isContourLayerAvailable) {
      upsertLayerItem({
        id: "junctionContourLayer",
        name: "等值线",
        visible:
          deckLayer?.getDeckLayerVisible("junctionContourLayer") ??
          showContourLayer ??
          false,
        type: "deck",
        layerRef: deckLayer?.getDeckLayerById("junctionContourLayer") ?? null,
      });
    }

    return items
      .filter((item) => LAYER_ORDER.includes(item.id))
      .sort((a, b) => LAYER_ORDER.indexOf(a.id) - LAYER_ORDER.indexOf(b.id));
  }, [
    map,
    data,
    deckLayer,
    isContourLayerAvailable,
    isWaterflowLayerAvailable,
    showContourLayer,
    showWaterflowLayer,
    refreshKey,
  ]);

  useEffect(() => {
    if (!map) return;

    const layerCollection = map.getLayers();
    const handleLayerChange = () => {
      setRefreshKey((prev) => prev + 1);
    };

    layerCollection.on("change:length", handleLayerChange);

    return () => {
      map.getLayers().un("change:length", handleLayerChange);
    };
  }, [map]);

  const handleVisibilityChange = (item: LayerItem, checked: boolean) => {
    if (item.type === "ol") {
      maps.forEach((targetMap) => {
        targetMap
          .getAllLayers()
          .filter((layer) => layer.get("value") === item.id)
          .forEach((layer) => layer.setVisible(checked));
      });
    } else if (item.type === "deck") {
      deckLayers.forEach((targetDeckLayer) => {
        targetDeckLayer.setDeckLayerVisible(item.id, checked);
      });
      if (item.id === "junctionContourLayer") {
        setShowContourLayer && setShowContourLayer(checked);
      }
      if (item.id === "waterflowLayer") {
        setShowWaterflowLayer && setShowWaterflowLayer(checked);
      }
    }
    setRefreshKey((prev) => prev + 1);
  };

  if (!data) {
    return <div>Loading...</div>;
  }

  return (
    <div className="absolute left-4 bottom-4 bg-white rounded-md drop-shadow-lg z-20 opacity-85 hover:opacity-100 transition-opacity max-w-xs">
      <div className="ml-3 grid grid-cols-3">
        {layerItems.map((item) => (
          <FormControlLabel
            key={item.id}
            control={
              <Checkbox
                checked={item.visible}
                onChange={(e) => handleVisibilityChange(item, e.target.checked)}
                size="small"
              />
            }
            label={item.name}
            sx={{
              fontSize: "0.7rem",
              "& .MuiFormControlLabel-label": { fontSize: "0.7rem" },
            }}
          />
        ))}
      </div>
    </div>
  );
};

export default LayerControl;
