"use client"

import { useState, useRef, useEffect, useCallback } from "react"
import { useMap } from "react-map-gl/mapbox"
import { BASE_BEARING, BASE_PITCH, BASE_ZOOM, MAPBOX_TILESET_ID } from "@/app/_utils/const/map"
import DistrictPopup from "../pop-up/district-popup"
import DistrictExtrusionLayer from "./district-extrusion-layer"
import ClusterLayer from "./cluster-layer"
import HeatmapLayer from "./heatmap-layer"
import DistrictLayer from "./district-layer-old"
import TimelineLayer from "./timeline-layer"

import type { ICrimes } from "@/app/_utils/types/crimes"
import { IDistrictFeature } from "@/app/_utils/types/map"
import { createFillColorExpression, processCrimeDataByDistrict } from "@/app/_utils/map"
import UnclusteredPointLayer from "./uncluster-layer"
import FlyToHandler from "../fly-to"
import { toast } from "sonner"
import { ITooltips } from "../controls/top/tooltips"
import { IUnits } from "@/app/_utils/types/units"
import UnitsLayer from "./units-layer"
import DistrictFillLineLayer from "./district-layer"

// District layer props
export interface IDistrictLayerProps {
    visible?: boolean
    onClick?: (feature: IDistrictFeature) => void
    year: string
    month: string
    filterCategory: string | "all"
    crimes: ICrimes[]
    units?: IUnits[]
    tilesetId?: string
}

interface LayersProps {
    visible?: boolean;
    crimes: ICrimes[];
    units?: IUnits[];
    year: string;
    month: string;
    filterCategory: string | "all";
    activeControl: ITooltips;
    tilesetId?: string;
    useAllData?: boolean; // New prop to indicate if we're showing all data
}

export default function Layers({
    visible = true,
    crimes,
    units,
    year,
    month,
    filterCategory,
    activeControl,
    tilesetId = MAPBOX_TILESET_ID,
    useAllData = false,
}: LayersProps) {
    const { current: map } = useMap()

    if (!map) {
        toast.error("Map not found")
        return null
    }

    const mapboxMap = map.getMap()

    const [selectedDistrict, setSelectedDistrict] = useState<IDistrictFeature | null>(null)
    const [focusedDistrictId, setFocusedDistrictId] = useState<string | null>(null)
    const selectedDistrictRef = useRef<IDistrictFeature | null>(null)

    const crimeDataByDistrict = processCrimeDataByDistrict(crimes)

    // Set up custom event handler for cluster clicks to ensure it works across components
    useEffect(() => {
        if (!mapboxMap) return;

        const handleClusterClickEvent = (e: CustomEvent) => {
            if (!e.detail) return;

            const { center, zoom } = e.detail;
            if (center && zoom) {
                mapboxMap.flyTo({
                    center: center,
                    zoom: zoom,
                    duration: 1000,
                    easing: (t) => t * (2 - t)
                });
            }
        };

        mapboxMap.getCanvas().addEventListener('cluster_click', handleClusterClickEvent as EventListener);

        return () => {
            mapboxMap.getCanvas().removeEventListener('cluster_click', handleClusterClickEvent as EventListener);
        };
    }, [mapboxMap]);

    // Handle popup close
    const handleCloseDistrictPopup = () => {
        console.log("Closing district popup")
        selectedDistrictRef.current = null
        setSelectedDistrict(null)
        setFocusedDistrictId(null)

        // Reset pitch and bearing
        if (map) {
            map.easeTo({
                zoom: BASE_ZOOM,
                pitch: BASE_PITCH,
                bearing: BASE_BEARING,
                duration: 1500,
                easing: (t) => t * (2 - t), // easeOutQuad
            })

            // Show all clusters again when closing popup
            if (map.getLayer("clusters")) {
                map.getMap().setLayoutProperty("clusters", "visibility", "visible")
            }
            if (map.getLayer("unclustered-point")) {
                map.getMap().setLayoutProperty("unclustered-point", "visibility", "visible")
            }

            // Explicitly update fill color for all districts
            if (map.getLayer("district-fill")) {
                const fillColorExpression = createFillColorExpression(null, crimeDataByDistrict)
                map.getMap().setPaintProperty("district-fill", "fill-color", fillColorExpression as any)
            }
        }
    }

    // Update selected district when year/month/filter changes
    useEffect(() => {
        if (selectedDistrictRef.current) {
            const districtId = selectedDistrictRef.current.id
            const districtCrime = crimes.find((crime) => crime.district_id === districtId)

            if (districtCrime) {
                const selectedYearNum = year ? Number.parseInt(year) : new Date().getFullYear()

                let demographics = districtCrime.districts.demographics?.find((d) => d.year === selectedYearNum)

                if (!demographics && districtCrime.districts.demographics?.length) {
                    demographics = districtCrime.districts.demographics.sort((a, b) => b.year - a.year)[0]
                }

                let geographics = districtCrime.districts.geographics?.find((g) => g.year === selectedYearNum)

                if (!geographics && districtCrime.districts.geographics?.length) {
                    const validGeographics = districtCrime.districts.geographics
                        .filter((g) => g.year !== null)
                        .sort((a, b) => (b.year || 0) - (a.year || 0))

                    geographics = validGeographics.length > 0 ? validGeographics[0] : districtCrime.districts.geographics[0]
                }

                if (!demographics || !geographics) {
                    console.error("Missing district data:", { demographics, geographics })
                    return
                }

                const crime_incidents = districtCrime.crime_incidents
                    .filter((incident) => filterCategory === "all" || incident.crime_categories.name === filterCategory)
                    .map((incident) => ({
                        id: incident.id,
                        timestamp: incident.timestamp,
                        description: incident.description,
                        status: incident.status || "",
                        category: incident.crime_categories.name,
                        type: incident.crime_categories.type || "",
                        address: incident.locations.address || "",
                        latitude: incident.locations.latitude,
                        longitude: incident.locations.longitude,
                    }))

                const updatedDistrict: IDistrictFeature = {
                    ...selectedDistrictRef.current,
                    number_of_crime: crimeDataByDistrict[districtId]?.number_of_crime || 0,
                    level: crimeDataByDistrict[districtId]?.level || selectedDistrictRef.current.level,
                    demographics: {
                        number_of_unemployed: demographics.number_of_unemployed,
                        population: demographics.population,
                        population_density: demographics.population_density,
                        year: demographics.year,
                    },
                    geographics: {
                        address: geographics.address || "",
                        land_area: geographics.land_area || 0,
                        year: geographics.year || 0,
                        latitude: geographics.latitude,
                        longitude: geographics.longitude,
                    },
                    crime_incidents,
                    selectedYear: year,
                    selectedMonth: month,
                }

                selectedDistrictRef.current = updatedDistrict

                setSelectedDistrict((prevDistrict) => {
                    if (
                        prevDistrict?.id === updatedDistrict.id &&
                        prevDistrict?.selectedYear === updatedDistrict.selectedYear &&
                        prevDistrict?.selectedMonth === updatedDistrict.selectedMonth
                    ) {
                        return prevDistrict
                    }
                    return updatedDistrict
                })
            }
        }
    }, [crimes, filterCategory, year, month, crimeDataByDistrict])

    // Make sure we have a defined handler for setFocusedDistrictId
    const handleSetFocusedDistrictId = useCallback((id: string | null) => {
        setFocusedDistrictId(id);
    }, []);

    if (!visible) return null

    // Determine which layers should be visible based on the active control
    const showDistrictLayer = activeControl === "incidents";
    const showHeatmapLayer = activeControl === "heatmap";
    const showClustersLayer = activeControl === "clusters";
    const showUnitsLayer = activeControl === "units";
    const showTimelineLayer = activeControl === "timeline";

    // District fill should only be visible for incidents and clusters
    const showDistrictFill = activeControl === "incidents" || activeControl === "clusters";

    // Show incident markers for incidents, clusters, AND units modes
    // But hide for heatmap and timeline
    const showIncidentMarkers = activeControl !== "heatmap" && activeControl !== "timeline";

    return (
        <>
            {/* Standard District Layer with incident points */}
            <DistrictFillLineLayer
                visible={true}
                map={mapboxMap}
                year={year}
                month={month}
                filterCategory={filterCategory}
                crimes={crimes}
                tilesetId={tilesetId}
                focusedDistrictId={focusedDistrictId}
                setFocusedDistrictId={handleSetFocusedDistrictId}
                crimeDataByDistrict={crimeDataByDistrict}
                showFill={showDistrictFill}
                activeControl={activeControl}
            />

            {/* Heatmap Layer */}
            <HeatmapLayer
                crimes={crimes}
                year={year}
                month={month}
                filterCategory={filterCategory}
                visible={showHeatmapLayer}
                useAllData={useAllData}
            />

            {/* Timeline Layer - make sure this is the only visible layer in timeline mode */}
            <TimelineLayer
                crimes={crimes}
                year={year}
                month={month}
                filterCategory={filterCategory}
                visible={showTimelineLayer}
                map={mapboxMap}
                useAllData={useAllData}
            />

            {/* Units Layer - always show incidents when Units is active */}
            <UnitsLayer
                crimes={crimes}
                units={units}
                filterCategory={filterCategory}
                visible={showUnitsLayer}
                map={mapboxMap}
            />

            {/* District base layer */}
            <DistrictExtrusionLayer
                visible={visible}
                map={mapboxMap}
                tilesetId={tilesetId}
                focusedDistrictId={focusedDistrictId}
                crimeDataByDistrict={crimeDataByDistrict}
            />

            {/* Cluster Layer - only enable when the clusters control is active and NOT in timeline mode */}
            <ClusterLayer
                visible={visible && activeControl === "clusters"}
                map={mapboxMap}
                crimes={crimes}
                filterCategory={filterCategory}
                focusedDistrictId={focusedDistrictId}
                clusteringEnabled={activeControl === "clusters"}
                showClusters={activeControl === "clusters"}
            />

            {/* Unclustered Points Layer - now show for both incidents and units modes */}
            <UnclusteredPointLayer
                visible={visible && showIncidentMarkers && !focusedDistrictId}
                map={mapboxMap}
                crimes={crimes}
                filterCategory={filterCategory}
                focusedDistrictId={focusedDistrictId}
            />

            <FlyToHandler map={mapboxMap} />

            {selectedDistrict && (
                <DistrictPopup
                    longitude={selectedDistrict.longitude || 0}
                    latitude={selectedDistrict.latitude || 0}
                    onClose={handleCloseDistrictPopup}
                    district={selectedDistrict}
                    year={year}
                    month={month}
                    filterCategory={filterCategory}
                />
            )}
        </>
    )
}
