"use client"

import { useEffect, useCallback } from "react"

import type mapboxgl from "mapbox-gl"
import type { GeoJSON } from "geojson"
import { IClusterLayerProps } from "@/app/_utils/types/map"
import { extractCrimeIncidents } from "@/app/_utils/map"

interface ExtendedClusterLayerProps extends IClusterLayerProps {
  clusteringEnabled?: boolean;
  showClusters?: boolean;
}

export default function ClusterLayer({
  visible = true,
  map,
  crimes = [],
  filterCategory = "all",
  focusedDistrictId,
  clusteringEnabled = false,
  showClusters = false,
}: ExtendedClusterLayerProps) {
  const handleClusterClick = useCallback(
    (e: any) => {
      if (!map) return

      e.originalEvent.stopPropagation()
      e.preventDefault()

      const features = map.queryRenderedFeatures(e.point, { layers: ["clusters"] })

      if (!features || features.length === 0) return

      const clusterId: number = features[0].properties?.cluster_id as number

      try {
        // Get the expanded zoom level for this cluster
        (map.getSource("crime-incidents") as mapboxgl.GeoJSONSource).getClusterExpansionZoom(clusterId, (err, zoom) => {
          if (err) {
            console.error("Error getting cluster expansion zoom:", err)
            return
          }

          const coordinates = (features[0].geometry as any).coordinates

          // Dispatch a custom event for the fly-to behavior
          const clusterClickEvent = new CustomEvent('cluster_click', {
            detail: {
              center: coordinates,
              zoom: zoom ?? undefined,
            },
            bubbles: true
          })

          if (map.getCanvas()) {
            map.getCanvas().dispatchEvent(clusterClickEvent)
          } else {
            document.dispatchEvent(clusterClickEvent)
          }

          // Also perform the direct flyTo operation for immediate feedback
          map.flyTo({
            center: coordinates,
            zoom: zoom ?? 12,
            duration: 1000,
            easing: (t) => t * (2 - t) // easeOutQuad
          })
        })
      } catch (error) {
        console.error("Error handling cluster click:", error)
      }
    },
    [map],
  )

  useEffect(() => {
    if (!map || !visible) return

    const onStyleLoad = () => {
      if (!map) return

      try {
        const layers = map.getStyle().layers
        let firstSymbolId: string | undefined
        for (const layer of layers) {
          if (layer.type === "symbol") {
            firstSymbolId = layer.id
            break
          }
        }

        if (!map.getSource("crime-incidents")) {
          const allIncidents = extractCrimeIncidents(crimes, filterCategory)

          map.addSource("crime-incidents", {
            type: "geojson",
            data: {
              type: "FeatureCollection",
              features: allIncidents as GeoJSON.Feature[],
            },
            cluster: clusteringEnabled,
            clusterMaxZoom: 14,
            clusterRadius: 50,
          })

          if (!map.getLayer("clusters")) {
            map.addLayer(
              {
                id: "clusters",
                type: "circle",
                source: "crime-incidents",
                filter: ["has", "point_count"],
                paint: {
                  "circle-color": ["step", ["get", "point_count"], "#51bbd6", 5, "#f1f075", 15, "#f28cb1"],
                  "circle-radius": ["step", ["get", "point_count"], 20, 5, 30, 15, 40],
                  "circle-opacity": 0.75,
                },
                layout: {
                  visibility: showClusters && !focusedDistrictId ? "visible" : "none",
                },
              },
              firstSymbolId,
            )
          }

          if (!map.getLayer("cluster-count")) {
            map.addLayer({
              id: "cluster-count",
              type: "symbol",
              source: "crime-incidents",
              filter: ["has", "point_count"],
              layout: {
                "text-field": "{point_count_abbreviated}",
                "text-font": ["DIN Offc Pro Medium", "Arial Unicode MS Bold"],
                "text-size": 12,
                visibility: showClusters && !focusedDistrictId ? "visible" : "none",
              },
              paint: {
                "text-color": "#ffffff",
              },
            })
          }

          map.on("mouseenter", "clusters", () => {
            map.getCanvas().style.cursor = "pointer"
          })

          map.on("mouseleave", "clusters", () => {
            map.getCanvas().style.cursor = ""
          })

          // Remove and re-add click handler to avoid duplicates
          map.off("click", "clusters", handleClusterClick)
          map.on("click", "clusters", handleClusterClick)
        } else {
          // Update source clustering option
          try {
            // We need to recreate the source if we're changing the clustering option
            const currentSource = map.getSource("crime-incidents") as mapboxgl.GeoJSONSource;
            const data = (currentSource as any)._data; // Get current data

            // If clustering state has changed, recreate the source
            const existingClusterState = (currentSource as any).options?.cluster;
            if (existingClusterState !== clusteringEnabled) {
              // Remove existing layers that use this source
              if (map.getLayer("clusters")) map.removeLayer("clusters");
              if (map.getLayer("cluster-count")) map.removeLayer("cluster-count");
              if (map.getLayer("unclustered-point")) map.removeLayer("unclustered-point");

              // Remove and recreate source with new clustering setting
              map.removeSource("crime-incidents");

              map.addSource("crime-incidents", {
                type: "geojson",
                data: data,
                cluster: clusteringEnabled,
                clusterMaxZoom: 14,
                clusterRadius: 50,
              });

              // Re-add the layers
              if (!map.getLayer("clusters")) {
                map.addLayer(
                  {
                    id: "clusters",
                    type: "circle",
                    source: "crime-incidents",
                    filter: ["has", "point_count"],
                    paint: {
                      "circle-color": ["step", ["get", "point_count"], "#51bbd6", 5, "#f1f075", 15, "#f28cb1"],
                      "circle-radius": ["step", ["get", "point_count"], 20, 5, 30, 15, 40],
                      "circle-opacity": 0.75,
                    },
                    layout: {
                      visibility: showClusters && !focusedDistrictId ? "visible" : "none",
                    },
                  },
                  firstSymbolId,
                );
              }

              if (!map.getLayer("cluster-count")) {
                map.addLayer({
                  id: "cluster-count",
                  type: "symbol",
                  source: "crime-incidents",
                  filter: ["has", "point_count"],
                  layout: {
                    "text-field": "{point_count_abbreviated}",
                    "text-font": ["DIN Offc Pro Medium", "Arial Unicode MS Bold"],
                    "text-size": 12,
                    visibility: showClusters && !focusedDistrictId ? "visible" : "none",
                  },
                  paint: {
                    "text-color": "#ffffff",
                  },
                });
              }
            }
          } catch (error) {
            console.error("Error updating cluster source:", error);
          }

          // Update visibility based on focused district and showClusters flag
          if (map.getLayer("clusters")) {
            map.setLayoutProperty("clusters", "visibility", showClusters && !focusedDistrictId ? "visible" : "none")
          }
          if (map.getLayer("cluster-count")) {
            map.setLayoutProperty("cluster-count", "visibility", showClusters && !focusedDistrictId ? "visible" : "none")
          }

          // Update the cluster click handler
          map.off("click", "clusters", handleClusterClick)
          map.on("click", "clusters", handleClusterClick)
        }
      } catch (error) {
        console.error("Error adding cluster layer:", error)
      }
    }

    if (map.isStyleLoaded()) {
      onStyleLoad()
    } else {
      map.once("style.load", onStyleLoad)
    }

    return () => {
      if (map) {
        map.off("click", "clusters", handleClusterClick)
      }
    }
  }, [map, visible, crimes, filterCategory, focusedDistrictId, handleClusterClick, clusteringEnabled, showClusters])

  // Update crime incidents data when filters change
  useEffect(() => {
    if (!map || !map.getSource("crime-incidents")) return

    try {
      const allIncidents = extractCrimeIncidents(crimes, filterCategory)
        ; (map.getSource("crime-incidents") as mapboxgl.GeoJSONSource).setData({
          type: "FeatureCollection",
          features: allIncidents as GeoJSON.Feature[],
        })
    } catch (error) {
      console.error("Error updating incident data:", error)
    }
  }, [map, crimes, filterCategory])

  // Update visibility when showClusters changes
  useEffect(() => {
    if (!map || !map.getLayer("clusters") || !map.getLayer("cluster-count")) return;

    try {
      map.setLayoutProperty("clusters", "visibility", showClusters && !focusedDistrictId ? "visible" : "none");
      map.setLayoutProperty("cluster-count", "visibility", showClusters && !focusedDistrictId ? "visible" : "none");
    } catch (error) {
      console.error("Error updating cluster visibility:", error);
    }
  }, [map, showClusters, focusedDistrictId]);

  return null
}
