"use client"

import { useEffect, useRef } from "react"
import { useMap } from "react-map-gl/mapbox"
import { CRIME_RATE_COLORS } from "@/app/_utils/const/map"
import { $Enums } from "@prisma/client"

export interface DistrictExtrusionLayerProps {
    visible?: boolean
    focusedDistrictId: string | null
    crimeDataByDistrict: Record<string, { number_of_crime?: number; level?: $Enums.crime_rates }>
    tilesetId: string
    beforeId?: string
}

export default function DistrictExtrusionLayer({
    visible = true,
    focusedDistrictId,
    crimeDataByDistrict,
    tilesetId,
    beforeId,
}: DistrictExtrusionLayerProps) {
    const { current: map } = useMap()
    const layersAdded = useRef(false)

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

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

            try {
                // Make sure the districts source exists
                if (!map.getMap().getSource("districts")) {
                    map.getMap().addSource("districts", {
                        type: "vector",
                        url: `mapbox://${tilesetId}`,
                    })
                }

                // Get the first symbol layer
                let firstSymbolId = beforeId
                if (!firstSymbolId) {
                    const layers = map.getStyle().layers
                    for (const layer of layers) {
                        if (layer.type === "symbol") {
                            firstSymbolId = layer.id
                            break
                        }
                    }
                }

                if (!map.getMap().getLayer("district-extrusion")) {
                    map.getMap().addLayer(
                        {
                            id: "district-extrusion",
                            type: "fill-extrusion",
                            source: "districts",
                            "source-layer": "Districts",
                            paint: {
                                "fill-extrusion-color": [
                                    "case",
                                    ["has", "kode_kec"],
                                    [
                                        "match",
                                        ["get", "kode_kec"],
                                        focusedDistrictId || "",
                                        crimeDataByDistrict[focusedDistrictId || ""]?.level === "low"
                                            ? CRIME_RATE_COLORS.low
                                            : crimeDataByDistrict[focusedDistrictId || ""]?.level === "medium"
                                                ? CRIME_RATE_COLORS.medium
                                                : crimeDataByDistrict[focusedDistrictId || ""]?.level === "high"
                                                    ? CRIME_RATE_COLORS.high
                                                    : CRIME_RATE_COLORS.default,
                                        "transparent",
                                    ],
                                    "transparent",
                                ],
                                "fill-extrusion-height": [
                                    "case",
                                    ["has", "kode_kec"],
                                    ["match", ["get", "kode_kec"], focusedDistrictId || "", 500, 0],
                                    0,
                                ],
                                "fill-extrusion-base": 0,
                                "fill-extrusion-opacity": 0.8,
                            },
                            filter: ["==", ["get", "kode_kec"], focusedDistrictId || ""],
                        },
                        firstSymbolId,
                    )
                    layersAdded.current = true
                }
            } catch (error) {
                console.error("Error adding extrusion layer:", error)
            }
        }

        if (map.isStyleLoaded()) {
            onStyleLoad()
        } else {
            map.once("style.load", onStyleLoad)
        }
    }, [map, visible, tilesetId, beforeId])

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

        try {
            if (map.getMap().getLayer("district-extrusion")) {
                map.getMap().setFilter("district-extrusion", ["==", ["get", "kode_kec"], focusedDistrictId || ""])

                map.getMap().setPaintProperty("district-extrusion", "fill-extrusion-color", [
                    "case",
                    ["has", "kode_kec"],
                    [
                        "match",
                        ["get", "kode_kec"],
                        focusedDistrictId || "",
                        crimeDataByDistrict[focusedDistrictId || ""]?.level === "low"
                            ? CRIME_RATE_COLORS.low
                            : crimeDataByDistrict[focusedDistrictId || ""]?.level === "medium"
                                ? CRIME_RATE_COLORS.medium
                                : crimeDataByDistrict[focusedDistrictId || ""]?.level === "high"
                                    ? CRIME_RATE_COLORS.high
                                    : CRIME_RATE_COLORS.default,
                        "transparent",
                    ],
                    "transparent",
                ])

                if (focusedDistrictId) {
                    const startHeight = 0
                    const targetHeight = 800
                    const duration = 700
                    const startTime = performance.now()

                    const animateHeight = (currentTime: number) => {
                        const elapsed = currentTime - startTime
                        const progress = Math.min(elapsed / duration, 1)
                        const easedProgress = progress * (2 - progress)
                        const currentHeight = startHeight + (targetHeight - startHeight) * easedProgress

                        map
                            .getMap()
                            .setPaintProperty("district-extrusion", "fill-extrusion-height", [
                                "case",
                                ["has", "kode_kec"],
                                ["match", ["get", "kode_kec"], focusedDistrictId, currentHeight, 0],
                                0,
                            ])

                        if (progress < 1) {
                            requestAnimationFrame(animateHeight)
                        }
                    }

                    requestAnimationFrame(animateHeight)
                } else {
                    const startHeight = 800
                    const targetHeight = 0
                    const duration = 500
                    const startTime = performance.now()

                    const animateHeightDown = (currentTime: number) => {
                        const elapsed = currentTime - startTime
                        const progress = Math.min(elapsed / duration, 1)
                        const easedProgress = progress * (2 - progress)
                        const currentHeight = startHeight + (targetHeight - startHeight) * easedProgress

                        map
                            .getMap()
                            .setPaintProperty("district-extrusion", "fill-extrusion-height", [
                                "case",
                                ["has", "kode_kec"],
                                ["match", ["get", "kode_kec"], "", currentHeight, 0],
                                0,
                            ])

                        if (progress < 1) {
                            requestAnimationFrame(animateHeightDown)
                        }
                    }

                    requestAnimationFrame(animateHeightDown)
                }
            }
        } catch (error) {
            console.error("Error updating extrusion layer:", error)
        }
    }, [map, focusedDistrictId, crimeDataByDistrict])

    return null
}
