"use client";

import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import type { ICrimes } from "@/app/_utils/types/crimes";
import {
    BASE_BEARING,
    BASE_DURATION,
    BASE_PITCH,
    BASE_ZOOM,
    PITCH_3D,
    ZOOM_3D,
} from "@/app/_utils/const/map";
import IncidentPopup from "../pop-up/incident-popup";
import type mapboxgl from "mapbox-gl";
import type { MapGeoJSONFeature, MapMouseEvent } from "react-map-gl/mapbox";
import { manageLayerVisibility } from "@/app/_utils/map/layer-visibility";
import { getCategoryColor } from "@/app/_utils/colors";

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

interface IIncidentFeatureProperties {
    id: string;
    category: string;
    description: string;
    timestamp: string;
    district: string;
    district_id: string;
    year: number;
    month: number;
    address: string | null;
    latitude: number;
    longitude: number;
}

interface IIncidentDetails {
    id: string;
    category: string;
    description: string;
    timestamp: Date;
    district: string;
    district_id: string;
    year: number;
    month: number;
    address: string | null;
    latitude: number;
    longitude: number;
}

export default function AllIncidentsLayer(
    { visible = false, map, crimes = [], filterCategory = "all" }:
        IAllIncidentsLayerProps,
) {
    const isInteractingWithMarker = useRef(false);
    const animationFrameRef = useRef<number | null>(null);
    const [selectedIncident, setSelectedIncident] = useState<
        IIncidentDetails | null
    >(null);

    // Define layer IDs for consistent management
    const LAYER_IDS = [
        "all-incidents-pulse",
        "all-incidents-circles",
        "all-incidents",
    ];

    const handleIncidentClick = useCallback(
        (e: MapMouseEvent & { features?: MapGeoJSONFeature[] }) => {
            if (!map) return;

            const features = map.queryRenderedFeatures(e.point, {
                layers: ["all-incidents"],
            });
            if (!features || features.length === 0) return;

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

            isInteractingWithMarker.current = true;

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

            const props = incident
                .properties as unknown as IIncidentFeatureProperties;

            const IincidentDetails: IIncidentDetails = {
                id: props.id,
                description: props.description,
                category: props.category,
                district: props.district,
                district_id: props.district_id,
                year: props.year,
                month: props.month,
                address: props.address,
                latitude: props.latitude,
                longitude: props.longitude,
                timestamp: new Date(props.timestamp || Date.now()),
            };

            // Fly to the incident location
            map.flyTo({
                center: [IincidentDetails.longitude, IincidentDetails.latitude],
                zoom: ZOOM_3D,
                bearing: BASE_BEARING,
                pitch: PITCH_3D,
                duration: BASE_DURATION,
            });

            // Set selected incident for the popup
            setSelectedIncident(IincidentDetails);

            // Reset the flag after a delay
            setTimeout(() => {
                isInteractingWithMarker.current = false;
            }, 1000);
        },
        [map],
    );

    // Handle popup close
    const handleClosePopup = useCallback(() => {
        if (!map) return;

        map.easeTo({
            zoom: BASE_ZOOM,
            bearing: BASE_BEARING,
            pitch: BASE_PITCH,
            duration: BASE_DURATION,
        });

        setSelectedIncident(null);
    }, [map]);

    // Effect to manage layer visibility consistently
    useEffect(() => {
        const cleanup = manageLayerVisibility(map, LAYER_IDS, visible, () => {
            // When layers become invisible, close any open popup
            if (!visible) setSelectedIncident(null);

            // Cancel animation frame when hiding the layer
            if (!visible && animationFrameRef.current) {
                cancelAnimationFrame(animationFrameRef.current);
                animationFrameRef.current = null;
            }
        });

        return cleanup;
    }, [visible, map]);

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

        // Get unique categories from crime data for more accurate color mapping
        const uniqueCategories = new Set<string>();
        crimes.forEach(crime => {
            crime.crime_incidents.forEach(incident => {
                if (incident.crime_categories?.name) {
                    uniqueCategories.add(incident.crime_categories.name);
                }
            });
        });

        // Pre-compute category colors for better performance
        const categoryColorMap: Record<string, string> = {};
        uniqueCategories.forEach(category => {
            categoryColorMap[category] = getCategoryColor(category);
        });

        // Convert incidents to GeoJSON format
        const allIncidents = crimes.flatMap((crime) => {
            return crime.crime_incidents
                .filter((incident) =>
                    // Apply category filter if specified
                    (filterCategory === "all" ||
                        incident.crime_categories?.name === filterCategory) &&
                    // Make sure we have valid location data
                    incident.locations?.latitude &&
                    incident.locations?.longitude
                )
                .map((incident) => ({
                    type: "Feature" as const,
                    geometry: {
                        type: "Point" as const,
                        coordinates: [
                            incident.locations!.longitude,
                            incident.locations!.latitude,
                        ],
                    },
                    properties: {
                        id: incident.id,
                        description: incident.description || "No description",
                        timestamp: incident.timestamp?.toString() ||
                            new Date().toString(),
                        category: incident.crime_categories?.name || "Unknown",
                        district: crime.districts?.name || "Unknown",
                        district_id: crime.district_id,
                        year: crime.year,
                        month: crime.month,
                        address: incident.locations?.address || null,
                        latitude: incident.locations!.latitude,
                        longitude: incident.locations!.longitude,
                    },
                }));
        });

        const incidentsGeoJSON = {
            type: "FeatureCollection" as const,
            features: allIncidents,
        };

        const setupLayersAndSources = () => {
            try {
                // Check if source already exists and update it
                if (map.getSource("all-incidents-source")) {
                    const source = map.getSource(
                        "all-incidents-source",
                    ) as mapboxgl.GeoJSONSource;
                    source.setData(incidentsGeoJSON);
                } else {
                    // Add source if it doesn't exist
                    map.addSource("all-incidents-source", {
                        type: "geojson",
                        data: incidentsGeoJSON,
                    });

                    // Get first symbol layer for insertion order
                    const layers = map.getStyle().layers;
                    let firstSymbolId: string | undefined;
                    for (const layer of layers) {
                        if (layer.type === "symbol") {
                            firstSymbolId = layer.id;
                            break;
                        }
                    }

                    // Pulsing circle effect for very recent incidents
                    map.addLayer({
                        id: "all-incidents-pulse",
                        type: "circle",
                        source: "all-incidents-source",
                        paint: {
                            "circle-radius": [
                                "interpolate",
                                ["linear"],
                                ["zoom"],
                                10,
                                10,
                                15,
                                20,
                            ],
                            "circle-color": [
                                "match",
                                ["get", "category"],
                                // Use dynamic mapping from pre-computed category colors
                                ...Object.entries(categoryColorMap).flatMap(
                                    ([category, color]) => [category, color]
                                ),
                                // Default color for other categories
                                getCategoryColor("Unknown")
                            ],
                            "circle-opacity": 0.4,
                            "circle-blur": 0.6,
                        },
                    }, firstSymbolId);

                    // Background circle for all incidents
                    map.addLayer({
                        id: "all-incidents-circles",
                        type: "circle",
                        source: "all-incidents-source",
                        paint: {
                            "circle-radius": [
                                "interpolate",
                                ["linear"],
                                ["zoom"],
                                10,
                                5,
                                15,
                                10,
                            ],
                            "circle-color": [
                                "match",
                                ["get", "category"],
                                // Use dynamic mapping from pre-computed category colors
                                ...Object.entries(categoryColorMap).flatMap(
                                    ([category, color]) => [category, color]
                                ),
                                // Default color for other categories
                                getCategoryColor("Unknown")
                            ],
                            "circle-stroke-width": 1,
                            "circle-stroke-color": "#FFFFFF",
                            "circle-opacity": 0.6,
                        },
                    }, firstSymbolId);

                    // Main incident point
                    map.addLayer({
                        id: "all-incidents",
                        type: "circle",
                        source: "all-incidents-source",
                        paint: {
                            "circle-radius": [
                                "interpolate",
                                ["linear"],
                                ["zoom"],
                                10,
                                3,
                                15,
                                6,
                            ],
                            "circle-color": [
                                "match",
                                ["get", "category"],
                                // Use dynamic mapping from pre-computed category colors
                                ...Object.entries(categoryColorMap).flatMap(
                                    ([category, color]) => [category, color]
                                ),
                                // Default color for other categories
                                getCategoryColor("Unknown")
                            ],
                            "circle-stroke-width": 1,
                            "circle-stroke-color": "#FFFFFF",
                            "circle-opacity": 1,
                        },
                    }, firstSymbolId);
                }

                // Add mouse events
                map.on("mouseenter", "all-incidents", () => {
                    map.getCanvas().style.cursor = "pointer";
                });

                map.on("mouseleave", "all-incidents", () => {
                    map.getCanvas().style.cursor = "";
                });

                map.on("click", "all-incidents", handleIncidentClick);
            } catch (error) {
                console.error("Error setting up all incidents layer:", error);
            }
        };

        // Set up layers when the map is ready
        if (map.isStyleLoaded()) {
            setupLayersAndSources();
        } else {
            map.once("load", setupLayersAndSources);
        }

        // Start the pulse animation effect
        const animatePulse = () => {
            if (!map || !visible || !map.getLayer("all-incidents-pulse")) {
                if (animationFrameRef.current) {
                    cancelAnimationFrame(animationFrameRef.current);
                    animationFrameRef.current = null;
                }
                return;
            }

            const pulseSize = 10 + 5 * Math.sin(Date.now() / 500);

            try {
                map.setPaintProperty("all-incidents-pulse", "circle-radius", [
                    "interpolate",
                    ["linear"],
                    ["zoom"],
                    10,
                    pulseSize,
                    15,
                    pulseSize * 2,
                ]);

                animationFrameRef.current = requestAnimationFrame(animatePulse);
            } catch (error) {
                if (animationFrameRef.current) {
                    cancelAnimationFrame(animationFrameRef.current);
                    animationFrameRef.current = null;
                }
            }
        };

        animationFrameRef.current = requestAnimationFrame(animatePulse);

        // Clean up event listeners and animation
        return () => {
            if (map) {
                map.off("click", "all-incidents", handleIncidentClick);
                map.off("mouseenter", "all-incidents", () => {
                    map.getCanvas().style.cursor = "pointer";
                });
                map.off("mouseleave", "all-incidents", () => {
                    map.getCanvas().style.cursor = "";
                });
            }

            if (animationFrameRef.current) {
                cancelAnimationFrame(animationFrameRef.current);
                animationFrameRef.current = null;
            }
        };
    }, [map, visible, crimes, filterCategory, handleIncidentClick]);

    return (
        <>
            {selectedIncident && (
                <IncidentPopup
                    longitude={selectedIncident.longitude}
                    latitude={selectedIncident.latitude}
                    onClose={handleClosePopup}
                    incident={selectedIncident}
                />
            )}
        </>
    );
}
