/**
 * ChatMapPanel.tsx - Collapsible MapLibre map panel for chat results
 * 
 * A Material-UI styled map panel that displays heritage institutions
 * with coordinates returned from RAG queries.
 * 
 * Features:
 * - Collapsible panel that shows/hides the map
 * - Real OSM/CartoDB tiles (light/dark mode)
 * - GLAMORCUBESFIXPHDNT type colors (19 types)
 * - Click markers to show institution details
 * - Automatic bounds fitting
 */

import React, { useRef, useEffect, useState, useMemo, useCallback } from 'react'
import maplibregl from 'maplibre-gl'
import type { StyleSpecification, MapLayerMouseEvent, GeoJSONSource } from 'maplibre-gl'
import 'maplibre-gl/dist/maplibre-gl.css'
import {
  Box,
  Paper,
  Typography,
  Collapse,
  IconButton,
  Chip,
  Link,
} from '@mui/material'
import ExpandMoreIcon from '@mui/icons-material/ExpandMore'
import ExpandLessIcon from '@mui/icons-material/ExpandLess'
import MapIcon from '@mui/icons-material/Map'
import PlaceIcon from '@mui/icons-material/Place'
import OpenInNewIcon from '@mui/icons-material/OpenInNew'
import CloseIcon from '@mui/icons-material/Close'

// NA Color palette (matches ChatPage.tsx)
const naColors = {
  primary: '#007bc7',
  red: '#d52b1e',
  orange: '#e17000',
  green: '#39870c',
  cream: '#f7f5f3',
  darkBlue: '#154273',
  lightBlue: '#e5f0f9',
}

// Custodian type colors matching GLAMORCUBESFIXPHDNT taxonomy (19 types)
const TYPE_COLORS: Record<string, string> = {
  G: '#00bcd4',  // Gallery - cyan
  L: '#2ecc71',  // Library - green
  A: '#3498db',  // Archive - blue
  M: '#e74c3c',  // Museum - red
  O: '#f39c12',  // Official - orange
  R: '#1abc9c',  // Research - teal
  C: '#795548',  // Corporation - brown
  U: '#9e9e9e',  // Unknown - gray
  B: '#4caf50',  // Botanical - green
  E: '#ff9800',  // Education - amber
  S: '#9b59b6',  // Society - purple
  F: '#95a5a6',  // Features - gray
  I: '#673ab7',  // Intangible - deep purple
  X: '#607d8b',  // Mixed - blue gray
  P: '#8bc34a',  // Personal - light green
  H: '#607d8b',  // Holy sites - blue gray
  D: '#34495e',  // Digital - dark gray
  N: '#e91e63',  // NGO - pink
  T: '#ff5722',  // Taste/smell - deep orange
}

const TYPE_NAMES: Record<string, string> = {
  G: 'Galerie',
  L: 'Bibliotheek',
  A: 'Archief',
  M: 'Museum',
  O: 'Officieel',
  R: 'Onderzoek',
  C: 'Bedrijf',
  U: 'Onbekend',
  B: 'Botanisch',
  E: 'Onderwijs',
  S: 'Vereniging',
  F: 'Monumenten',
  I: 'Immaterieel',
  X: 'Gemengd',
  P: 'Persoonlijk',
  H: 'Heilige plaatsen',
  D: 'Digitaal',
  N: 'NGO',
  T: 'Smaak/geur',
}

// Map tile styles
const getMapStyle = (isDarkMode: boolean): StyleSpecification => {
  if (isDarkMode) {
    return {
      version: 8,
      sources: {
        'carto-dark': {
          type: 'raster',
          tiles: [
            'https://a.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}@2x.png',
            'https://b.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}@2x.png',
          ],
          tileSize: 256,
          attribution: '&copy; OpenStreetMap &copy; CARTO',
        },
      },
      layers: [
        {
          id: 'carto-dark-tiles',
          type: 'raster',
          source: 'carto-dark',
          minzoom: 0,
          maxzoom: 19,
        },
      ],
    }
  } else {
    return {
      version: 8,
      sources: {
        'osm': {
          type: 'raster',
          tiles: [
            'https://a.tile.openstreetmap.org/{z}/{x}/{y}.png',
            'https://b.tile.openstreetmap.org/{z}/{x}/{y}.png',
          ],
          tileSize: 256,
          attribution: '&copy; OpenStreetMap contributors',
        },
      },
      layers: [
        {
          id: 'osm-tiles',
          type: 'raster',
          source: 'osm',
          minzoom: 0,
          maxzoom: 19,
        },
      ],
    }
  }
}

// Institution interface (matches ChatPage.tsx)
export interface Institution {
  name: string
  type?: string
  city?: string
  country?: string
  description?: string
  website?: string
  latitude?: number
  longitude?: number
  score?: number
}

interface ChatMapPanelProps {
  institutions: Institution[]
  defaultExpanded?: boolean
}

/**
 * Map a type name to single-letter code
 */
function mapTypeNameToCode(typeName?: string): string {
  if (!typeName) return 'U'
  
  const normalized = typeName.toLowerCase()
  
  if (normalized.includes('museum')) return 'M'
  if (normalized.includes('archief') || normalized.includes('archive')) return 'A'
  if (normalized.includes('bibliotheek') || normalized.includes('library')) return 'L'
  if (normalized.includes('galerie') || normalized.includes('gallery')) return 'G'
  if (normalized.includes('universiteit') || normalized.includes('university') || normalized.includes('onderwijs') || normalized.includes('education')) return 'E'
  if (normalized.includes('onderzoek') || normalized.includes('research')) return 'R'
  if (normalized.includes('vereniging') || normalized.includes('society')) return 'S'
  if (normalized.includes('botanisch') || normalized.includes('botanical') || normalized.includes('zoo')) return 'B'
  if (normalized.includes('officieel') || normalized.includes('official')) return 'O'
  if (normalized.includes('bedrijf') || normalized.includes('corporation')) return 'C'
  if (normalized.includes('monument') || normalized.includes('feature')) return 'F'
  if (normalized.includes('immaterieel') || normalized.includes('intangible')) return 'I'
  if (normalized.includes('persoonlijk') || normalized.includes('personal')) return 'P'
  if (normalized.includes('heilig') || normalized.includes('holy') || normalized.includes('kerk')) return 'H'
  if (normalized.includes('digitaal') || normalized.includes('digital')) return 'D'
  if (normalized.includes('ngo')) return 'N'
  if (normalized.includes('smaak') || normalized.includes('taste')) return 'T'
  if (normalized.includes('gemengd') || normalized.includes('mixed')) return 'X'
  
  return 'U'
}

/**
 * Convert institutions to GeoJSON FeatureCollection
 */
function institutionsToGeoJSON(institutions: Institution[]): GeoJSON.FeatureCollection {
  const validInstitutions = institutions.filter(
    inst => inst.latitude != null && inst.longitude != null
  )
  
  return {
    type: 'FeatureCollection',
    features: validInstitutions.map((inst, index) => {
      const typeCode = mapTypeNameToCode(inst.type)
      return {
        type: 'Feature' as const,
        id: index,
        geometry: {
          type: 'Point' as const,
          coordinates: [inst.longitude!, inst.latitude!],
        },
        properties: {
          index,
          name: inst.name,
          type: typeCode,
          typeName: inst.type || '',
          color: TYPE_COLORS[typeCode] || '#9e9e9e',
          city: inst.city || '',
          country: inst.country || '',
          website: inst.website || '',
          description: inst.description || '',
        },
      }
    }),
  }
}

export const ChatMapPanel: React.FC<ChatMapPanelProps> = ({
  institutions,
  defaultExpanded = true,
}) => {
  const mapContainerRef = useRef<HTMLDivElement>(null)
  const mapRef = useRef<maplibregl.Map | null>(null)
  const [mapReady, setMapReady] = useState(false)
  const [expanded, setExpanded] = useState(defaultExpanded)
  const [selectedInstitution, setSelectedInstitution] = useState<Institution | null>(null)
  const [isDarkMode] = useState(() => 
    window.matchMedia?.('(prefers-color-scheme: dark)').matches ?? false
  )

  // Filter institutions with valid coordinates
  const validInstitutions = useMemo(() => 
    institutions.filter(inst => inst.latitude != null && inst.longitude != null),
    [institutions]
  )

  // Convert to GeoJSON
  const geoJSON = useMemo(() => institutionsToGeoJSON(institutions), [institutions])

  // Calculate bounds
  const bounds = useMemo(() => {
    if (validInstitutions.length === 0) return null
    
    const lngs = validInstitutions.map(i => i.longitude!)
    const lats = validInstitutions.map(i => i.latitude!)
    
    return new maplibregl.LngLatBounds(
      [Math.min(...lngs), Math.min(...lats)],
      [Math.max(...lngs), Math.max(...lats)]
    )
  }, [validInstitutions])

  // Initialize map
  useEffect(() => {
    if (!mapContainerRef.current || !expanded || mapRef.current) return

    const map = new maplibregl.Map({
      container: mapContainerRef.current,
      style: getMapStyle(isDarkMode),
      center: bounds ? bounds.getCenter().toArray() as [number, number] : [5.2913, 52.1326],
      zoom: 7,
      attributionControl: true,
    })

    mapRef.current = map

    map.on('load', () => {
      setMapReady(true)

      // Fit to bounds if we have markers
      if (bounds && validInstitutions.length > 1) {
        map.fitBounds(bounds, { padding: 50, maxZoom: 14 })
      } else if (validInstitutions.length === 1) {
        map.setCenter([validInstitutions[0].longitude!, validInstitutions[0].latitude!])
        map.setZoom(12)
      }
    })

    map.addControl(new maplibregl.NavigationControl(), 'top-right')

    return () => {
      map.remove()
      mapRef.current = null
      setMapReady(false)
    }
  }, [expanded])

  // Add/update GeoJSON source and layers
  useEffect(() => {
    if (!mapRef.current || !mapReady) return

    const map = mapRef.current

    const addLayers = () => {
      // Remove existing layers and source if they exist
      if (map.getLayer('institutions-circles')) map.removeLayer('institutions-circles')
      if (map.getLayer('institutions-stroke')) map.removeLayer('institutions-stroke')
      if (map.getSource('institutions')) map.removeSource('institutions')

      // Add source
      map.addSource('institutions', {
        type: 'geojson',
        data: geoJSON,
      })

      // Add circle layer
      map.addLayer({
        id: 'institutions-circles',
        type: 'circle',
        source: 'institutions',
        paint: {
          'circle-radius': 8,
          'circle-color': ['get', 'color'],
          'circle-stroke-width': 2,
          'circle-stroke-color': '#ffffff',
          'circle-opacity': 0.85,
        },
      })

      // Fit bounds
      if (bounds && validInstitutions.length > 1) {
        map.fitBounds(bounds, { padding: 50, maxZoom: 14 })
      }
    }

    if (map.isStyleLoaded()) {
      addLayers()
    } else {
      map.once('style.load', addLayers)
    }
  }, [geoJSON, mapReady, bounds, validInstitutions.length])

  // Handle click events
  useEffect(() => {
    if (!mapRef.current || !mapReady) return

    const map = mapRef.current

    const handleClick = (e: MapLayerMouseEvent) => {
      if (!e.features || e.features.length === 0) return

      const feature = e.features[0]
      const props = feature.properties
      const index = props?.index

      if (index !== undefined && validInstitutions[index]) {
        setSelectedInstitution(validInstitutions[index])
      }
    }

    const handleMouseEnter = () => {
      map.getCanvas().style.cursor = 'pointer'
    }

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

    // Wait for layer to exist
    const bindEvents = () => {
      if (map.getLayer('institutions-circles')) {
        map.on('click', 'institutions-circles', handleClick)
        map.on('mouseenter', 'institutions-circles', handleMouseEnter)
        map.on('mouseleave', 'institutions-circles', handleMouseLeave)
      } else {
        setTimeout(bindEvents, 100)
      }
    }

    bindEvents()

    return () => {
      if (map.getLayer('institutions-circles')) {
        map.off('click', 'institutions-circles', handleClick)
        map.off('mouseenter', 'institutions-circles', handleMouseEnter)
        map.off('mouseleave', 'institutions-circles', handleMouseLeave)
      }
    }
  }, [mapReady, validInstitutions])

  // Don't render if no valid institutions
  if (validInstitutions.length === 0) {
    return null
  }

  // Get unique types for legend
  const uniqueTypes = Array.from(new Set(validInstitutions.map(i => mapTypeNameToCode(i.type))))
    .filter(code => code !== 'U')
    .slice(0, 6)

  return (
    <Paper 
      elevation={1} 
      sx={{ 
        mt: 2, 
        mb: 2, 
        overflow: 'hidden',
        border: `1px solid ${naColors.lightBlue}`,
      }}
    >
      {/* Header - Clickable to expand/collapse */}
      <Box 
        sx={{ 
          display: 'flex', 
          alignItems: 'center', 
          justifyContent: 'space-between',
          px: 2, 
          py: 1,
          bgcolor: naColors.lightBlue,
          cursor: 'pointer',
        }}
        onClick={() => setExpanded(!expanded)}
      >
        <Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
          <MapIcon sx={{ color: naColors.primary }} />
          <Typography variant="subtitle2" sx={{ color: naColors.primary, fontWeight: 600 }}>
            {validInstitutions.length} instelling{validInstitutions.length !== 1 ? 'en' : ''} op de kaart
          </Typography>
        </Box>
        <IconButton size="small" sx={{ color: naColors.primary }}>
          {expanded ? <ExpandLessIcon /> : <ExpandMoreIcon />}
        </IconButton>
      </Box>

      {/* Map Container - Collapsible */}
      <Collapse in={expanded}>
        <Box sx={{ position: 'relative', height: 350 }}>
          <Box
            ref={mapContainerRef}
            sx={{ width: '100%', height: '100%' }}
          />

          {/* Legend */}
          <Paper
            sx={{
              position: 'absolute',
              bottom: 10,
              left: 10,
              p: 1,
              bgcolor: 'rgba(255,255,255,0.9)',
              borderRadius: 1,
              maxWidth: 160,
            }}
            elevation={2}
          >
            <Typography variant="caption" sx={{ fontWeight: 600, display: 'block', mb: 0.5 }}>
              Legenda
            </Typography>
            <Box sx={{ display: 'flex', flexDirection: 'column', gap: 0.25 }}>
              {uniqueTypes.map(code => (
                <Box key={code} sx={{ display: 'flex', alignItems: 'center', gap: 0.5 }}>
                  <Box 
                    sx={{ 
                      width: 10, 
                      height: 10, 
                      borderRadius: '50%', 
                      bgcolor: TYPE_COLORS[code],
                      flexShrink: 0,
                    }} 
                  />
                  <Typography variant="caption" sx={{ fontSize: '0.65rem' }}>
                    {TYPE_NAMES[code]}
                  </Typography>
                </Box>
              ))}
            </Box>
          </Paper>

          {/* Selected Institution Panel */}
          {selectedInstitution && (
            <Paper
              sx={{
                position: 'absolute',
                top: 10,
                right: 10,
                p: 2,
                maxWidth: 280,
                bgcolor: 'rgba(255,255,255,0.95)',
              }}
              elevation={3}
            >
              <Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start' }}>
                <Typography variant="subtitle2" sx={{ fontWeight: 600, color: naColors.primary, pr: 2 }}>
                  {selectedInstitution.name}
                </Typography>
                <IconButton size="small" onClick={() => setSelectedInstitution(null)}>
                  <CloseIcon sx={{ fontSize: 18 }} />
                </IconButton>
              </Box>

              {selectedInstitution.type && (
                <Chip
                  label={selectedInstitution.type}
                  size="small"
                  sx={{
                    mt: 0.5,
                    height: 20,
                    fontSize: '0.7rem',
                    bgcolor: TYPE_COLORS[mapTypeNameToCode(selectedInstitution.type)],
                    color: '#fff',
                  }}
                />
              )}

              {(selectedInstitution.city || selectedInstitution.country) && (
                <Box sx={{ display: 'flex', alignItems: 'center', gap: 0.5, mt: 1 }}>
                  <PlaceIcon sx={{ fontSize: 14, color: 'text.secondary' }} />
                  <Typography variant="caption" color="text.secondary">
                    {[selectedInstitution.city, selectedInstitution.country].filter(Boolean).join(', ')}
                  </Typography>
                </Box>
              )}

              {selectedInstitution.description && (
                <Typography variant="body2" sx={{ mt: 1, fontSize: '0.75rem', lineHeight: 1.4 }}>
                  {selectedInstitution.description.slice(0, 150)}
                  {selectedInstitution.description.length > 150 ? '...' : ''}
                </Typography>
              )}

              {selectedInstitution.website && (
                <Link
                  href={selectedInstitution.website}
                  target="_blank"
                  rel="noopener noreferrer"
                  sx={{
                    display: 'flex',
                    alignItems: 'center',
                    gap: 0.5,
                    mt: 1,
                    fontSize: '0.75rem',
                    color: naColors.primary,
                  }}
                >
                  Website <OpenInNewIcon sx={{ fontSize: 12 }} />
                </Link>
              )}
            </Paper>
          )}
        </Box>
      </Collapse>
    </Paper>
  )
}

export default ChatMapPanel
