"use client"

import { useEffect, useMemo, useState } from 'react'
import { Layer, Source } from "react-map-gl/mapbox"
import { ICrimes } from "@/app/_utils/types/crimes"
import mapboxgl from 'mapbox-gl'
import { format } from 'date-fns'
import { calculateAverageTimeOfDay } from '@/app/_utils/time'


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

export default function TimelineLayer({
    crimes,
    year,
    month,
    filterCategory,
    visible = false,
    map
}: TimelineLayerProps) {
    // State to hold the currently selected district for popup display
    const [selectedDistrict, setSelectedDistrict] = useState<string | null>(null)
    const [popup, setPopup] = useState<mapboxgl.Popup | null>(null)

    // Process district data to extract average incident times
    const districtTimeData = useMemo(() => {
        // Group incidents by district
        const districtGroups = new Map<string, {
            districtId: string,
            districtName: string,
            incidents: Array<{ timestamp: Date, category: string }>,
            center: [number, number]
        }>()

        crimes.forEach(crime => {
            if (!crime.districts || !crime.district_id) return

            // Initialize district group if not exists
            if (!districtGroups.has(crime.district_id)) {
                // Find a central location for the district from any incident
                const centerIncident = crime.crime_incidents.find(inc =>
                    inc.locations?.latitude && inc.locations?.longitude
                )

                const center: [number, number] = centerIncident
                    ? [centerIncident.locations.longitude, centerIncident.locations.latitude]
                    : [0, 0]

                districtGroups.set(crime.district_id, {
                    districtId: crime.district_id,
                    districtName: crime.districts.name,
                    incidents: [],
                    center
                })
            }

            // Add valid incidents to the district group
            crime.crime_incidents.forEach(incident => {
                if (!incident.timestamp) return
                if (filterCategory !== "all" && incident.crime_categories.name !== filterCategory) return

                const group = districtGroups.get(crime.district_id)
                if (group) {
                    group.incidents.push({
                        timestamp: new Date(incident.timestamp),
                        category: incident.crime_categories.name
                    })
                }
            })
        })

        // Calculate average time for each district
        const result = Array.from(districtGroups.values())
            .filter(group => group.incidents.length > 0 && group.center[0] !== 0)
            .map(group => {
                const avgTimeInfo = calculateAverageTimeOfDay(group.incidents.map(inc => inc.timestamp))

                return {
                    id: group.districtId,
                    name: group.districtName,
                    center: group.center,
                    avgHour: avgTimeInfo.hour,
                    avgMinute: avgTimeInfo.minute,
                    formattedTime: avgTimeInfo.formattedTime,
                    timeDescription: avgTimeInfo.description,
                    totalIncidents: group.incidents.length,
                    // Categorize by morning, afternoon, evening, night
                    timeOfDay: avgTimeInfo.timeOfDay,
                    // Additional statistics 
                    earliestTime: format(avgTimeInfo.earliest, 'p'),
                    latestTime: format(avgTimeInfo.latest, 'p'),
                    mostFrequentHour: avgTimeInfo.mostFrequentHour,
                    // Group incidents by category for the popup
                    categoryCounts: group.incidents.reduce((acc, inc) => {
                        acc[inc.category] = (acc[inc.category] || 0) + 1
                        return acc
                    }, {} as Record<string, number>)
                }
            })

        return result
    }, [crimes, filterCategory])

    // Convert processed data to GeoJSON for display
    const timelineGeoJSON = useMemo(() => {
        return {
            type: "FeatureCollection" as const,
            features: districtTimeData.map(district => ({
                type: "Feature" as const,
                properties: {
                    id: district.id,
                    name: district.name,
                    avgTime: district.formattedTime,
                    timeDescription: district.timeDescription,
                    totalIncidents: district.totalIncidents,
                    timeOfDay: district.timeOfDay
                },
                geometry: {
                    type: "Point" as const,
                    coordinates: district.center
                }
            }))
        }
    }, [districtTimeData])

    // Style time markers based on time of day
    const getTimeMarkerColor = (timeOfDay: string) => {
        switch (timeOfDay) {
            case 'morning': return '#FFEB3B' // yellow
            case 'afternoon': return '#FF9800' // orange
            case 'evening': return '#3F51B5' // indigo
            case 'night': return '#263238' // dark blue-grey
            default: return '#4CAF50' // green fallback
        }
    }

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

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

            const feature = e.features[0]
            const props = feature.properties
            if (!props) return

            // Get the corresponding district data for detailed info
            const districtData = districtTimeData.find(d => d.id === props.id)
            if (!districtData) return

            // Remove existing popup if any
            if (popup) popup.remove()

            // Create HTML content for popup
            const categoriesHtml = Object.entries(districtData.categoryCounts)
                .sort(([, countA], [, countB]) => countB - countA)
                .slice(0, 5) // Top 5 categories
                .map(([category, count]) =>
                    `<div class="flex justify-between mb-1">
            <span class="text-xs">${category}</span>
            <span class="text-xs font-semibold">${count}</span>
          </div>`
                ).join('')

            // Create popup
            const newPopup = new mapboxgl.Popup({ closeButton: true, closeOnClick: false })
                .setLngLat(feature.geometry.type === 'Point' ? (feature.geometry as GeoJSON.Point).coordinates as [number, number] : [0, 0])
                .setHTML(`
          <div class="p-3">
            <div class="font-bold text-base mb-2">${districtData.name}</div>
            <div class="mb-3">
              <span class="text-xs text-gray-600">Average incident time</span>
              <div class="flex items-center gap-2">
                <div class="text-lg font-bold">${districtData.formattedTime}</div>
                <div class="text-xs bg-gray-200 rounded px-2 py-0.5">${districtData.timeDescription}</div>
              </div>
              <div class="text-xs mt-1">Based on ${districtData.totalIncidents} incidents</div>
            </div>
            
            <div class="text-sm my-2">
              <div class="flex justify-between mb-1">
                <span>Earliest incident:</span>
                <span class="font-medium">${districtData.earliestTime}</span>
              </div>
              <div class="flex justify-between">
                <span>Latest incident:</span>
                <span class="font-medium">${districtData.latestTime}</span>
              </div>
            </div>
            
            <div class="border-t border-gray-200 my-2 pt-2">
              <div class="text-xs font-medium mb-1">Top incident types:</div>
              ${categoriesHtml}
            </div>
          </div>
        `)
                .addTo(map)

            // Store popup reference
            setPopup(newPopup)
            setSelectedDistrict(props.id)

            // Remove popup when closed
            newPopup.on('close', () => {
                setPopup(null)
                setSelectedDistrict(null)
            })
        }

        // Set up event handlers
        const handleMouseEnter = () => {
            if (map) map.getCanvas().style.cursor = 'pointer'
        }

        const handleMouseLeave = () => {
            if (map) map.getCanvas().style.cursor = ''
        }

        // Add event listeners
        if (map.getLayer('timeline-markers')) {
            map.on('click', 'timeline-markers', handleTimeMarkerClick)
            map.on('mouseenter', 'timeline-markers', handleMouseEnter)
            map.on('mouseleave', 'timeline-markers', handleMouseLeave)
        }

        return () => {
            // Clean up event listeners
            if (map) {
                map.off('click', 'timeline-markers', handleTimeMarkerClick)
                map.off('mouseenter', 'timeline-markers', handleMouseEnter)
                map.off('mouseleave', 'timeline-markers', handleMouseLeave)

                // Remove popup if it exists
                if (popup) {
                    popup.remove()
                    setPopup(null)
                }
            }
        }
    }, [map, visible, districtTimeData, popup])

    // Clean up popup on unmount or when visibility changes
    useEffect(() => {
        if (!visible && popup) {
            popup.remove()
            setPopup(null)
            setSelectedDistrict(null)
        }
    }, [visible, popup])

    if (!visible) return null

    return (
        <Source id="timeline-data" type="geojson" data={timelineGeoJSON}>
            {/* Time marker circles */}
            <Layer
                id="timeline-markers"
                type="circle"
                paint={{
                    'circle-color': [
                        'match',
                        ['get', 'timeOfDay'],
                        'morning', '#FFEB3B',
                        'afternoon', '#FF9800',
                        'evening', '#3F51B5',
                        'night', '#263238',
                        '#4CAF50'  // Default color
                    ],
                    'circle-radius': 12,
                    'circle-stroke-width': 2,
                    'circle-stroke-color': '#ffffff',
                    'circle-opacity': 0.9
                }}
            />

            {/* Time labels */}
            <Layer
                id="timeline-labels"
                type="symbol"
                layout={{
                    'text-field': '{avgTime}',
                    'text-font': ['DIN Offc Pro Medium', 'Arial Unicode MS Bold'],
                    'text-size': 10,
                    'text-anchor': 'center',
                    'text-allow-overlap': true
                }}
                paint={{
                    'text-color': [
                        'match',
                        ['get', 'timeOfDay'],
                        'night', '#FFFFFF',
                        'evening', '#FFFFFF',
                        '#000000'  // Default text color
                    ]
                }}
            />
        </Source>
    )
}
