import { useState, useRef, useEffect } from 'react'
import { ComboBox } from '@common/components/ui/ComboBox'
import type { PredictionModel } from './OilSpillView'
import { analyzeImage } from '../services/predictionApi'
import type { ImageAnalyzeResult } from '../services/predictionApi'

interface PredictionInputSectionProps {
  expanded: boolean
  onToggle: () => void
  accidentTime: string
  onAccidentTimeChange: (time: string) => void
  incidentCoord: { lon: number; lat: number } | null
  onCoordChange: (coord: { lon: number; lat: number }) => void
  isSelectingLocation: boolean
  onMapSelectClick: () => void
  onRunSimulation: () => void
  isRunningSimulation: boolean
  selectedModels: Set<PredictionModel>
  onModelsChange: (models: Set<PredictionModel>) => void
  visibleModels?: Set<PredictionModel>
  onVisibleModelsChange?: (models: Set<PredictionModel>) => void
  hasResults?: boolean
  predictionTime: number
  onPredictionTimeChange: (time: number) => void
  spillType: string
  onSpillTypeChange: (type: string) => void
  oilType: string
  onOilTypeChange: (type: string) => void
  spillAmount: number
  onSpillAmountChange: (amount: number) => void
  incidentName: string
  onIncidentNameChange: (name: string) => void
  spillUnit: string
  onSpillUnitChange: (unit: string) => void
  onImageAnalysisResult?: (result: ImageAnalyzeResult) => void
}

const PredictionInputSection = ({
  expanded,
  onToggle,
  accidentTime,
  onAccidentTimeChange,
  incidentCoord,
  onCoordChange,
  isSelectingLocation,
  onMapSelectClick,
  onRunSimulation,
  isRunningSimulation,
  selectedModels,
  onModelsChange,
  onVisibleModelsChange,
  hasResults,
  predictionTime,
  onPredictionTimeChange,
  spillType,
  onSpillTypeChange,
  oilType,
  onOilTypeChange,
  spillAmount,
  onSpillAmountChange,
  incidentName,
  onIncidentNameChange,
  spillUnit,
  onSpillUnitChange,
  onImageAnalysisResult,
}: PredictionInputSectionProps) => {
  const [inputMode, setInputMode] = useState<'direct' | 'upload'>('direct')
  const [uploadedFile, setUploadedFile] = useState<File | null>(null)
  const [isAnalyzing, setIsAnalyzing] = useState(false)
  const [analyzeError, setAnalyzeError] = useState<string | null>(null)
  const [analyzeResult, setAnalyzeResult] = useState<ImageAnalyzeResult | null>(null)
  const fileInputRef = useRef<HTMLInputElement>(null)

  const handleFileSelect = (e: React.ChangeEvent<HTMLInputElement>) => {
    const file = e.target.files?.[0] ?? null
    setUploadedFile(file)
    setAnalyzeError(null)
    setAnalyzeResult(null)
  }

  const handleRemoveFile = () => {
    setUploadedFile(null)
    setAnalyzeError(null)
    setAnalyzeResult(null)
    if (fileInputRef.current) fileInputRef.current.value = ''
  }

  const handleAnalyze = async () => {
    if (!uploadedFile) return
    setIsAnalyzing(true)
    setAnalyzeError(null)
    try {
      const result = await analyzeImage(uploadedFile)
      setAnalyzeResult(result)
      onImageAnalysisResult?.(result)
    } catch (err: unknown) {
      if (err && typeof err === 'object' && 'response' in err) {
        const res = (err as { response?: { data?: { error?: string } } }).response
        if (res?.data?.error === 'GPS_NOT_FOUND') {
          setAnalyzeError('GPS 정보가 없는 이미지입니다')
          return
        }
        if (res?.data?.error === 'TIMEOUT') {
          setAnalyzeError('분석 서버 응답 없음 (시간 초과)')
          return
        }
      }
      setAnalyzeError('이미지 분석 중 오류가 발생했습니다')
    } finally {
      setIsAnalyzing(false)
    }
  }

  return (
    <div className="border-b border-border">
      <div
        onClick={onToggle}
        className="flex items-center justify-between p-4 cursor-pointer hover:bg-[rgba(255,255,255,0.02)]"
      >
        <h3 className="text-[13px] font-bold text-text-2 font-korean">
          예측정보 입력
        </h3>
        <span className="text-[10px] text-text-3">
          {expanded ? '▼' : '▶'}
        </span>
      </div>

      {expanded && (
        <div className="px-4 pb-4 flex flex-col gap-[6px]">
          {/* Input Mode Selection */}
          <div className="flex items-center gap-[10px] text-[11px]">
            <label className="flex items-center gap-[3px] cursor-pointer">
              <input
                type="radio"
                name="prdType"
                checked={inputMode === 'direct'}
                onChange={() => setInputMode('direct')}
                className="accent-[var(--cyan)] m-0 w-[11px] h-[11px]"
              />
              직접 입력
            </label>
            <label className="flex items-center gap-[3px] cursor-pointer">
              <input
                type="radio"
                name="prdType"
                checked={inputMode === 'upload'}
                onChange={() => setInputMode('upload')}
                className="accent-[var(--cyan)] m-0 w-[11px] h-[11px]"
              />
              이미지 업로드
            </label>
          </div>

          {/* Direct Input Mode */}
          {inputMode === 'direct' && (
            <>
              <input
                className="prd-i"
                placeholder="사고명 직접 입력"
                value={incidentName}
                onChange={(e) => onIncidentNameChange(e.target.value)}
              />
              <input className="prd-i" placeholder="또는 사고 리스트에서 선택" readOnly />
            </>
          )}

          {/* Image Upload Mode */}
          {inputMode === 'upload' && (
            <>
              {/* 파일 선택 영역 */}
              {!uploadedFile ? (
                <label
                  className="flex items-center justify-center text-[11px] text-text-3 cursor-pointer"
                  style={{
                    padding: '20px',
                    background: 'var(--bg0)',
                    border: '2px dashed var(--bd)',
                    borderRadius: 'var(--rS)',
                    transition: '0.15s',
                  }}
                  onMouseEnter={(e) => {
                    e.currentTarget.style.borderColor = 'var(--cyan)'
                    e.currentTarget.style.background = 'rgba(6,182,212,0.05)'
                  }}
                  onMouseLeave={(e) => {
                    e.currentTarget.style.borderColor = 'var(--bd)'
                    e.currentTarget.style.background = 'var(--bg0)'
                  }}
                >
                  📁 이미지 파일을 선택하세요
                  <input
                    ref={fileInputRef}
                    type="file"
                    accept="image/*"
                    onChange={handleFileSelect}
                    className="hidden"
                  />
                </label>
              ) : (
                <div
                  className="flex items-center justify-between font-mono text-[10px] bg-bg-0 border border-border"
                  style={{ padding: '8px 10px', borderRadius: 'var(--rS)' }}
                >
                  <span className="text-text-2">📄 {uploadedFile.name}</span>
                  <button
                    onClick={handleRemoveFile}
                    className="text-[10px] text-text-3 bg-transparent border-none cursor-pointer"
                    style={{ padding: '2px 6px', transition: '0.15s' }}
                    onMouseEnter={(e) => { e.currentTarget.style.color = 'var(--red)' }}
                    onMouseLeave={(e) => { e.currentTarget.style.color = 'var(--t3)' }}
                  >
                    ✕
                  </button>
                </div>
              )}

              {/* 분석 실행 버튼 */}
              <button
                className="prd-btn pri"
                style={{ padding: '7px', fontSize: '11px' }}
                onClick={handleAnalyze}
                disabled={!uploadedFile || isAnalyzing}
              >
                {isAnalyzing ? '⏳ 분석 중...' : '🔍 이미지 분석 실행'}
              </button>

              {/* 에러 메시지 */}
              {analyzeError && (
                <div
                  className="text-[10px] font-semibold"
                  style={{
                    padding: '6px 8px',
                    background: 'rgba(239,68,68,0.1)',
                    border: '1px solid rgba(239,68,68,0.3)',
                    borderRadius: 'var(--rS)',
                    color: 'var(--red)',
                  }}
                >
                  ⚠ {analyzeError}
                </div>
              )}

              {/* 분석 완료 메시지 */}
              {analyzeResult && (
                <div
                  className="text-[10px] font-semibold"
                  style={{
                    padding: '6px 8px',
                    background: 'rgba(34,197,94,0.1)',
                    border: '1px solid rgba(34,197,94,0.3)',
                    borderRadius: 'var(--rS)',
                    color: '#22c55e',
                    lineHeight: 1.6,
                  }}
                >
                  ✓ 분석 완료<br />
                  <span className="font-normal text-text-3">
                    위도 {analyzeResult.lat.toFixed(4)} / 경도 {analyzeResult.lon.toFixed(4)}<br />
                    유종: {analyzeResult.oilType} / 면적: {analyzeResult.area.toFixed(1)} m²
                  </span>
                </div>
              )}
            </>
          )}

          {/* 사고 발생 시각 */}
          <div className="flex flex-col gap-0.5">
            <label className="text-[9px] text-text-3 font-korean">사고 발생 시각 (KST)</label>
            <DateTimeInput
              value={accidentTime}
              onChange={onAccidentTimeChange}
            />
          </div>

          {/* Coordinates (DMS) + Map Button */}
          <div className="flex flex-col gap-1">
            <div className="grid grid-cols-[1fr_auto] gap-x-1 gap-y-1">
              <DmsCoordInput
                label="위도"
                isLatitude={true}
                decimal={incidentCoord?.lat ?? 0}
                onChange={(val) => onCoordChange({ lon: incidentCoord?.lon ?? 0, lat: val })}
              />
              <button
                className={`prd-map-btn${isSelectingLocation ? ' active' : ''}`}
                onClick={onMapSelectClick}
                style={{ gridRow: '1 / 3', gridColumn: 2, whiteSpace: 'nowrap', height: '100%', minWidth: 48, padding: '0 10px' }}
              >📍<br/>지도</button>
              <DmsCoordInput
                label="경도"
                isLatitude={false}
                decimal={incidentCoord?.lon ?? 0}
                onChange={(val) => onCoordChange({ lat: incidentCoord?.lat ?? 0, lon: val })}
              />
            </div>
          </div>

          {/* Oil Type + Oil Kind */}
          <div className="grid grid-cols-2 gap-1">
            <ComboBox
              className="prd-i"
              value={spillType}
              onChange={onSpillTypeChange}
              options={[
                { value: '연속', label: '연속' },
                { value: '비연속', label: '비연속' },
                { value: '순간 유출', label: '순간 유출' }
              ]}
            />
            <ComboBox
              className="prd-i"
              value={oilType}
              onChange={onOilTypeChange}
              options={[
                { value: '벙커C유', label: '벙커C유' },
                { value: '경유', label: '경유' },
                { value: '원유', label: '원유' },
                { value: '중유', label: '중유' },
                { value: '등유', label: '등유' },
                { value: '휘발유', label: '휘발유' }
              ]}
            />
          </div>

          {/* Volume + Unit + Duration */}
          <div className="grid items-center gap-1" style={{ gridTemplateColumns: '1fr 65px 1fr' }}>
            <input
              className="prd-i"
              placeholder="유출량"
              type="number"
              min="1"
              step="1"
              value={spillAmount}
              onChange={(e) => onSpillAmountChange(parseInt(e.target.value) || 0)}
            />
            <ComboBox
              className="prd-i"
              value={spillUnit}
              onChange={onSpillUnitChange}
              options={[
                { value: 'kL', label: 'kL' },
                { value: 'ton', label: 'Ton' },
                { value: 'barrel', label: '배럴' }
              ]}
            />
            <ComboBox
              className="prd-i"
              value={predictionTime}
              onChange={(v) => onPredictionTimeChange(parseInt(v))}
              options={[
                { value: '6', label: '6시간' },
                { value: '12', label: '12시간' },
                { value: '24', label: '24시간' },
                { value: '48', label: '48시간' },
                { value: '72', label: '72시간' }
              ]}
            />
          </div>

          {/* Divider */}
          <div className="h-px bg-border my-0.5" />

          {/* Model Selection (다중 선택) */}
          {/* POSEIDON: 엔진 연동 완료. KOSPS: 준비 중 (ready: false) */}
          <div className="grid grid-cols-3 gap-[3px]">
            {([
              { id: 'KOSPS' as PredictionModel, color: 'var(--cyan)', ready: false },
              { id: 'POSEIDON' as PredictionModel, color: 'var(--red)', ready: true },
              { id: 'OpenDrift' as PredictionModel, color: 'var(--blue)', ready: true },
            ] as const).map(m => (
              <div
                key={m.id}
                className={`prd-mc ${selectedModels.has(m.id) ? 'on' : ''} cursor-pointer text-center`}
                onClick={() => {
                  if (!m.ready) {
                    alert(`${m.id} 모델은 현재 준비중입니다.`)
                    return
                  }
                  const next = new Set(selectedModels)
                  if (next.has(m.id)) { next.delete(m.id) } else { next.add(m.id) }
                  onModelsChange(next)
                  if (hasResults && onVisibleModelsChange) {
                    onVisibleModelsChange(new Set(next))
                  }
                }}
              >
                <span className="prd-md" style={{ background: m.color }} />
                {m.id}
              </div>
            ))}
            {/* 임시 비활성화 — OpenDrift만 구동 가능 (앙상블은 모든 모델 연동 후 활성화 예정)
            <div
              className={`prd-mc ${selectedModels.size === ALL_MODELS.length ? 'on' : ''} cursor-pointer`}
              onClick={() => {
                alert('앙상블 모델은 현재 준비중입니다.')
              }}
            >
              <span className="prd-md" style={{ background: 'var(--purple)' }} />
              앙상블
            </div>
            */}
          </div>

          {/* 모델 미선택 경고 */}
          {selectedModels.size === 0 && (
            <p className="text-[10px] text-status-red font-korean">
              ⚠ 예측 모델을 하나 이상 선택하세요.
            </p>
          )}

          {/* Run Button */}
          <button
            className="prd-btn pri mt-0.5"
            style={{ padding: '7px', fontSize: '11px' }}
            onClick={onRunSimulation}
            disabled={isRunningSimulation}
          >
            {isRunningSimulation ? '⏳ 실행 중...' : '🔬 확산예측 실행'}
          </button>
        </div>
      )}
    </div>
  )
}

// ── 커스텀 날짜/시간 선택 컴포넌트 ─────────────────────
function DateTimeInput({ value, onChange }: { value: string; onChange: (v: string) => void }) {
  const [showCal, setShowCal] = useState(false)
  const ref = useRef<HTMLDivElement>(null)

  const datePart = value ? value.split('T')[0] : ''
  const timePart = value && value.includes('T') ? value.split('T')[1] : '00:00'
  const timeParts = timePart.split(':').map(Number)
  const hh = isNaN(timeParts[0]) ? 0 : timeParts[0]
  const mm = (timeParts[1] === undefined || isNaN(timeParts[1])) ? 0 : timeParts[1]

  const parsed = datePart ? new Date(datePart + 'T00:00:00') : new Date()
  const [viewYear, setViewYear] = useState(parsed.getFullYear())
  const [viewMonth, setViewMonth] = useState(parsed.getMonth())

  const selY = datePart ? parsed.getFullYear() : -1
  const selM = datePart ? parsed.getMonth() : -1
  const selD = datePart ? parsed.getDate() : -1

  useEffect(() => {
    const handler = (e: MouseEvent) => {
      if (ref.current && !ref.current.contains(e.target as Node)) setShowCal(false)
    }
    document.addEventListener('mousedown', handler)
    return () => document.removeEventListener('mousedown', handler)
  }, [])

  const daysInMonth = new Date(viewYear, viewMonth + 1, 0).getDate()
  const firstDay = new Date(viewYear, viewMonth, 1).getDay()
  const days: (number | null)[] = []
  for (let i = 0; i < firstDay; i++) days.push(null)
  for (let i = 1; i <= daysInMonth; i++) days.push(i)

  const pickDate = (day: number) => {
    const m = String(viewMonth + 1).padStart(2, '0')
    const d = String(day).padStart(2, '0')
    onChange(`${viewYear}-${m}-${d}T${timePart}`)
    setShowCal(false)
  }

  const updateTime = (newHH: number, newMM: number) => {
    const date = datePart || new Date().toISOString().split('T')[0]
    onChange(`${date}T${String(newHH).padStart(2, '0')}:${String(newMM).padStart(2, '0')}`)
  }

  const prevMonth = () => {
    if (viewMonth === 0) { setViewYear(viewYear - 1); setViewMonth(11) }
    else setViewMonth(viewMonth - 1)
  }
  const nextMonth = () => {
    if (viewMonth === 11) { setViewYear(viewYear + 1); setViewMonth(0) }
    else setViewMonth(viewMonth + 1)
  }

  const displayDate = datePart
    ? `${selY}.${String(selM + 1).padStart(2, '0')}.${String(selD).padStart(2, '0')}`
    : '날짜 선택'

  const today = new Date()
  const todayY = today.getFullYear()
  const todayM = today.getMonth()
  const todayD = today.getDate()

  return (
    <div ref={ref} className="flex items-center gap-1 relative">
      {/* 날짜 버튼 */}
      <button
        type="button"
        onClick={() => setShowCal(!showCal)}
        className="prd-i flex-1 flex items-center justify-between cursor-pointer"
        style={{ padding: '5px 8px', fontSize: 10 }}
      >
        <span className="font-mono" style={{ color: datePart ? 'var(--t1)' : 'var(--t3)' }}>{displayDate}</span>
        <span className="text-[9px] opacity-60">📅</span>
      </button>

      {/* 시 */}
      <TimeDropdown value={hh} max={24} onChange={(v) => updateTime(v, mm)} />
      <span className="text-[8px] text-text-3 font-bold">:</span>
      {/* 분 */}
      <TimeDropdown value={mm} max={60} onChange={(v) => updateTime(hh, v)} />

      {/* 캘린더 팝업 */}
      {showCal && (
        <div
          className="absolute z-[9999] rounded-md overflow-hidden"
          style={{
            top: '100%',
            left: 0,
            marginTop: 4,
            width: 200,
            background: 'var(--bg3)',
            border: '1px solid var(--bd)',
            boxShadow: '0 8px 24px rgba(0,0,0,0.5)',
          }}
        >
          {/* 헤더 */}
          <div className="flex items-center justify-between" style={{ padding: '6px 8px', borderBottom: '1px solid var(--bd)' }}>
            <button type="button" onClick={prevMonth} className="text-[10px] text-text-3 cursor-pointer px-1 hover:text-text-1">◀</button>
            <span className="text-[10px] font-bold text-text-1 font-korean">{viewYear}년 {viewMonth + 1}월</span>
            <button type="button" onClick={nextMonth} className="text-[10px] text-text-3 cursor-pointer px-1 hover:text-text-1">▶</button>
          </div>
          {/* 요일 */}
          <div className="grid grid-cols-7 text-center" style={{ padding: '3px 4px 0' }}>
            {['일', '월', '화', '수', '목', '금', '토'].map((d) => (
              <span key={d} className="text-[8px] text-text-3 font-korean" style={{ padding: '2px 0' }}>{d}</span>
            ))}
          </div>
          {/* 날짜 */}
          <div className="grid grid-cols-7 text-center" style={{ padding: '2px 4px 6px' }}>
            {days.map((day, i) => {
              if (day === null) return <span key={`e-${i}`} />
              const isSelected = viewYear === selY && viewMonth === selM && day === selD
              const isToday = viewYear === todayY && viewMonth === todayM && day === todayD
              return (
                <button
                  key={day}
                  type="button"
                  onClick={() => pickDate(day)}
                  className="cursor-pointer rounded-sm"
                  style={{
                    padding: '3px 0',
                    fontSize: 9,
                    fontFamily: 'var(--fM)',
                    fontWeight: isSelected ? 700 : 400,
                    color: isSelected ? '#fff' : isToday ? 'var(--cyan)' : 'var(--t2)',
                    background: isSelected ? 'var(--cyan)' : 'transparent',
                    border: 'none',
                  }}
                >
                  {day}
                </button>
              )
            })}
          </div>
          {/* 오늘 버튼 */}
          <div style={{ padding: '0 8px 6px' }}>
            <button
              type="button"
              onClick={() => {
                const now = new Date()
                setViewYear(now.getFullYear())
                setViewMonth(now.getMonth())
                const m = String(now.getMonth() + 1).padStart(2, '0')
                const d = String(now.getDate()).padStart(2, '0')
                const hh = String(now.getHours()).padStart(2, '0')
                const mm = String(now.getMinutes()).padStart(2, '0')
                onChange(`${now.getFullYear()}-${m}-${d}T${hh}:${mm}`)
                setShowCal(false)
              }}
              className="w-full text-[8px] font-korean font-semibold cursor-pointer rounded-sm"
              style={{
                padding: '3px 0',
                background: 'rgba(6,182,212,0.08)',
                border: '1px solid rgba(6,182,212,0.2)',
                color: 'var(--cyan)',
              }}
            >
              오늘
            </button>
          </div>
        </div>
      )}
    </div>
  )
}

// ── 커스텀 시간 드롭다운 (다크 테마) ───────────────────
function TimeDropdown({ value, max, onChange }: { value: number; max: number; onChange: (v: number) => void }) {
  const [open, setOpen] = useState(false)
  const dropRef = useRef<HTMLDivElement>(null)
  const listRef = useRef<HTMLDivElement>(null)

  useEffect(() => {
    const handler = (e: MouseEvent) => {
      if (dropRef.current && !dropRef.current.contains(e.target as Node)) setOpen(false)
    }
    document.addEventListener('mousedown', handler)
    return () => document.removeEventListener('mousedown', handler)
  }, [])

  useEffect(() => {
    if (open && listRef.current) {
      const activeEl = listRef.current.querySelector('[data-active="true"]')
      if (activeEl) activeEl.scrollIntoView({ block: 'center' })
    }
  }, [open])

  return (
    <div ref={dropRef} className="relative">
      <button
        type="button"
        onClick={() => setOpen(!open)}
        className="prd-i text-center font-mono cursor-pointer"
        style={{ width: 38, padding: '5px 2px', fontSize: 9 }}
      >
        {String(value).padStart(2, '0')}
      </button>
      {open && (
        <div
          ref={listRef}
          className="absolute z-[9999] overflow-y-auto rounded-md"
          style={{
            top: '100%',
            left: '50%',
            transform: 'translateX(-50%)',
            marginTop: 2,
            width: 42,
            maxHeight: 160,
            background: 'var(--bg3)',
            border: '1px solid var(--bd)',
            boxShadow: '0 8px 24px rgba(0,0,0,0.5)',
            scrollbarWidth: 'thin',
            scrollbarColor: 'var(--bd) transparent',
          }}
        >
          {Array.from({ length: max }, (_, i) => (
            <button
              key={i}
              type="button"
              data-active={i === value}
              onClick={() => { onChange(i); setOpen(false) }}
              className="w-full text-center font-mono cursor-pointer"
              style={{
                padding: '4px 0',
                fontSize: 9,
                color: i === value ? 'var(--cyan)' : 'var(--t2)',
                background: i === value ? 'rgba(6,182,212,0.15)' : 'transparent',
                fontWeight: i === value ? 700 : 400,
                border: 'none',
              }}
            >
              {String(i).padStart(2, '0')}
            </button>
          ))}
        </div>
      )}
    </div>
  )
}

// ── 도분초 좌표 입력 컴포넌트 ──────────────────────────
function DmsCoordInput({
  label,
  isLatitude,
  decimal,
  onChange,
}: {
  label: string
  isLatitude: boolean
  decimal: number
  onChange: (val: number) => void
}) {
  const abs = Math.abs(decimal)
  const d = Math.floor(abs)
  const mDec = (abs - d) * 60
  const m = Math.floor(mDec)
  const s = parseFloat(((mDec - m) * 60).toFixed(2))
  const dir = isLatitude ? (decimal >= 0 ? 'N' : 'S') : (decimal >= 0 ? 'E' : 'W')

  const update = (deg: number, min: number, sec: number, direction: string) => {
    let val = deg + min / 60 + sec / 3600
    if (direction === 'S' || direction === 'W') val = -val
    onChange(val)
  }

  const fieldStyle = { padding: '5px 2px', fontSize: 10, minWidth: 0 }

  return (
    <div className="flex flex-col gap-0.5">
      <span className="text-[8px] text-text-3 font-korean">{label}</span>
      <div className="flex items-center gap-0.5">
        <select
          className="prd-i text-center"
          value={dir}
          onChange={(e) => update(d, m, s, e.target.value)}
          style={{ width: 32, padding: '5px 1px', fontSize: 10, appearance: 'none', WebkitAppearance: 'none', backgroundImage: 'none' }}
        >
          {isLatitude ? (
            <><option value="N">N</option><option value="S">S</option></>
          ) : (
            <><option value="E">E</option><option value="W">W</option></>
          )}
        </select>
        <input className="prd-i text-center flex-1" type="number" min={0} max={isLatitude ? 90 : 180}
          value={d} onChange={(e) => update(parseInt(e.target.value) || 0, m, s, dir)} style={fieldStyle} />
        <span className="text-[9px] text-text-3">°</span>
        <input className="prd-i text-center flex-1" type="number" min={0} max={59}
          value={m} onChange={(e) => update(d, parseInt(e.target.value) || 0, s, dir)} style={fieldStyle} />
        <span className="text-[9px] text-text-3">'</span>
        <input className="prd-i text-center flex-1" type="number" min={0} max={59.99} step={0.01}
          value={s} onChange={(e) => update(d, m, parseFloat(e.target.value) || 0, dir)} style={fieldStyle} />
        <span className="text-[9px] text-text-3">"</span>
      </div>
    </div>
  )
}

export default PredictionInputSection
