import { useState, useEffect, useCallback } from 'react'
import { useTranslation } from 'react-i18next'
import L from 'leaflet'
import { useFlight, ConfirmDialog } from '../../components'
import { api, createSSE, endpoints } from '../../api'
import FlightListSidebar from './FlightListSidebar'
import FlightParamsPanel from './FlightParamsPanel'
import FlightMap from './FlightMap'
import AltitudeDialog from './AltitudeDialog'
import JsonEditorDialog from './JsonEditorDialog'
import GpsDeniedPanel from './GpsDeniedPanel'
import { DRAW_MODES, DRAW_MODE_ACCENT } from './drawModes'
import { newGuid, calculateDistance, calculateAllPoints, parseCoordinates, getMockAircraftParams } from './flightPlanUtils'
import { PURPOSES } from './types'
import type { Aircraft, Waypoint } from '../../types'
import type { FlightPoint, CalculatedPointInfo, MapRectangle, ActionMode, WindParams, AircraftParams, OrthoPhoto } from './types'

const tabStyle = (active: boolean, accentVar: string): React.CSSProperties => ({
  padding: '10px 0', fontSize: 10, letterSpacing: '0.14em', borderBottom: '2px solid',
  color: active ? 'var(--text-primary)' : 'var(--text-secondary)',
  borderColor: active ? accentVar : 'transparent',
  background: active ? 'var(--surface-1)' : 'transparent',
})

export default function FlightsPage() {
  const { t } = useTranslation()
  const { flights, selectedFlight, selectFlight, refreshFlights } = useFlight()

  const [mode, setMode] = useState<'params' | 'gps'>('params')
  const [deleteId, setDeleteId] = useState<string | null>(null)
  const [collapsed, setCollapsed] = useState(false)

  const [aircrafts, setAircrafts] = useState<Aircraft[]>([])
  const [liveGps, setLiveGps] = useState<{ lat: number; lon: number; satellites: number; status: string } | null>(null)

  const [aircraft, setAircraft] = useState<AircraftParams | null>(null)
  const [points, setPoints] = useState<FlightPoint[]>([])
  const [calculatedPointInfo, setCalculatedPointInfo] = useState<CalculatedPointInfo[]>([])
  const [rectangles, setRectangles] = useState<MapRectangle[]>([])
  const [actionMode, setActionMode] = useState<ActionMode>('points')
  const [wind, setWind] = useState<WindParams>({ direction: 0, speed: 0 })
  const [initialAltitude, setInitialAltitude] = useState(1000)
  const [currentPosition, setCurrentPosition] = useState<{ lat: number; lng: number }>({ lat: 47.242, lng: 35.024 })
  const [locationInput, setLocationInput] = useState('')

  const [altDialog, setAltDialog] = useState<{ open: boolean; point: FlightPoint | null; isEdit: boolean }>({ open: false, point: null, isEdit: false })
  const [jsonDialog, setJsonDialog] = useState({ open: false, text: '' })
  const [orthophotos, setOrthophotos] = useState<OrthoPhoto[]>([])

  const handleApplyCorrection = useCallback((waypointNumber: number, lat: number, lon: number) => {
    const idx = waypointNumber - 1
    setPoints(prev => (idx < 0 || idx >= prev.length)
      ? prev
      : prev.map((p, i) => i === idx ? { ...p, position: { lat, lng: lon } } : p))
  }, [])

  useEffect(() => {
    api.get<Aircraft[]>(endpoints.flights.aircrafts()).then(setAircrafts).catch(() => {})
    setAircraft(getMockAircraftParams())
    navigator.geolocation.getCurrentPosition(
      (pos) => setCurrentPosition({ lat: pos.coords.latitude, lng: pos.coords.longitude }),
      () => {},
    )
  }, [])

  useEffect(() => {
    setLiveGps(null) // drop the previous flight's GPS readout until the new stream sends a fix
    if (!selectedFlight) { setPoints([]); return }
    api.get<Waypoint[]>(endpoints.flights.flightWaypoints(selectedFlight.id))
      .then(wps => {
        setPoints(wps.sort((a, b) => a.order - b.order).map(wp => ({
          id: wp.id,
          position: { lat: wp.latitude, lng: wp.longitude },
          altitude: 300,
          meta: [PURPOSES[0].value, PURPOSES[1].value],
        })))
      })
      .catch(() => {})
  }, [selectedFlight])

  useEffect(() => {
    if (!selectedFlight || mode !== 'gps') return
    return createSSE<{ lat: number; lon: number; satellites: number; status: string }>(endpoints.flights.flightLiveGps(selectedFlight.id), (data) => setLiveGps(data))
  }, [selectedFlight, mode])

  useEffect(() => {
    if (!aircraft || points.length < 2) { setCalculatedPointInfo([{ bat: 100, time: 0 }]); return }
    calculateAllPoints(points, aircraft, initialAltitude).then(setCalculatedPointInfo)
  }, [points, aircraft, initialAltitude])

  const handleCreateFlight = async (name: string) => {
    await api.post(endpoints.flights.collection(), { name })
    refreshFlights()
  }
  const handleDeleteFlight = async () => {
    if (!deleteId) return
    await api.delete(endpoints.flights.flight(deleteId))
    if (selectedFlight?.id === deleteId) selectFlight(null)
    setDeleteId(null)
    refreshFlights()
  }

  const addPoint = useCallback((lat: number, lng: number) => {
    const pt: FlightPoint = { id: newGuid(), position: { lat, lng }, altitude: initialAltitude, meta: [PURPOSES[0].value, PURPOSES[1].value] }
    setPoints(prev => [...prev, pt])
  }, [initialAltitude])

  const updatePointPosition = useCallback((index: number, pos: { lat: number; lng: number }) => {
    setPoints(prev => prev.map((p, i) => i === index ? { ...p, position: pos } : p))
  }, [])

  const removePoint = useCallback((id: string) => {
    setPoints(prev => prev.filter(p => p.id !== id))
  }, [])

  const handlePolylineClick = useCallback((e: L.LeafletMouseEvent) => {
    const click = e.latlng
    let closestIdx = -1, minDist = Infinity
    points.forEach((p, i) => {
      if (i < points.length - 1) {
        const dist = L.LineUtil.pointToSegmentDistance(
          L.point(click.lng, click.lat),
          L.point(p.position.lng, p.position.lat),
          L.point(points[i + 1].position.lng, points[i + 1].position.lat),
        )
        if (dist < minDist) { minDist = dist; closestIdx = i }
      }
    })
    if (closestIdx !== -1) {
      const alt = (points[closestIdx].altitude + points[closestIdx + 1].altitude) / 2
      const pt: FlightPoint = { id: newGuid(), position: { lat: click.lat, lng: click.lng }, altitude: alt, meta: [PURPOSES[0].value, PURPOSES[1].value] }
      setPoints(prev => { const u = [...prev]; u.splice(closestIdx + 1, 0, pt); return u })
    }
  }, [points])

  const openEditDialog = (point: FlightPoint) => {
    setAltDialog({ open: true, point: { ...point }, isEdit: true })
  }
  const handleAltSubmit = () => {
    if (!altDialog.point) return
    if (altDialog.isEdit) {
      setPoints(prev => prev.map(p => p.id === altDialog.point!.id ? altDialog.point! : p))
    } else {
      setPoints(prev => [...prev, altDialog.point!])
    }
    setAltDialog({ open: false, point: null, isEdit: false })
  }

  const buildFlightPlanData = () => ({
    operational_height: { currentAltitude: initialAltitude },
    geofences: { polygons: rectangles.map(r => {
      const sw = r.bounds.getSouthWest(), ne = r.bounds.getNorthEast()
      return { northWest: { lat: ne.lat, lon: sw.lng }, southEast: { lat: sw.lat, lon: ne.lng }, fence_type: r.color === 'red' ? 'EXCLUSION' : 'INCLUSION' }
    })},
    action_points: points.map(p => ({ point: { lat: p.position.lat, lon: p.position.lng }, height: p.altitude, action: 'search', action_specific: { targets: p.meta } })),
  })

  const handleEditJson = () => {
    setJsonDialog({ open: true, text: JSON.stringify(buildFlightPlanData(), null, 2) })
  }

  const handleExport = () => {
    const blob = new Blob([JSON.stringify(buildFlightPlanData(), null, 2)], { type: 'application/json' })
    const url = URL.createObjectURL(blob)
    const a = document.createElement('a')
    a.href = url
    a.download = `${selectedFlight?.name ?? 'flight-plan'}.json`
    a.click()
    URL.revokeObjectURL(url)
  }

  const handleImport = () => {
    const input = document.createElement('input')
    input.type = 'file'
    input.accept = 'application/json'
    input.onchange = async (e) => {
      const file = (e.target as HTMLInputElement).files?.[0]
      if (!file) return
      const text = await file.text()
      handleJsonSave(text)
    }
    input.click()
  }

  const handleJsonSave = (json: string) => {
    try {
      const data = JSON.parse(json)
      if (data.action_points) {
        setPoints(data.action_points.map((ap: Record<string, unknown>) => ({
          id: newGuid(),
          position: {
            lat: (ap.point as Record<string, number>)?.lat ?? (ap.lat as number),
            lng: (ap.point as Record<string, number>)?.lon ?? (ap.lon as number),
          },
          altitude: (ap.height as number) || 300,
          meta: (ap.action_specific as Record<string, string[]>)?.targets || [PURPOSES[0].value, PURPOSES[1].value],
        })))
      }
      if (data.geofences?.polygons) {
        setRectangles(data.geofences.polygons.map((p: { southEast: { lat: number; lon: number }; northWest: { lat: number; lon: number }; fence_type?: string }) => ({
          id: newGuid(),
          bounds: L.latLngBounds([p.southEast.lat, p.northWest.lon], [p.northWest.lat, p.southEast.lon]),
          color: p.fence_type === 'EXCLUSION' ? 'red' as const : 'green' as const,
        })))
      }
      if (data.operational_height?.currentAltitude) setInitialAltitude(data.operational_height.currentAltitude)
      setJsonDialog({ open: false, text: '' })
    } catch { alert(t('flights.planner.invalidJson')) }
  }

  const handleSave = async () => {
    if (!selectedFlight) return
    const existing = await api.get<Waypoint[]>(endpoints.flights.flightWaypoints(selectedFlight.id)).catch(() => [] as Waypoint[])
    for (const wp of existing) {
      await api.delete(endpoints.flights.flightWaypoint(selectedFlight.id, wp.id)).catch(() => {})
    }
    for (let i = 0; i < points.length; i++) {
      await api.post(endpoints.flights.flightWaypoints(selectedFlight.id), {
        name: `Point ${i + 1}`,
        latitude: points[i].position.lat,
        longitude: points[i].position.lng,
        order: i,
      }).catch(() => {})
    }
  }

  const handleLocationSearch = () => {
    const coords = parseCoordinates(locationInput)
    if (coords) setCurrentPosition(coords)
  }

  const lastInfo = calculatedPointInfo[calculatedPointInfo.length - 1]
  const batteryStatus = !lastInfo ? { label: '', color: '#6c757d' }
    : lastInfo.bat > 12 ? { label: t('flights.planner.statusGood'), color: '#40c057' }
    : lastInfo.bat > 5 ? { label: t('flights.planner.statusCaution'), color: '#FFFF00' }
    : { label: t('flights.planner.statusLow'), color: '#fa5252' }

  const totalDist = aircraft && points.length > 1
    ? points.reduce((acc, p, i) => i === 0 ? 0 : acc + calculateDistance(points[i - 1], p, aircraft.type, initialAltitude, aircraft.downang, aircraft.upang), 0).toFixed(1) + t('flights.planner.km')
    : ''
  const totalTimeStr = lastInfo && lastInfo.time > 0
    ? `${Math.floor(lastInfo.time) >= 1 ? Math.floor(lastInfo.time) + t('flights.planner.hour') : ''}${Math.floor((lastInfo.time - Math.floor(lastInfo.time)) * 60)}${t('flights.planner.minutes')}`
    : ''

  return (
    <div className="flex h-full">
      <FlightListSidebar
        flights={flights}
        selectedFlight={selectedFlight}
        onSelect={selectFlight}
        onCreate={handleCreateFlight}
        onDelete={(id) => setDeleteId(id)}
      />

      {collapsed ? (
        <div className="shrink-0 flex flex-col items-center gap-2 border-r border-border-hair"
          style={{ width: 44, background: 'var(--surface-1)', padding: '10px 6px' }}>
          <button onClick={() => setCollapsed(false)} title={t('flights.v2.expandParams')}
            className="ibtn mono" style={{ width: 32, height: 32 }}>&#187;</button>
          <span className="block" style={{ width: 24, height: 1, background: 'var(--border-hair)' }} />
          {DRAW_MODES.map(({ mode: m, i18nKey, accent, icon }) => {
            const active = actionMode === m
            const { color, tint } = DRAW_MODE_ACCENT[accent]
            return (
              <button key={m} onClick={() => setActionMode(m)} title={t(i18nKey)} className="mono"
                style={{
                  width: 32, height: 32, display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
                  border: `1px solid ${color}`, color, borderRadius: 2, cursor: 'pointer',
                  background: active ? tint : 'transparent',
                  boxShadow: active ? `inset 0 0 0 1px ${color}` : 'none',
                }}>
                {icon}
              </button>
            )
          })}
        </div>
      ) : (
        <div className="shrink-0 flex flex-col overflow-y-auto border-r border-border-hair"
          style={{ width: 290, background: 'var(--surface-1)' }}>
          <div className="flex items-stretch border-b border-border-hair" style={{ background: 'var(--surface-0)' }}>
            <button onClick={() => setMode('params')}
              className="flex-1 mono uppercase"
              style={tabStyle(mode === 'params', 'var(--accent-amber)')}>
              {t('flights.v2.flightParams')}
            </button>
            <button onClick={() => setMode('gps')}
              className="flex-1 mono uppercase"
              style={tabStyle(mode === 'gps', 'var(--accent-red)')}>
              {t('flights.v2.gpsDenied')}
            </button>
            <button onClick={() => setCollapsed(true)} title={t('flights.v2.collapse')}
              className="ibtn mono shrink-0 self-center mx-1" style={{ width: 26, height: 26 }}>&#171;</button>
          </div>

          {mode === 'params' && (
            <FlightParamsPanel
              points={points} calculatedPointInfo={calculatedPointInfo} aircrafts={aircrafts}
              initialAltitude={initialAltitude} actionMode={actionMode}
              wind={wind} locationInput={locationInput} currentPosition={currentPosition}
              totalDistance={totalDist} totalTime={totalTimeStr} batteryStatus={batteryStatus}
              onInitialAltitudeChange={setInitialAltitude} onActionModeChange={setActionMode}
              onWindChange={setWind} onLocationInputChange={setLocationInput}
              onLocationSearch={handleLocationSearch}
              onReorderPoints={setPoints} onEditPoint={openEditDialog} onRemovePoint={removePoint}
              onSave={handleSave} onUpload={handleImport} onEditJson={handleEditJson} onExport={handleExport}
            />
          )}

          {mode === 'gps' && (
            <GpsDeniedPanel
              liveGps={liveGps}
              orthophotos={orthophotos}
              onAddOrthophotos={(photos) => setOrthophotos(prev => [...prev, ...photos])}
              onApplyCorrection={handleApplyCorrection}
              onBack={() => setMode('params')}
            />
          )}
        </div>
      )}

      <FlightMap
        points={points} calculatedPointInfo={calculatedPointInfo}
        currentPosition={currentPosition} rectangles={rectangles} setRectangles={setRectangles}
        rectangleColor={actionMode === 'workArea' ? 'green' : 'red'}
        actionMode={actionMode}
        onAddPoint={addPoint} onUpdatePoint={updatePointPosition} onRemovePoint={removePoint}
        onAltitudeChange={(i, alt) => setPoints(prev => prev.map((p, idx) => idx === i ? { ...p, altitude: alt } : p))}
        onMetaChange={(i, meta) => setPoints(prev => prev.map((p, idx) => idx === i ? { ...p, meta } : p))}
        onPolylineClick={handlePolylineClick}
        onPositionChange={setCurrentPosition}
        onMapMove={() => {}}
        liveGps={liveGps}
        flightLabel={selectedFlight?.name ?? '—'}
      />

      <AltitudeDialog
        open={altDialog.open}
        isEditMode={altDialog.isEdit}
        latitude={altDialog.point?.position.lat ?? 0}
        longitude={altDialog.point?.position.lng ?? 0}
        altitude={altDialog.point?.altitude ?? 300}
        meta={altDialog.point?.meta ?? []}
        onLatitudeChange={v => setAltDialog(prev => ({ ...prev, point: prev.point ? { ...prev.point, position: { ...prev.point.position, lat: v } } : null }))}
        onLongitudeChange={v => setAltDialog(prev => ({ ...prev, point: prev.point ? { ...prev.point, position: { ...prev.point.position, lng: v } } : null }))}
        onAltitudeChange={v => setAltDialog(prev => ({ ...prev, point: prev.point ? { ...prev.point, altitude: v } : null }))}
        onMetaChange={v => setAltDialog(prev => ({ ...prev, point: prev.point ? { ...prev.point, meta: v } : null }))}
        onSubmit={handleAltSubmit}
        onClose={() => setAltDialog({ open: false, point: null, isEdit: false })}
      />

      <JsonEditorDialog
        open={jsonDialog.open}
        jsonText={jsonDialog.text}
        onClose={() => setJsonDialog({ open: false, text: '' })}
        onSave={handleJsonSave}
      />

      <ConfirmDialog
        open={!!deleteId}
        title={t('common.delete')}
        message="Delete this flight and all its data?"
        onConfirm={handleDeleteFlight}
        onCancel={() => setDeleteId(null)}
      />
    </div>
  )
}
