"use client"

import { useEffect, useMemo, useRef, useState, useCallback } from "react"
import { Layer, Source } from "react-map-gl/mapbox"
import type { ICrimes } from "@/app/_utils/types/crimes"
import type { IUnits } from "@/app/_utils/types/units"
import type mapboxgl from "mapbox-gl"

import { generateCategoryColorMap } from "@/app/_utils/colors"
import UnitPopup from "../pop-up/unit-popup"
import IncidentPopup from "../pop-up/incident-popup"

interface UnitsLayerProps {
    crimes: ICrimes[]
    units?: IUnits[]
    filterCategory: string | "all"
    visible?: boolean
    map?: mapboxgl.Map | null
}

interface IDistrictIncidents {
    incident_id: string
    category_name: string
    incident_description: string
    distance_meters: number
    timestamp: Date
}

export default function UnitsLayer({ crimes, units = [], filterCategory, visible = false, map }: UnitsLayerProps) {
    const [loadedUnits, setLoadedUnits] = useState<IUnits[]>([])
    const loadedUnitsRef = useRef<IUnits[]>([])

    // For popups
    const [selectedUnit, setSelectedUnit] = useState<IUnits | null>(null)
    const [selectedIncident, setSelectedIncident] = useState<any | null>(null)
    const [selectedEntityId, setSelectedEntityId] = useState<string | undefined>()
    const [isUnitSelected, setIsUnitSelected] = useState<boolean>(false)
    const [selectedDistrictId, setSelectedDistrictId] = useState<string | undefined>()
    const [unitIncident, setUnitIncident] = useState<IDistrictIncidents[]>([])
    const [isLoading, setIsLoading] = useState<boolean>(false)

    // Use either provided units or loaded units
    const unitsData = useMemo(() => {
        return units.length > 0 ? units : loadedUnits || []
    }, [units, loadedUnits])

    // Extract all unique crime categories for color generation
    const uniqueCategories = useMemo(() => {
        const categories = new Set<string>()
        crimes.forEach((crime) => {
            crime.crime_incidents.forEach((incident) => {
                if (incident.crime_categories?.name) {
                    categories.add(incident.crime_categories.name)
                }
            })
        })
        return Array.from(categories)
    }, [crimes])

    // Generate color map for all categories
    const categoryColorMap = useMemo(() => {
        return generateCategoryColorMap(uniqueCategories)
    }, [uniqueCategories])

    // Process units data to GeoJSON format
    const unitsGeoJSON = useMemo(() => {
        console.log("Units data being processed:", unitsData) // Debug log

        return {
            type: "FeatureCollection" as const,
            features: unitsData.map((unit) => {
                // Debug log for individual units
                console.log("Processing unit:", unit.code_unit, unit.name, {
                    longitude: unit.longitude,
                    latitude: unit.latitude,
                    district: unit.district_name,
                })

                return {
                    type: "Feature" as const,
                    properties: {
                        id: unit.code_unit,
                        name: unit.name,
                        address: unit.address,
                        phone: unit.phone,
                        type: unit.type,
                        district: unit.district_name || "",
                        district_id: unit.district_id,
                    },
                    geometry: {
                        type: "Point" as const,
                        coordinates: [
                            Number.parseFloat(String(unit.longitude)) || 0,
                            Number.parseFloat(String(unit.latitude)) || 0,
                        ],
                    },
                }
            }),
        }
    }, [unitsData])

    // Process incident data to GeoJSON format
    const incidentsGeoJSON = useMemo(() => {
        const features: any[] = []

        crimes.forEach((crime) => {
            crime.crime_incidents.forEach((incident) => {
                // Skip incidents without location data or filtered by category
                if (
                    !incident.locations?.latitude ||
                    !incident.locations?.longitude ||
                    (filterCategory !== "all" && incident.crime_categories.name !== filterCategory)
                )
                    return

                features.push({
                    type: "Feature" as const,
                    properties: {
                        id: incident.id,
                        description: incident.description || "No description",
                        category: incident.crime_categories.name,
                        date: incident.timestamp,
                        district: crime.districts.name,
                        district_id: crime.district_id,
                        categoryColor: categoryColorMap[incident.crime_categories.name] || "#22c55e",
                        distance_to_unit: incident.locations.distance_to_unit || "Unknown",
                    },
                    geometry: {
                        type: "Point" as const,
                        coordinates: [incident.locations.longitude, incident.locations.latitude],
                    },
                })
            })
        })

        return {
            type: "FeatureCollection" as const,
            features,
        }
    }, [crimes, filterCategory, categoryColorMap])

    // Create lines between units and incidents within their districts
    const connectionLinesGeoJSON = useMemo(() => {
        if (!unitsData.length || !crimes.length)
            return {
                type: "FeatureCollection" as const,
                features: [],
            }

        // Map district IDs to their units
        const districtUnitsMap = new Map<string, IUnits[]>()

        unitsData.forEach((unit) => {
            if (!unit.district_id || !unit.longitude || !unit.latitude) return

            if (!districtUnitsMap.has(unit.district_id)) {
                districtUnitsMap.set(unit.district_id, [])
            }
            districtUnitsMap.get(unit.district_id)!.push(unit)
        })

        // Create lines from units to incidents in their district
        const lineFeatures: any[] = []

        crimes.forEach((crime) => {
            // Get all units in this district
            const districtUnits = districtUnitsMap.get(crime.district_id) || []
            if (!districtUnits.length) return

            // For each incident in this district
            crime.crime_incidents.forEach((incident) => {
                // Skip incidents without location data or filtered by category
                if (
                    !incident.locations?.latitude ||
                    !incident.locations?.longitude ||
                    (filterCategory !== "all" && incident.crime_categories.name !== filterCategory)
                )
                    return

                // Create a line from each unit in this district to this incident
                districtUnits.forEach((unit) => {
                    if (!unit.longitude || !unit.latitude) return

                    lineFeatures.push({
                        type: "Feature" as const,
                        properties: {
                            unit_id: unit.code_unit,
                            unit_name: unit.name,
                            incident_id: incident.id,
                            district_id: crime.district_id,
                            district_name: crime.districts.name,
                            category: incident.crime_categories.name,
                            lineColor: categoryColorMap[incident.crime_categories.name] || "#22c55e",
                        },
                        geometry: {
                            type: "LineString" as const,
                            coordinates: [
                                [unit.longitude, unit.latitude],
                                [incident.locations.longitude, incident.locations.latitude],
                            ],
                        },
                    })
                })
            })
        })

        return {
            type: "FeatureCollection" as const,
            features: lineFeatures,
        }
    }, [unitsData, crimes, filterCategory, categoryColorMap])

    // Handle unit click
    const handleUnitClick = useCallback(
        (
            map: mapboxgl.Map,
            unitsData: IUnits[],
            setSelectedUnit: (unit: IUnits | null) => void,
            setSelectedIncident: (incident: any | null) => void,
            setSelectedEntityId: (id: string | undefined) => void,
            setIsUnitSelected: (isSelected: boolean) => void,
            setSelectedDistrictId: (id: string | undefined) => void,
        ) =>
            (e: mapboxgl.MapMouseEvent & { features?: mapboxgl.MapboxGeoJSONFeature[] }) => {
                if (!e.features || e.features.length === 0) return

                // Stop event propagation to prevent district layer from handling this click
                e.originalEvent.stopPropagation()
                e.preventDefault()

                const feature = e.features[0]
                const properties = feature.properties

                if (!properties) return

                // Find the unit in our data
                const unit = unitsData.find((u) => u.code_unit === properties.id)
                if (!unit) {
                    console.log("Unit not found in data:", properties.id)
                    return
                }

                setIsLoading(true)

                // Find all incidents in the same district as the unit
                const districtIncidents: IDistrictIncidents[] = []
                crimes.forEach((crime) => {
                    // Check if this crime is in the same district as the unit

                    if (selectedUnit?.code_unit === unit.code_unit) {
                        crime.crime_incidents.forEach((incident) => {
                            if (incident.locations && typeof incident.locations.distance_to_unit !== "undefined") {
                                districtIncidents.push({
                                    incident_id: incident.id,
                                    category_name: incident.crime_categories.name,
                                    incident_description: incident.description || "No description",
                                    distance_meters: incident.locations.distance_to_unit!,
                                    timestamp: incident.timestamp,
                                })
                            }
                        })
                    }
                })

                // Sort by distance (closest first)
                districtIncidents.sort((a, b) => a.distance_meters - b.distance_meters)

                console.log("Sorted district incidents:", districtIncidents)

                // Update the state with the distance results
                setUnitIncident(districtIncidents)
                setIsLoading(false)

                // Fly to the unit location
                map.flyTo({
                    center: [unit.longitude || 0, unit.latitude || 0],
                    zoom: 14,
                    pitch: 45,
                    bearing: 0,
                    duration: 2000,
                })

                // Set the selected unit and query parameters
                setSelectedUnit(unit)
                setSelectedIncident(null) // Clear any selected incident
                setSelectedEntityId(properties.id)
                setIsUnitSelected(true)
                setSelectedDistrictId(properties.district_id)

                // Highlight the connected lines for this unit
                if (map.getLayer("units-connection-lines")) {
                    map.setFilter("units-connection-lines", ["==", ["get", "unit_id"], properties.id])
                }

                // Dispatch a custom event for other components to react to
                const customEvent = new CustomEvent("unit_click", {
                    detail: {
                        unitId: properties.id,
                        districtId: properties.district_id,
                        name: properties.name,
                        longitude: feature.geometry.type === "Point" ? (feature.geometry as any).coordinates[0] : 0,
                        latitude: feature.geometry.type === "Point" ? (feature.geometry as any).coordinates[1] : 0,
                    },
                    bubbles: true,
                })

                map.getCanvas().dispatchEvent(customEvent)
                document.dispatchEvent(customEvent)
            },
        [crimes], // Add crimes as a dependency
    )

    // Handle incident click
    const handleIncidentClick = useCallback(
        (
            map: mapboxgl.Map,
            setSelectedIncident: (incident: any | null) => void,
            setSelectedUnit: (unit: IUnits | null) => void,
            setSelectedEntityId: (id: string | undefined) => void,
            setIsUnitSelected: (isSelected: boolean) => void,
            setSelectedDistrictId: (id: string | undefined) => void,
        ) =>
            (e: mapboxgl.MapMouseEvent & { features?: mapboxgl.MapboxGeoJSONFeature[] }) => {
                if (!e.features || e.features.length === 0) return

                // Stop event propagation
                e.originalEvent.stopPropagation()
                e.preventDefault()

                const feature = e.features[0]
                const properties = feature.properties

                if (!properties) return

                // Get coordinates
                const longitude = feature.geometry.type === "Point" ? (feature.geometry as any).coordinates[0] : 0
                const latitude = feature.geometry.type === "Point" ? (feature.geometry as any).coordinates[1] : 0

                // Fly to the incident location
                map.flyTo({
                    center: [longitude, latitude],
                    zoom: 15,
                    pitch: 45,
                    bearing: 0,
                    duration: 2000,
                })

                // Create incident object from properties
                const incident = {
                    id: properties.id,
                    category: properties.category,
                    description: properties.description,
                    date: properties.date,
                    district: properties.district,
                    district_id: properties.district_id,
                    distance_to_unit: properties.distance_to_unit,
                    longitude,
                    latitude,
                }

                // Set the selected incident and query parameters
                setSelectedIncident(incident)
                setSelectedUnit(null) // Clear any selected unit
                setSelectedEntityId(properties.id)
                setIsUnitSelected(false)
                setSelectedDistrictId(properties.district_id)

                // Highlight the connected lines for this incident
                if (map.getLayer("units-connection-lines")) {
                    map.setFilter("units-connection-lines", ["==", ["get", "incident_id"], properties.id])
                }

                // Dispatch a custom event for other components to react to
                const customEvent = new CustomEvent("incident_click", {
                    detail: {
                        id: properties.id,
                        district: properties.district,
                        category: properties.category,
                        description: properties.description,
                        longitude,
                        latitude,
                    },
                    bubbles: true,
                })

                map.getCanvas().dispatchEvent(customEvent)
                document.dispatchEvent(customEvent)
            },
        [],
    )

    const unitClickHandler = useMemo(
        () =>
            handleUnitClick(
                map as mapboxgl.Map,
                unitsData,
                setSelectedUnit,
                setSelectedIncident,
                setSelectedEntityId,
                setIsUnitSelected,
                setSelectedDistrictId,
            ),
        [
            map,
            unitsData,
            setSelectedUnit,
            setSelectedIncident,
            setSelectedEntityId,
            setIsUnitSelected,
            setSelectedDistrictId,
        ],
    )

    const incidentClickHandler = useMemo(
        () =>
            handleIncidentClick(
                map as mapboxgl.Map,
                setSelectedIncident,
                setSelectedUnit,
                setSelectedEntityId,
                setIsUnitSelected,
                setSelectedDistrictId,
            ),
        [map, setSelectedIncident, setSelectedUnit, setSelectedEntityId, setIsUnitSelected, setSelectedDistrictId],
    )

    // Set up event handlers
    useEffect(() => {
        if (!map || !visible) return

        // Debug log to confirm map layers
        console.log(
            "Available map layers:",
            map.getStyle().layers?.map((l) => l.id),
        )

        // Define event handlers that can be referenced for both adding and removing
        const handleMouseEnter = () => {
            map.getCanvas().style.cursor = "pointer"
        }

        const handleMouseLeave = () => {
            map.getCanvas().style.cursor = ""
        }

        // Add click event for units-points layer
        if (map.getLayer("units-points")) {
            map.off("click", "units-points", unitClickHandler)
            map.on("click", "units-points", unitClickHandler)

            // Change cursor on hover
            map.on("mouseenter", "units-points", handleMouseEnter)
            map.on("mouseleave", "units-points", handleMouseLeave)
        }

        // Add click event for incidents-points layer
        if (map.getLayer("incidents-points")) {
            map.off("click", "incidents-points", incidentClickHandler)
            map.on("click", "incidents-points", incidentClickHandler)

            // Change cursor on hover
            map.on("mouseenter", "incidents-points", handleMouseEnter)
            map.on("mouseleave", "incidents-points", handleMouseLeave)
        }

        return () => {
            if (map) {
                if (map.getLayer("units-points")) {
                    map.off("click", "units-points", unitClickHandler)
                    map.off("mouseenter", "units-points", handleMouseEnter)
                    map.off("mouseleave", "units-points", handleMouseLeave)
                }

                if (map.getLayer("incidents-points")) {
                    map.off("click", "incidents-points", incidentClickHandler)
                    map.off("mouseenter", "incidents-points", handleMouseEnter)
                    map.off("mouseleave", "incidents-points", handleMouseLeave)
                }
            }
        }
    }, [map, visible, unitClickHandler, incidentClickHandler])

    // Reset map filters when popup is closed
    const handleClosePopup = useCallback(() => {
        setSelectedUnit(null)
        setSelectedIncident(null)
        setSelectedEntityId(undefined)
        setSelectedDistrictId(undefined)
        setUnitIncident([])
        setIsLoading(false)

        if (map && map.getLayer("units-connection-lines")) {
            map.setFilter("units-connection-lines", ["has", "unit_id"])
        }
    }, [map])

    // Clean up on unmount or when visibility changes
    useEffect(() => {
        if (!visible) {
            handleClosePopup()
        }
    }, [visible, handleClosePopup])

    if (!visible) return null

    return (
        <>
            {/* Units Points */}
            <Source id="units-source" type="geojson" data={unitsGeoJSON}>
                <Layer
                    id="units-points"
                    type="circle"
                    paint={{
                        "circle-radius": 8,
                        "circle-color": "#1e40af", // Deep blue for police units
                        "circle-stroke-width": 2,
                        "circle-stroke-color": "#ffffff",
                        "circle-opacity": 0.8,
                    }}
                />

                {/* Units Symbols */}
                <Layer
                    id="units-symbols"
                    type="symbol"
                    layout={{
                        "text-field": ["get", "name"],
                        "text-font": ["DIN Offc Pro Medium", "Arial Unicode MS Bold"],
                        "text-size": 12,
                        "text-offset": [0, -2],
                        "text-anchor": "bottom",
                        "text-allow-overlap": false,
                        "text-ignore-placement": false,
                    }}
                    paint={{
                        "text-color": "#ffffff",
                        "text-halo-color": "#000000",
                        "text-halo-width": 1,
                    }}
                />
            </Source>

            {/* Incidents Points */}
            <Source id="incidents-source" type="geojson" data={incidentsGeoJSON}>
                <Layer
                    id="incidents-points"
                    type="circle"
                    paint={{
                        "circle-radius": 6,
                        // Use the pre-computed color stored in the properties
                        "circle-color": ["get", "categoryColor"],
                        "circle-stroke-width": 1,
                        "circle-stroke-color": "#ffffff",
                        "circle-opacity": 0.8,
                    }}
                />
            </Source>

            {/* Connection Lines */}
            <Source id="units-lines-source" type="geojson" data={connectionLinesGeoJSON}>
                <Layer
                    id="units-connection-lines"
                    type="line"
                    paint={{
                        // Use the pre-computed color stored in the properties
                        "line-color": ["get", "lineColor"],
                        "line-width": 3,
                        "line-opacity": 0.9,
                        "line-blur": 0.5,
                        "line-dasharray": [3, 1],
                    }}
                />
            </Source>

            {/* Custom Unit Popup */}
            {selectedUnit && (
                <UnitPopup
                    longitude={selectedUnit.longitude || 0}
                    latitude={selectedUnit.latitude || 0}
                    onClose={handleClosePopup}
                    unit={{
                        id: selectedUnit.code_unit,
                        name: selectedUnit.name,
                        type: selectedUnit.type,
                        address: selectedUnit.address || "No address",
                        phone: selectedUnit.phone || "No phone",
                        district: selectedUnit.district_name || "No district",
                        district_id: selectedUnit.district_id,
                    }}
                    incidents={unitIncident}
                    isLoadingIncidents={isLoading}
                />
            )}

            {/* Custom Incident Popup */}
            {selectedIncident && (
                <IncidentPopup
                    longitude={selectedIncident.longitude}
                    latitude={selectedIncident.latitude}
                    onClose={handleClosePopup}
                    incident={selectedIncident}
                />
            )}
        </>
    )
}
