'use client'

import { useEffect, useRef, useCallback } from 'react'
import type L from 'leaflet'
import 'leaflet/dist/leaflet.css'
import 'leaflet-draw/dist/leaflet.draw.css'
import type { Feature, Polygon } from 'geojson'
import { createZonedGrid } from './cropZoningUtils'
import { CROP_COLORS, type CropType, type LayerType, type ZoneFeatureProperties } from './cropZoningTypes'

export type MapDrawGeoJSON = Record<string, unknown> | null

type CropZoningMapProps = {
  center?: [number, number]
  zoom?: number
  height?: string | number
  activeLayer: LayerType
  onAreaChange?: (geojson: MapDrawGeoJSON) => void
  onZoneClick?: (zone: ZoneFeatureProperties) => void
  optimizationKey?: number
  className?: string
  /** منطقهٔ اولیه از دیتای ماک؛ وقتی مقدار دارد نقشه فقط نمایشی است و کاربر نمیتواند منطقه را تغییر دهد */
  initialAreaGeoJson?: MapDrawGeoJSON | null
  /** غیرفعال کردن رسم و ویرایش منطقه توسط کاربر */
  readOnly?: boolean
}

export default function CropZoningMap({
  center = [35.6892, 51.389],
  zoom = 13,
  height = '100%',
  activeLayer,
  onAreaChange,
  onZoneClick,
  optimizationKey = 0,
  className = '',
  initialAreaGeoJson = null,
  readOnly = false
}: CropZoningMapProps) {
  const mapRef = useRef<HTMLDivElement>(null)
  const mapInstanceRef = useRef<L.Map | null>(null)
  const drawnItemsRef = useRef<L.FeatureGroup | null>(null)
  const drawControlRef = useRef<L.Control.Draw | null>(null)
  const zonesLayerRef = useRef<L.GeoJSON | null>(null)

  const renderZones = useCallback(
    (map: L.Map, polygonFeature: Feature<Polygon>) => {
      if (zonesLayerRef.current) {
        map.removeLayer(zonesLayerRef.current)
        zonesLayerRef.current = null
      }

      const grid = createZonedGrid(polygonFeature)
      const L = (window as unknown as { L: typeof import('leaflet') }).L
      if (!L) return

      const geoJsonLayer = L.geoJSON(grid as never, {
        style: (feature?: { properties?: ZoneFeatureProperties }) => {
          const props = feature?.properties
          if (!props || activeLayer !== 'crops') {
            return { fillColor: '#94a3b8', fillOpacity: 0.5, weight: 1, color: '#fff' }
          }
          return {
            fillColor: CROP_COLORS[props.crop as CropType],
            fillOpacity: 0.5,
            weight: 1,
            color: '#fff'
          }
        },
        onEachFeature: (feature: { properties?: ZoneFeatureProperties }, leafLayer: L.Layer) => {
          const props = feature?.properties
          if (!props) return
          const layer = leafLayer as L.Polygon
          const cropLabel = props.crop === 'wheat' ? 'گندم' : props.crop === 'canola' ? 'کلزا' : 'زعفران'
          const tooltipContent = `
            <div style="font-family: inherit; font-size: 12px; padding: 4px 8px; min-width: 160px;">
              <div style="font-weight: 600; margin-bottom: 6px;">${cropLabel}</div>
              <div>درصد تطابق: ${props.matchPercent}%</div>
              <div>نیاز آب: ${props.waterNeed}</div>
              <div>سود تخمینی: ${props.estimatedProfit}</div>
            </div>
          `
          layer.bindTooltip(tooltipContent, {
            sticky: true,
            className: 'zone-tooltip',
            direction: 'top',
            offset: [0, -8]
          })
          layer.on('click', () => onZoneClick?.(props))
        }
      })

      geoJsonLayer.addTo(map)
      zonesLayerRef.current = geoJsonLayer

      let idx = 0
      geoJsonLayer.eachLayer((layer: L.Layer) => {
        const leafLayer = layer as L.Polygon
        leafLayer.setStyle({ fillOpacity: 0 })
        const index = idx++
        const targetOpacity = 0.5
        const delay = Math.min(index * 30, 600)
        setTimeout(() => {
          leafLayer.setStyle({ fillOpacity: targetOpacity })
        }, delay)
      })
    },
    [activeLayer, onZoneClick]
  )

  useEffect(() => {
    if (typeof window === 'undefined' || !mapRef.current) return

    let isMounted = true
    let cleanupFn: (() => void) | null = null

    const initMap = async () => {
      const L = (await import('leaflet')).default
      await import('leaflet-draw')
      ;(window as unknown as { L: typeof L }).L = L

      if (!isMounted || !mapRef.current || mapInstanceRef.current) return

      const map = L.map(mapRef.current).setView(center, zoom)

      L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
        attribution: '© OpenStreetMap'
      }).addTo(map)

      const drawnItems = L.featureGroup().addTo(map)
      drawnItemsRef.current = drawnItems

      if (!readOnly) {
        const drawControl = new L.Control.Draw({
          position: 'topright',
          draw: {
            polygon: { shapeOptions: { color: '#3388ff' } },
            rectangle: { shapeOptions: { color: '#3388ff' } },
            circle: false,
            circlemarker: false,
            marker: false,
            polyline: false
          },
          edit: { featureGroup: drawnItems, remove: true }
        })
        map.addControl(drawControl)
        drawControlRef.current = drawControl
      }

      const getGeoJsonFromDrawn = (): MapDrawGeoJSON => {
        const geojson = drawnItems.toGeoJSON()
        if (geojson.type === 'FeatureCollection' && geojson.features.length > 0) {
          return geojson.features[0] as unknown as MapDrawGeoJSON
        }
        return null
      }

      const emitAndRender = () => {
        const geojson = getGeoJsonFromDrawn()
        onAreaChange?.(geojson)
        if (geojson && geojson.geometry && (geojson.geometry as { type: string }).type === 'Polygon') {
          renderZones(map, geojson as Feature<Polygon>)
        } else if (zonesLayerRef.current) {
          map.removeLayer(zonesLayerRef.current)
          zonesLayerRef.current = null
        }
      }

      if (readOnly && initialAreaGeoJson && initialAreaGeoJson.geometry && (initialAreaGeoJson.geometry as { type: string }).type === 'Polygon') {
        drawnItems.clearLayers()
        L.geoJSON(initialAreaGeoJson as Feature<Polygon>).eachLayer((layer) => drawnItems.addLayer(layer))
        emitAndRender()
      }

      const onCreated = (e: L.LeafletEvent) => {
        const event = e as L.DrawEvents.Created
        drawnItems.clearLayers()
        drawnItems.addLayer(event.layer)
        emitAndRender()
      }

      const onEdited = () => emitAndRender()
      const onDeleted = () => {
        onAreaChange?.(null)
        if (zonesLayerRef.current) {
          map.removeLayer(zonesLayerRef.current)
          zonesLayerRef.current = null
        }
      }

      if (!readOnly) {
        map.on(L.Draw.Event.CREATED, onCreated)
        map.on(L.Draw.Event.EDITED, onEdited)
        map.on(L.Draw.Event.DELETED, onDeleted)
      }

      mapInstanceRef.current = map

      cleanupFn = () => {
        if (!readOnly) {
          map.off(L.Draw.Event.CREATED, onCreated)
          map.off(L.Draw.Event.EDITED, onEdited)
          map.off(L.Draw.Event.DELETED, onDeleted)
          if (drawControlRef.current) {
            map.removeControl(drawControlRef.current)
          }
        }
        if (zonesLayerRef.current) map.removeLayer(zonesLayerRef.current)
        map.remove()
        mapInstanceRef.current = null
        drawnItemsRef.current = null
        drawControlRef.current = null
        zonesLayerRef.current = null
      }
    }

    initMap()

    return () => {
      isMounted = false
      if (cleanupFn) cleanupFn()
    }
  }, [])

  useEffect(() => {
    if (!mapInstanceRef.current || !drawnItemsRef.current || optimizationKey === 0) return
    const geojson = drawnItemsRef.current.toGeoJSON()
    if (geojson.type === 'FeatureCollection' && geojson.features.length > 0) {
      const feature = geojson.features[0] as Feature<Polygon>
      renderZones(mapInstanceRef.current, feature)
    }
  }, [optimizationKey, activeLayer, renderZones])

  useEffect(() => {
    const zonesLayer = zonesLayerRef.current
    if (!zonesLayer || !drawnItemsRef.current) return
    const geojson = drawnItemsRef.current.toGeoJSON()
    if (geojson.type !== 'FeatureCollection' || geojson.features.length === 0) return
    zonesLayer.eachLayer((layer: L.Layer) => {
      const leafLayer = layer as L.Polygon & { feature?: { properties: ZoneFeatureProperties } }
      const props = leafLayer.feature?.properties
      if (!props) return
      leafLayer.setStyle({
        fillColor: activeLayer === 'crops' ? CROP_COLORS[props.crop as CropType] : '#94a3b8',
        fillOpacity: 0.5,
        weight: 1,
        color: '#fff'
      })
    })
  }, [activeLayer])

  return (
    <div
      ref={mapRef}
      style={{
        height: typeof height === 'number' ? `${height}px` : height,
        width: '100%',
        borderRadius: 12
      }}
      className={`overflow-hidden ${className}`}
    />
  )
}
