import { useCallback, useEffect, useMemo, useState } from 'react'
import {
  CartesianGrid,
  Legend,
  Line,
  LineChart,
  ResponsiveContainer,
  Tooltip,
  XAxis,
  YAxis,
} from 'recharts'

import {
  getBaselineLoadSlotsRange,
  getForecastPvSlotsRangeCorrected,
  getTelemetry15mRange,
  type BaselineLoadSlotRow,
  type ForecastPvSlotCorrectedRow,
  type Telemetry15mRow,
} from '../api/backend'
import { useSiteStatus } from '../hooks/useSiteStatus'
import { instantPragueDay } from '../lib/pragueDate'

type MetricKey = 'pv' | 'load' | 'grid'

type Point = {
  k: string
  timeLabel: string
  actual_kw: number | null
  forecast_kw: number | null
  corrected_kw: number | null
}

function kwFromW(w: number | null | undefined): number | null {
  if (w == null || Number.isNaN(Number(w))) return null
  return Number(w) / 1000
}

function fmtDayLabel(ymd: string): string {
  return new Date(ymd + 'T12:00:00Z').toLocaleDateString('cs-CZ', {
    weekday: 'short',
    day: 'numeric',
    month: 'numeric',
    timeZone: 'Europe/Prague',
  })
}

function DayChart({
  title,
  points,
  showForecast,
  showCorrected,
}: {
  title: string
  points: Point[]
  showForecast: boolean
  showCorrected: boolean
}) {
  return (
    <div className="h-[240px] w-full rounded-xl border border-slate-800 bg-slate-900/40 p-2 pt-4">
      <div className="px-2 pb-2 text-xs font-semibold uppercase tracking-wide text-slate-500">{title}</div>
      <ResponsiveContainer width="100%" height="100%">
        <LineChart data={points} margin={{ top: 8, right: 16, left: 0, bottom: 0 }}>
          <CartesianGrid strokeDasharray="3 3" stroke="#334155" opacity={0.6} />
          <XAxis dataKey="timeLabel" tick={{ fill: '#94a3b8', fontSize: 11 }} interval={7} />
          <YAxis
            tick={{ fill: '#94a3b8', fontSize: 11 }}
            label={{ value: 'kW', angle: -90, position: 'insideLeft', fill: '#64748b', fontSize: 11 }}
          />
          <Tooltip
            contentStyle={{
              backgroundColor: '#0f172a',
              border: '1px solid #1e293b',
              borderRadius: '8px',
            }}
            labelStyle={{ color: '#e2e8f0' }}
          />
          <Legend wrapperStyle={{ fontSize: 12 }} />
          <Line
            type="monotone"
            dataKey="actual_kw"
            name="Skutečnost"
            stroke="#e2e8f0"
            strokeWidth={2}
            dot={false}
            connectNulls
            isAnimationActive={false}
          />
          {showForecast ? (
            <Line
              type="monotone"
              dataKey="forecast_kw"
              name="Předpověď"
              stroke="#fbbf24"
              strokeWidth={1.5}
              dot={false}
              connectNulls
              strokeDasharray="5 4"
              isAnimationActive={false}
            />
          ) : null}
          {showCorrected ? (
            <Line
              type="monotone"
              dataKey="corrected_kw"
              name="Korigovaná"
              stroke="#fde68a"
              strokeWidth={1.5}
              dot={false}
              connectNulls
              strokeDasharray="2 3"
              isAnimationActive={false}
            />
          ) : null}
        </LineChart>
      </ResponsiveContainer>
    </div>
  )
}

export default function ForecastVsActual() {
  const { site: siteRow, ready: siteReady, error: siteErr } = useSiteStatus()
  const siteId = siteRow?.site_id ?? null

  const [metric, setMetric] = useState<MetricKey>('pv')
  const [days, setDays] = useState(20)
  const [ready, setReady] = useState(false)
  const [error, setError] = useState<string | null>(null)

  const [telemetry, setTelemetry] = useState<Telemetry15mRow[]>([])
  const [pvSlots, setPvSlots] = useState<ForecastPvSlotCorrectedRow[]>([])
  const [baselineSlots, setBaselineSlots] = useState<BaselineLoadSlotRow[]>([])

  const load = useCallback(async () => {
    if (siteId == null) {
      setTelemetry([])
      setPvSlots([])
      setBaselineSlots([])
      setError(null)
      setReady(true)
      return
    }
    const to = new Date()
    const from = new Date(to.getTime() - days * 24 * 60 * 60 * 1000)
    const fromIso = from.toISOString()
    const toIso = to.toISOString()
    try {
      const [tel, pv, base] = await Promise.all([
        getTelemetry15mRange(siteId, fromIso, toIso),
        getForecastPvSlotsRangeCorrected(siteId, fromIso, toIso),
        getBaselineLoadSlotsRange(siteId, fromIso, toIso),
      ])
      setTelemetry(tel)
      setPvSlots(pv)
      setBaselineSlots(base)
      setError(null)
    } catch (e) {
      setTelemetry([])
      setPvSlots([])
      setBaselineSlots([])
      setError(e instanceof Error ? e.message : 'Chyba načítání dat')
    } finally {
      setReady(true)
    }
  }, [siteId, days])

  useEffect(() => {
    void load()
  }, [load])

  const byInterval = useMemo(() => {
    const map = new Map<string, { tel?: Telemetry15mRow; pv?: ForecastPvSlotCorrectedRow; base?: BaselineLoadSlotRow }>()
    for (const r of telemetry) {
      map.set(r.slot_start, { ...(map.get(r.slot_start) ?? {}), tel: r })
    }
    for (const r of pvSlots) {
      map.set(r.interval_start, { ...(map.get(r.interval_start) ?? {}), pv: r })
    }
    for (const r of baselineSlots) {
      map.set(r.interval_start, { ...(map.get(r.interval_start) ?? {}), base: r })
    }
    return map
  }, [telemetry, pvSlots, baselineSlots])

  const daysGrouped = useMemo(() => {
    const byDay = new Map<string, Point[]>()
    const keys = [...byInterval.keys()].sort((a, b) => new Date(a).getTime() - new Date(b).getTime())
    for (const iso of keys) {
      const item = byInterval.get(iso)
      if (!item?.tel) continue
      const d = new Date(iso)
      const day = instantPragueDay(iso)
      const timeLabel = d.toLocaleTimeString('cs-CZ', {
        hour: '2-digit',
        minute: '2-digit',
        timeZone: 'Europe/Prague',
      })
      const k = iso

      let actual_kw: number | null = null
      let forecast_kw: number | null = null
      let corrected_kw: number | null = null

      if (metric === 'pv') {
        actual_kw = kwFromW(item.tel.avg_pv_w)
        forecast_kw = kwFromW(item.pv?.pv_forecast_total_w ?? null)
        corrected_kw = kwFromW(item.pv?.pv_forecast_corrected_w ?? null)
      } else if (metric === 'load') {
        actual_kw = kwFromW(item.tel.avg_load_w)
        forecast_kw = kwFromW(item.base?.forecast_w ?? null)
        corrected_kw = null
      } else if (metric === 'grid') {
        actual_kw = kwFromW(item.tel.avg_grid_w)
        forecast_kw = null
        corrected_kw = null
      }

      const arr = byDay.get(day) ?? []
      arr.push({ k, timeLabel, actual_kw, forecast_kw, corrected_kw })
      byDay.set(day, arr)
    }
    return [...byDay.entries()]
      .sort((a, b) => b[0].localeCompare(a[0]))
      .map(([day, points]) => ({
        day,
        points: points.sort((p, q) => new Date(p.k).getTime() - new Date(q.k).getTime()),
      }))
  }, [byInterval, metric])

  const title = metric === 'pv' ? 'FVE (výroba)' : metric === 'load' ? 'Spotřeba (bazál)' : 'Síť (signed)'
  const showForecast = metric === 'pv' || metric === 'load'
  const showCorrected = metric === 'pv'

  const tabClass = (on: boolean) =>
    `rounded-lg px-3 py-2 text-sm font-medium transition ${on ? 'bg-slate-800 text-white' : 'text-slate-400 hover:bg-slate-900 hover:text-slate-200'}`

  return (
    <div className="min-h-screen bg-gray-950 p-4 text-slate-100 md:p-8">
      <div className="mx-auto max-w-7xl space-y-5">
        <header className="border-b border-slate-800/80 pb-5">
          <h1 className="text-2xl font-bold tracking-tight text-white">Srovnání predikce vs skutečnost</h1>
          <p className="mt-1 text-sm text-slate-400">Posledních {days} dní (po dnech, 15min sloty)</p>
        </header>

        {!siteReady ? (
          <p className="text-sm text-slate-500">Načítám lokalitu…</p>
        ) : siteErr ? (
          <p className="text-sm text-red-200">{siteErr}</p>
        ) : siteId == null ? (
          <p className="text-sm text-slate-500">Žádná vybraná lokalita.</p>
        ) : (
          <div className="flex flex-wrap items-center gap-2">
            <button type="button" className={tabClass(metric === 'pv')} onClick={() => setMetric('pv')}>
              FVE
            </button>
            <button type="button" className={tabClass(metric === 'load')} onClick={() => setMetric('load')}>
              Spotřeba
            </button>
            <button type="button" className={tabClass(metric === 'grid')} onClick={() => setMetric('grid')}>
              Síť
            </button>
            <div className="ml-auto flex items-center gap-2">
              <label className="text-xs text-slate-400">
                Dní:{' '}
                <input
                  className="ml-1 w-20 rounded-md border border-slate-700 bg-slate-900 px-2 py-1 text-slate-100"
                  type="number"
                  min={3}
                  max={60}
                  value={days}
                  onChange={(e) => setDays(Math.max(3, Math.min(60, Number(e.target.value) || 20)))}
                />
              </label>
              <button
                type="button"
                onClick={() => void load()}
                className="rounded-lg bg-slate-800 px-3 py-2 text-sm font-semibold text-slate-100 hover:bg-slate-700"
              >
                Obnovit
              </button>
            </div>
          </div>
        )}

        {siteReady && siteId != null ? (
          <p className="text-xs text-slate-500">
            Legenda: <span className="text-slate-200">plná šedá</span> = skutečnost z telemetrie (15m CA),{' '}
            <span className="text-amber-200">čárkovaná žlutá</span> = předpověď (FVE: Open‑Meteo/pvlib; spotřeba: baseline
            z historie), <span className="text-yellow-100">tečkovaná světlá</span> = korigovaná FVE (delta profil z historie).
            U sítě zatím nemáme samostatnou „předpověď“ řady (jen skutečnost).
          </p>
        ) : null}

        {error ? (
          <div className="rounded-xl border border-red-500/40 bg-red-950/40 px-4 py-3 text-sm text-red-200" role="alert">
            {error}
          </div>
        ) : null}

        {!ready ? (
          <p className="text-sm text-slate-500">Načítám data…</p>
        ) : daysGrouped.length === 0 ? (
          <p className="text-sm text-slate-500">Žádná data pro zvolený rozsah.</p>
        ) : (
          <section className="space-y-4">
            {daysGrouped.map(({ day, points }) => (
              <DayChart
                key={day}
                title={`${fmtDayLabel(day)} · ${title}`}
                points={points}
                showForecast={showForecast}
                showCorrected={showCorrected}
              />
            ))}
          </section>
        )}
      </div>
    </div>
  )
}

