"use client"

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

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

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

    // 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(() => {
        return {
            type: "FeatureCollection" as const,
            features: unitsData.map(unit => ({
                type: "Feature" as const,
                properties: {
                    id: unit.code_unit,
                    name: unit.name,
                    address: unit.address,
                    phone: unit.phone,
                    type: unit.type,
                    district: unit.districts?.name || "",
                    district_id: unit.district_id,
                },
                geometry: {
                    type: "Point" as const,
                    coordinates: [unit.longitude || 0, unit.latitude || 0]
                }
            })).filter(feature =>
                feature.geometry.coordinates[0] !== 0 &&
                feature.geometry.coordinates[1] !== 0
            )
        }
    }, [unitsData])

    // 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])

    // Map click handler code and the rest remains the same...
    useEffect(() => {
        if (!map || !visible) return

        const handleUnitClick = (e: mapboxgl.MapMouseEvent & { features?: mapboxgl.MapboxGeoJSONFeature[] }) => {
            if (!e.features || e.features.length === 0) return

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

            if (!properties) return

            // Create a popup for the unit
            const popup = new mapboxgl.Popup()
                .setLngLat(feature.geometry.type === 'Point' ?
                    (feature.geometry as any).coordinates as [number, number] :
                    [0, 0]) // Fallback coordinates if not a Point geometry
                .setHTML(`
          <div class="p-2">
            <h3 class="font-bold text-base">${properties.name}</h3>
            <p class="text-sm">${properties.type}</p>
            <p class="text-sm">${properties.address || 'No address provided'}</p>
            <p class="text-xs mt-2">Staff: ${properties.staff_count || 'N/A'}</p>
            <p class="text-xs">Phone: ${properties.phone || 'N/A'}</p>
            <p class="text-xs">District: ${properties.district || 'N/A'}</p>
          </div>
        `)
                .addTo(map)

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

            // When popup closes, reset the lines filter
            popup.on('close', () => {
                if (map.getLayer('units-connection-lines')) {
                    map.setFilter('units-connection-lines', ['has', 'unit_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.on('click', 'units-points', handleUnitClick)

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

        return () => {
            if (map.getLayer('units-points')) {
                map.off('click', 'units-points', handleUnitClick)
                map.off('mouseenter', 'units-points', handleMouseEnter)
                map.off('mouseleave', 'units-points', handleMouseLeave)
            }
        }
    }, [map, visible])

    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>

            {/* 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': 1.5,
                        'line-opacity': 0.7,
                        'line-dasharray': [1, 2] // Dashed line
                    }}
                />
            </Source>
        </>
    )
}
