"use client"

import { BASE_BEARING, BASE_PITCH, BASE_ZOOM } from "@/app/_utils/const/map"
import { createFillColorExpression, processDistrictFeature } from "@/app/_utils/map"
import { IDistrictLayerProps } from "@/app/_utils/types/map"
import { useEffect } from "react"


export default function DistrictFillLineLayer({
    visible = true,
    map,
    onClick,
    year,
    month,
    filterCategory = "all",
    crimes = [],
    tilesetId,
    focusedDistrictId,
    setFocusedDistrictId,
    crimeDataByDistrict,
    showFill = true,
    activeControl,
}: IDistrictLayerProps) {
    useEffect(() => {
        if (!map || !visible) return

        const handleDistrictClick = (e: any) => {
            const incidentFeatures = map.queryRenderedFeatures(e.point, {
                layers: ["unclustered-point", "clusters"],
            })

            if (incidentFeatures && incidentFeatures.length > 0) {
                return
            }

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

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

            // If clicking the same district, deselect it
            if (focusedDistrictId === districtId) {
                // Add null check for setFocusedDistrictId
                if (setFocusedDistrictId) {
                    setFocusedDistrictId(null)
                }

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

                // Restore fill color for all districts when unfocusing
                const fillColorExpression = createFillColorExpression(null, crimeDataByDistrict)
                map.setPaintProperty("district-fill", "fill-color", fillColorExpression as any)

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

                return
            } else if (focusedDistrictId) {
                // If we're already focusing on a district and clicking a different one,
                // we need to reset the current one and move to the new one
                if (setFocusedDistrictId) {
                    setFocusedDistrictId(null)
                }

                // Wait a moment before selecting the new district to ensure clean transitions
                setTimeout(() => {
                    const district = processDistrictFeature(feature, e, districtId, crimeDataByDistrict, crimes, year, month)
                    if (!district || !setFocusedDistrictId) return

                    setFocusedDistrictId(district.id)

                    // Fly to the new district
                    map.flyTo({
                        center: [district.longitude, district.latitude],
                        zoom: 12.5,
                        pitch: 75,
                        bearing: 0,
                        duration: 1500,
                        easing: (t) => t * (2 - t), // easeOutQuad
                    })

                    if (onClick) {
                        onClick(district)
                    }
                }, 100)

                return
            }

            const district = processDistrictFeature(feature, e, districtId, crimeDataByDistrict, crimes, year, month)

            if (!district) return

            // Set the fill color expression immediately to show the focus
            const focusedFillColorExpression = createFillColorExpression(district.id, crimeDataByDistrict)
            map.setPaintProperty("district-fill", "fill-color", focusedFillColorExpression as any)

            // Add null check for setFocusedDistrictId
            if (setFocusedDistrictId) {
                setFocusedDistrictId(district.id)
            }

            // Hide clusters when focusing on a district
            if (map.getLayer("clusters")) {
                map.setLayoutProperty("clusters", "visibility", "none")
            }
            if (map.getLayer("unclustered-point")) {
                map.setLayoutProperty("unclustered-point", "visibility", "none")
            }

            // Animate to a pitched view focused on the district
            map.flyTo({
                center: [district.longitude, district.latitude],
                zoom: 12.5,
                pitch: 75,
                bearing: 0,
                duration: 1500,
                easing: (t) => t * (2 - t), // easeOutQuad
            })

            if (onClick) {
                onClick(district)
            }
        }

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

            try {
                if (!map.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.addSource("districts", {
                        type: "vector",
                        url: `mapbox://${tilesetId}`,
                    })

                    const fillColorExpression = createFillColorExpression(focusedDistrictId, crimeDataByDistrict)

                    // Determine fill opacity based on active control
                    const fillOpacity = getFillOpacity(activeControl, showFill);

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

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

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

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

                    map.off("click", "district-fill", handleDistrictClick)
                    map.on("click", "district-fill", handleDistrictClick)
                } else {
                    if (map.getLayer("district-fill")) {
                        const fillColorExpression = createFillColorExpression(focusedDistrictId, crimeDataByDistrict)
                        map.setPaintProperty("district-fill", "fill-color", fillColorExpression as any)

                        // Update fill opacity when active control changes
                        const fillOpacity = getFillOpacity(activeControl, showFill);
                        map.setPaintProperty("district-fill", "fill-opacity", fillOpacity);
                    }
                }
            } catch (error) {
                console.error("Error adding district layers:", error)
            }
        }

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

        return () => {
            if (map) {
                map.off("click", "district-fill", handleDistrictClick)
            }
        }
    }, [
        map,
        visible,
        tilesetId,
        crimes,
        filterCategory,
        year,
        month,
        focusedDistrictId,
        crimeDataByDistrict,
        onClick,
        setFocusedDistrictId,
        showFill,
        activeControl,
    ])

    // Add an effect to update the fill color and opacity whenever relevant props change
    useEffect(() => {
        if (!map || !map.getLayer("district-fill")) return;

        try {
            const fillColorExpression = createFillColorExpression(focusedDistrictId, crimeDataByDistrict)
            map.setPaintProperty("district-fill", "fill-color", fillColorExpression as any)

            // Update fill opacity when active control changes
            const fillOpacity = getFillOpacity(activeControl, showFill);
            map.setPaintProperty("district-fill", "fill-opacity", fillOpacity);
        } catch (error) {
            console.error("Error updating district fill colors or opacity:", error)
        }
    }, [map, focusedDistrictId, crimeDataByDistrict, activeControl, showFill])

    return null
}

// Helper function to determine fill opacity based on active control
function getFillOpacity(activeControl?: string, showFill?: boolean): number {
    if (!showFill) return 0;

    // Full opacity for incidents and clusters
    if (activeControl === "incidents" || activeControl === "clusters") {
        return 0.6;
    }

    // Low opacity for timeline to show markers but still see district boundaries
    if (activeControl === "timeline") {
        return 0.1;
    }

    // No fill for other controls, but keep boundaries visible
    return 0;
}
