"use client"

import { useEffect, useState, useRef, useCallback } from "react"
import { useMap } from "react-map-gl/mapbox"
import { CRIME_RATE_COLORS, MAPBOX_TILESET_ID } from "@/app/_utils/const/map"

import { $Enums } from "@prisma/client"
import DistrictPopup from "../pop-up/district-popup"

// Types for district properties
export interface DistrictFeature {
    id: string
    name: string
    properties: Record<string, any>
    longitude: number
    latitude: number
    number_of_crime: number
    level: $Enums.crime_rates
    demographics: {
        number_of_unemployed: number
        population: number
        population_density: number
        year: number
    }
    geographics: {
        address: string
        land_area: number
        year: number
        latitude: number
        longitude: number
    }
    crime_incidents: Array<{
        id: string
        timestamp: Date
        description: string
        status: string
        category: string
        type: string
        address: string
        latitude: number
        longitude: number
    }>
    selectedYear?: string
    selectedMonth?: string
}

// Updated interface to match the structure returned by getCrimeByYearAndMonth
export interface ICrimeData {
    id: string
    district_id: string
    districts: {
        name: string
        geographics: {
            address: string
            land_area: number
            year: number
            latitude: number
            longitude: number
        }
        demographics: {
            number_of_unemployed: number
            population: number
            population_density: number
            year: number
        }
    }
    number_of_crime: number
    level: $Enums.crime_rates
    score: number
    month: number
    year: number
    crime_incidents: Array<{
        id: string
        timestamp: Date
        description: string
        status: string
        crime_categories: {
            name: string
            type: string
        }
        locations: {
            address: string
            latitude: number
            longitude: number
        }
    }>
}

// District layer props
export interface DistrictLayerProps {
    visible?: boolean
    onClick?: (feature: DistrictFeature) => void
    year?: string
    month?: string
    filterCategory?: string | "all"
    crimes?: ICrimeData[]
    tilesetId?: string
}

export default function DistrictLayer({
    visible = true,
    onClick,
    year,
    month,
    filterCategory = "all",
    crimes = [],
    tilesetId = MAPBOX_TILESET_ID,
}: DistrictLayerProps) {
    const { current: map } = useMap()

    const [hoverInfo, setHoverInfo] = useState<{
        x: number
        y: number
        feature: any
    } | null>(null)

    // Menggunakan useRef untuk menyimpan informasi distrik yang dipilih
    // sehingga nilainya tidak hilang saat komponen di-render ulang
    const selectedDistrictRef = useRef<DistrictFeature | null>(null)
    const [selectedDistrict, setSelectedDistrict] = useState<DistrictFeature | null>(null)

    // Use a ref to track whether layers have been added
    const layersAdded = useRef(false)

    // Process crime data to map to districts by district_id (kode_kec)
    const crimeDataByDistrict = crimes.reduce(
        (acc, crime) => {
            // Use district_id (which corresponds to kode_kec in the tileset) as the key
            const districtId = crime.district_id

            acc[districtId] = {
                number_of_crime: crime.number_of_crime,
                level: crime.level,
            }
            return acc
        },
        {} as Record<string, { number_of_crime?: number; level?: $Enums.crime_rates }>,
    )

    // Handle click on district
    const handleClick = (e: any) => {
        if (!map || !e.features || e.features.length === 0) return

        const feature = e.features[0]
        const districtId = feature.properties.kode_kec // Using kode_kec as the unique identifier
        const crimeData = crimeDataByDistrict[districtId] || {}

        // Get ALL crime_incidents for this district by aggregating from all matching crime records
        let crime_incidents: Array<{
            id: string
            timestamp: Date
            description: string
            status: string
            category: string
            type: string
            address: string
            latitude: number
            longitude: number
        }> = []

        // Find all crime data records for this district (across all months)
        const districtCrimes = crimes.filter(crime => crime.district_id === districtId)

        console.log(`Found ${districtCrimes.length} crime data records for district ID ${districtId}`)

        // Collect all crime incidents from all month records for this district
        districtCrimes.forEach(crimeRecord => {
            if (crimeRecord && crimeRecord.crime_incidents) {
                const incidents = crimeRecord.crime_incidents.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 || 0,
                    longitude: incident.locations?.longitude || 0
                }))

                crime_incidents = [...crime_incidents, ...incidents]
            }
        })

        console.log(`Aggregated ${crime_incidents.length} total crime incidents for district`)

        // Get demographics and geographics from the first record (should be the same across all records)
        const firstDistrictCrime = districtCrimes.length > 0 ? districtCrimes[0] : null
        const demographics = firstDistrictCrime?.districts.demographics
        const geographics = firstDistrictCrime?.districts.geographics

        // Make sure we have valid coordinates from the click event
        const clickLng = e.lngLat ? e.lngLat.lng : null
        const clickLat = e.lngLat ? e.lngLat.lat : null

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

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

        // Create a complete district object ensuring all required properties are present
        const district: DistrictFeature = {
            id: districtId,
            name: feature.properties.nama || feature.properties.kecamatan || "Unknown District",
            properties: feature.properties,
            longitude: geographics.longitude || clickLng || 0,
            latitude: geographics.latitude || clickLat || 0,
            // Use the total crime count across all months
            number_of_crime: crimeData.number_of_crime || 0,
            // Use the level from the currently selected month/year (or default to low)
            level: crimeData.level || $Enums.crime_rates.low,
            demographics,
            geographics,
            // Include all aggregated crime incidents
            crime_incidents: crime_incidents || [],
            selectedYear: year,
            selectedMonth: month
    }

        if (!district.longitude || !district.latitude) {
            console.error("Invalid district coordinates:", district);
            return;
        }

        console.log("Selected district:", district);
        console.log(`Selected district has ${district.crime_incidents?.length || 0} crime_incidents out of ${district.number_of_crime} total crimes`);

        // Set the reference BEFORE handling the onClick or setState
        selectedDistrictRef.current = district;

        if (onClick) {
            onClick(district);
    } else {
            setSelectedDistrict(district);
    }
    }

    // Pastikan event handler klik selalu diperbarui
    // dan re-attach setiap kali ada perubahan data
    useEffect(() => {
        if (!map || !visible || !map.getMap().getLayer("district-fill")) return;

        // Re-attach click handler
        map.off("click", "district-fill", handleClick);
        map.on("click", "district-fill", handleClick);

        console.log("Re-attached click handler, current district:", selectedDistrict?.name || "None");

        return () => {
            if (map) {
                map.off("click", "district-fill", handleClick);
            }
        };
    }, [map, visible, crimes, filterCategory, year, month]);

    // Add district layer to the map when it's loaded
    useEffect(() => {
        if (!map || !visible) return;

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

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

                    map.getMap().addSource("districts", {
                        type: "vector",
                        url: `mapbox://${tilesetId}`,
                    })

                    const fillColorExpression: any = [
                        "case",
                        ["has", "kode_kec"],
                        [
                            "match",
                            ["get", "kode_kec"],
                            ...Object.entries(crimeDataByDistrict).flatMap(([districtId, data]) => {
                                return [
                                    districtId,
                                    data.level === "low"
                                        ? CRIME_RATE_COLORS.low
                                        : data.level === "medium"
                                            ? CRIME_RATE_COLORS.medium
                                            : data.level === "high"
                                                ? CRIME_RATE_COLORS.high
                                                : CRIME_RATE_COLORS.default,
                                ]
                            }),
                            CRIME_RATE_COLORS.default,
                        ],
                        CRIME_RATE_COLORS.default,
                    ]

                    if (!map.getMap().getLayer("district-fill")) {
                        map.getMap().addLayer(
                            {
                                id: "district-fill",
                                type: "fill",
                                source: "districts",
                                "source-layer": "Districts",
                                paint: {
                                    "fill-color": fillColorExpression,
                                    "fill-opacity": 0.6,
                                },
                            },
                            firstSymbolId,
                        )
                    }

                    if (!map.getMap().getLayer("district-line")) {
                        map.getMap().addLayer(
                            {
                                id: "district-line",
                                type: "line",
                                source: "districts",
                                "source-layer": "Districts",
                                paint: {
                                    "line-color": "#ffffff",
                                    "line-width": 1,
                                    "line-opacity": 0.5,
                                },
                            },
                            firstSymbolId,
                        )
                    }

                    if (crimes.length > 0 && !map.getMap().getSource("crime-incidents")) {
                        const allIncidents = crimes.flatMap((crime) => {

                            let filteredIncidents = crime.crime_incidents

                            if (filterCategory !== "all") {
                                filteredIncidents = crime.crime_incidents.filter(
                                    incident => incident.crime_categories.name === filterCategory
                                )
                            }

                            return filteredIncidents.map((incident) => ({
                                type: "Feature" as const,
                                properties: {
                                    id: incident.id,
                                    district: crime.districts.name,
                                    category: incident.crime_categories.name,
                                    incidentType: incident.crime_categories.type,
                                    level: crime.level,
                                    description: incident.description,
                                },
                                geometry: {
                                    type: "Point" as const,
                                    coordinates: [incident.locations.longitude, incident.locations.latitude],
                                },
                            }))
                        })

                        map.getMap().addSource("crime-incidents", {
                            type: "geojson",
                            data: {
                                type: "FeatureCollection",
                                features: allIncidents,
                            },
                            cluster: true,
                            clusterMaxZoom: 14,
                            clusterRadius: 50,
                        })

                        if (!map.getMap().getLayer("clusters")) {
                            map.getMap().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,
                                    },
                                },
                                firstSymbolId,
                            )
                        }

                        if (!map.getMap().getLayer("cluster-count")) {
                            map.getMap().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,
                                },
                                paint: {
                                    "text-color": "#ffffff",
                                },
                            })
                        }

                        if (!map.getMap().getLayer("unclustered-point")) {
                            map.getMap().addLayer(
                                {
                                    id: "unclustered-point",
                                    type: "circle",
                                    source: "crime-incidents",
                                    filter: ["!", ["has", "point_count"]],
                                    paint: {
                                        "circle-color": "#11b4da",
                                        "circle-radius": 8,
                                        "circle-stroke-width": 1,
                                        "circle-stroke-color": "#fff",
                                    },
                                },
                                firstSymbolId,
                            )
                        }

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

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

                            const clusterId = features[0].properties?.cluster_id

                                ; (map.getSource("crime-incidents") as mapboxgl.GeoJSONSource).getClusterExpansionZoom(
                                    clusterId,
                                    (err, zoom) => {
                                        if (err) return

                                        map.easeTo({
                                            center: (features[0].geometry as any).coordinates,
                                            zoom: zoom ?? undefined,
                                        })
                                    },
                                )
                        })

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

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

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

                        map.on("mouseleave", "unclustered-point", () => {
                            map.getCanvas().style.cursor = ""
                        })
                    }

                    // Rebind the click event listener for "district-fill"
                    map.on("click", "district-fill", handleClick);

                    // Ensure hover info is cleared when leaving the layer
                    map.on("mouseleave", "district-fill", () => setHoverInfo(null));

                    layersAdded.current = true;
                } else {
                    if (map.getMap().getLayer("district-fill")) {
                        map.getMap().setPaintProperty("district-fill", "fill-color", [
                            "case",
                            ["has", "kode_kec"],
                            [
                                "match",
                                ["get", "kode_kec"],
                                ...Object.entries(crimeDataByDistrict).flatMap(([districtId, data]) => {
                                    return [
                                        districtId,
                                        data.level === "low"
                                            ? CRIME_RATE_COLORS.low
                                            : data.level === "medium"
                                                ? CRIME_RATE_COLORS.medium
                                                : data.level === "high"
                                                    ? CRIME_RATE_COLORS.high
                                                    : CRIME_RATE_COLORS.default,
                                    ]
                                }),
                                CRIME_RATE_COLORS.default,
                            ],
                            CRIME_RATE_COLORS.default,
                        ] as any)
                    }
                }
            } catch (error) {
                console.error("Error adding district layers:", error)
            }
        };

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

        return () => {
            if (map) {
                // Remove the click event listener when the component unmounts or dependencies change
                map.off("click", "district-fill", handleClick);

            }
        };
    }, [map, visible, tilesetId, crimes, filterCategory, year, month]);

    useEffect(() => {
        if (!map || !layersAdded.current) return

        try {
            if (map.getMap().getLayer("district-fill")) {
                // Create a safety check for empty or invalid data
                const colorEntries = Object.entries(crimeDataByDistrict).flatMap(([districtId, data]) => {
                    if (!data || !data.level) {
                        return [
                            districtId,
                            CRIME_RATE_COLORS.default
                        ]
                    }

                    return [
                        districtId,
                        data.level === "low"
                            ? CRIME_RATE_COLORS.low
                            : data.level === "medium"
                                ? CRIME_RATE_COLORS.medium
                                : data.level === "high"
                                    ? CRIME_RATE_COLORS.high
                                    : CRIME_RATE_COLORS.default,
                    ]
                })

                const fillColorExpression = [
                    "case",
                    ["has", "kode_kec"],
                    [
                        "match",
                        ["get", "kode_kec"],
                        ...colorEntries,
                        CRIME_RATE_COLORS.default,
                    ],
                    CRIME_RATE_COLORS.default,
                ] as any

                map.getMap().setPaintProperty("district-fill", "fill-color", fillColorExpression)
            }
        } catch (error) {
            console.error("Error updating district layer:", error)
        }
    }, [map, crimes, crimeDataByDistrict])

    useEffect(() => {
        if (!map || !map.getMap().getSource("crime-incidents")) return

        try {
            const allIncidents = crimes.flatMap((crime) => {
                // Make sure we handle cases where crime_incidents might be undefined
                if (!crime.crime_incidents) return []

                // Apply category filter if specified
                let filteredIncidents = crime.crime_incidents

                if (filterCategory !== "all") {
                    filteredIncidents = crime.crime_incidents.filter(
                        incident => incident.crime_categories &&
                            incident.crime_categories.name === filterCategory
                    )
                }

                return filteredIncidents.map((incident) => {
                    // Handle possible null/undefined values
                    if (!incident.locations) {
                        console.warn("Missing location for incident:", incident.id)
                        return null
                    }

                    return {
                        type: "Feature" as const,
                        properties: {
                            id: incident.id,
                            district: crime.districts?.name || "Unknown",
                            category: incident.crime_categories?.name || "Unknown",
                            incidentType: incident.crime_categories?.type || "Unknown",
                            level: crime.level || "low",
                            description: incident.description || "",
                        },
                        geometry: {
                            type: "Point" as const,
                            coordinates: [
                                incident.locations.longitude || 0,
                                incident.locations.latitude || 0
                            ],
                        },
                    }
                }).filter(Boolean) // Remove null values
            });

            (map.getMap().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])

    // Effect khusus untuk memastikan state selectedDistrict dipertahankan
    // ketika data berubah (tahun/bulan diubah)
    useEffect(() => {
        // Jika kita memiliki district yang dipilih dalam ref, pastikan
        // state juga diperbarui dengan data terbaru
        if (selectedDistrictRef.current) {
            // Cari crime data terbaru untuk district yang dipilih
            const districtId = selectedDistrictRef.current.id;
            const crimeData = crimeDataByDistrict[districtId] || {};

            // Cari data district terkini
            const districtCrime = crimes.find(crime => crime.district_id === districtId);

            // Perbarui data district dengan informasi terkini
            if (districtCrime) {
                const demographics = districtCrime.districts.demographics;
                const geographics = districtCrime.districts.geographics;

                // Filter crime_incidents
                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
                    }));

                // Buat district object baru dengan data terkini
                const updatedDistrict: DistrictFeature = {
                    ...selectedDistrictRef.current,
                    ...crimeData,
                    demographics,
                    geographics,
                    crime_incidents,
                    selectedYear: year,
                    selectedMonth: month
                };

                // Perbarui ref tetapi BUKAN state di sini
                selectedDistrictRef.current = updatedDistrict;

                // Gunakan functional update untuk menghindari loop
                // Hanya update jika berbeda dari state sebelumnya
                setSelectedDistrict(prevDistrict => {
                    // Jika sudah sama, tidak perlu update
                    if (prevDistrict?.id === updatedDistrict.id &&
                        prevDistrict?.selectedYear === updatedDistrict.selectedYear &&
                        prevDistrict?.selectedMonth === updatedDistrict.selectedMonth) {
                        return prevDistrict;
                    }
                    return updatedDistrict;
                });

                console.log("Updated selected district with new data:", updatedDistrict.name);
            }
        }
    }, [crimes, filterCategory, year, month]); // hapus crimeDataByDistrict dari dependencies

    const handleIncidentClick = useCallback((e: any) => {
        if (!map) return;

        // Try to query for crime_incidents at the click location
        const features = map.queryRenderedFeatures(e.point, { layers: ["unclustered-point"] })
        if (!features || features.length === 0) return

        const incident = features[0]
        if (!incident.properties) return

        // Prevent the click from propagating to other layers
        e.originalEvent.stopPropagation()

        // Extract the incident details from the feature properties
        const incidentDetails = {
            id: incident.properties.id,
            district: incident.properties.district,
            category: incident.properties.category,
            type: incident.properties.incidentType,
            description: incident.properties.description,
            status: incident.properties?.status || "Unknown",
            longitude: (incident.geometry as any).coordinates[0],
            latitude: (incident.geometry as any).coordinates[1],
            timestamp: new Date(),
        }

        // Dispatch the custom event to the map container element directly
        const customEvent = new CustomEvent('incident_click', {
            detail: incidentDetails,
            bubbles: true // Make sure the event bubbles up
        })

        if (map.getMap().getCanvas()) {
            map.getMap().getCanvas().dispatchEvent(customEvent)
        } else {
            document.dispatchEvent(customEvent) // Fallback
        }
    }, [map]);

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

        // Add click handler for individual incident points
        if (map.getMap().getLayer("unclustered-point")) {
            map.on("click", "unclustered-point", handleIncidentClick)
        }

        return () => {
            if (map && map.getMap().getLayer("unclustered-point")) {
                map.off("click", "unclustered-point", handleIncidentClick)
            }
        }
    }, [map, visible, handleIncidentClick]);

    if (!visible) return null

    return (
        <>
            {/* {hoverInfo && (
                <div
                    className="absolute z-10 bg-white rounded-md shadow-md px-3 py-2 pointer-events-none"
                    style={{
                        left: hoverInfo.x + 10,
                        top: hoverInfo.y + 10,
                    }}
                >
                    <p className="text-sm font-medium">
                        {hoverInfo.feature.properties.nama || hoverInfo.feature.properties.kecamatan}
                    </p>
                    {hoverInfo.feature.properties.number_of_crime !== undefined && (
                        <p className="text-xs text-gray-600">
                            {hoverInfo.feature.properties.number_of_crime} crime_incidents
                            {hoverInfo.feature.properties.level && (
                                <span className="ml-2 text-xs font-semibold text-gray-500">({hoverInfo.feature.properties.level})</span>
                            )}
                        </p>
                    )}
                </div>
            )} */}

            {selectedDistrictRef.current ? (
                <DistrictPopup
                    longitude={selectedDistrictRef.current.longitude || 0}
                    latitude={selectedDistrictRef.current.latitude || 0}
                    onClose={() => {
                        selectedDistrictRef.current = null;
                        setSelectedDistrict(null);
                    }}
                    district={selectedDistrictRef.current}
                    year={year}
                    month={month}
                    filterCategory={filterCategory}
                />
            ) : null}
        </>
    )
}
