import { memo, useMemo } from 'react'

import { SLOT_MS, TOTAL_SLOTS } from './charts/chartConstants'
import type { SlotData } from '../types/dashboard'

export type StatePanelProps = {
  slots: SlotData[]
  nowIndex: number
}

function deyeModeLabel(s: SlotData): string {
  const m = s.deye_physical_mode
  if (m === 'SELL') return 'SELL'
  if (m === 'CHARGE') return 'CHARGE'
  if (m === 'PASSIVE') return 'PASSIVE'
  return '—'
}

function deyeModeBadge(s: SlotData): { label: string; klass: string; title: string } {
  const m = s.deye_physical_mode
  const em = (s.export_mode ?? 'NONE').toString().trim().toUpperCase()
  const exportHint =
    em !== 'NONE' ? ` · plán export ${em}` : ''
  if (m === 'SELL') {
    return {
      label: 'SELL',
      klass: 'bg-orange-500/15 text-orange-200 ring-1 ring-orange-500/35',
      title: `SELL (selling first): reg142=0, reg178=32 (grid peak shaving off)${exportHint}`,
    }
  }
  if (m === 'CHARGE') {
    return {
      label: 'CHARGE',
      klass: 'bg-sky-500/15 text-sky-200 ring-1 ring-sky-500/35',
      title: 'CHARGE (grid charge): TOU grid_charge enabled v time pointech; reg178=48',
    }
  }
  return {
    label: 'PASSIVE',
    klass: 'bg-slate-600/40 text-slate-200 ring-1 ring-slate-500/30',
    title: 'PASSIVE (ZERO): reg142=deye_zero_export_mode; reg178=48',
  }
}

/** Stav segmentu pro jeden track */
export type TrackSegment = {
  widthPct: number
  label: string
  color: string
  textColor: string
  isFuture: boolean
  tooltip?: string
  /** Zákaz exportu (záporná prodejní cena) – overlay „0!“ */
  exportBanOverlay?: boolean
}

const TIME_PRAGUE = new Intl.DateTimeFormat('cs-CZ', {
  timeZone: 'Europe/Prague',
  hour: '2-digit',
  minute: '2-digit',
  hour12: false,
})

function slotRangeLabel(slots: SlotData[], i0: number, i1: number): string {
  const t0 = new Date(slots[i0]!.interval_start).getTime()
  const t1 = new Date(slots[i1]!.interval_start).getTime() + SLOT_MS
  return `${TIME_PRAGUE.format(t0)}–${TIME_PRAGUE.format(t1)}`
}

function fmtMoney(v: number | null | undefined): string | null {
  if (v == null || Number.isNaN(v)) return null
  return `${v.toFixed(2)} Kč/kWh`
}

function avg(nums: number[]): number {
  if (nums.length === 0) return 0
  return nums.reduce((a, b) => a + b, 0) / nums.length
}

type GridKind = 'import' | 'export' | 'idle'

function gridKind(s: SlotData): GridKind {
  const sp = s.grid_setpoint_w
  const pw = s.grid_power_w
  const imp = (sp != null && sp > 500) || (pw != null && pw > 500)
  const exp = (sp != null && sp < -500) || (pw != null && pw < -500)
  if (imp) return 'import'
  if (exp) return 'export'
  return 'idle'
}

function gridFlowW(s: SlotData): number {
  return s.grid_setpoint_w ?? s.grid_power_w ?? 0
}

export function buildGridSegments(slots: SlotData[], nowIndex: number): TrackSegment[] {
  const n = slots.length
  if (n === 0) return []
  const out: TrackSegment[] = []
  let i = 0
  while (i < n) {
    const g = gridKind(slots[i]!)
    const neg = slots[i]!.sell_price != null && slots[i]!.sell_price! < 0
    const fut = i > nowIndex
    const start = i
    const gw: number[] = []
    const buys: number[] = []
    const sells: number[] = []
    while (i < n) {
      const s = slots[i]!
      if (gridKind(s) !== g) break
      if ((s.sell_price != null && s.sell_price < 0) !== neg) break
      if ((i > nowIndex) !== fut) break
      gw.push(gridFlowW(s))
      if (s.buy_price != null) buys.push(s.buy_price)
      if (s.sell_price != null) sells.push(s.sell_price)
      i++
    }
    const count = i - start
    const widthPct = (count / n) * 100
    const avgW = avg(gw)
    const avgBuy = buys.length ? avg(buys) : null
    const avgSell = sells.length ? avg(sells) : null

    let color = '#88878012'
    let textColor = '#5F5E5A'
    let label = '–'
    if (g === 'import') {
      color = '#E24B4A1A'
      textColor = '#993C1D'
      label = `↓ ${(avgW / 1000).toFixed(1)} kW`
    } else if (g === 'export') {
      color = '#1D9E751A'
      textColor = '#0F6E56'
      label = `↑ ${(Math.abs(avgW) / 1000).toFixed(1)} kW`
    }

    const range = slotRangeLabel(slots, start, i - 1)
    let tooltip = range
    if (g === 'import') {
      tooltip += ` · import ${(avgW / 1000).toFixed(1)} kW`
      const p = fmtMoney(avgBuy)
      if (p) tooltip += ` · cena nákup ${p}`
    } else if (g === 'export') {
      tooltip += ` · export ${(Math.abs(avgW) / 1000).toFixed(1)} kW`
      const p = fmtMoney(avgSell)
      if (p) tooltip += ` · cena prodej ${p}`
    } else {
      tooltip += ' · síť v klidu'
      const p = fmtMoney(avgSell ?? avgBuy)
      if (p) tooltip += ` · cena ${p}`
    }

    out.push({
      widthPct,
      label,
      color,
      textColor,
      isFuture: fut,
      tooltip,
      exportBanOverlay: neg,
    })
  }
  return out
}

type BatKind = 'fve' | 'grid' | 'dis' | 'idle'

function batKind(s: SlotData): BatKind {
  const bsp = s.battery_setpoint_w
  const bpw = s.battery_power_w
  const gsp = s.grid_setpoint_w
  const gpw = s.grid_power_w

  if ((bsp != null && bsp < -500) || (bpw != null && bpw < -500)) return 'dis'

  const gridHeavy = (gsp != null && gsp > 500) || (gpw != null && gpw > 500)

  if (bsp != null && bsp > 500) {
    if (gsp != null && gsp > 500) return 'grid'
    if (gridHeavy) return 'grid'
    return 'fve'
  }

  if (bpw != null && bpw > 500) {
    if (gridHeavy) return 'grid'
    return 'fve'
  }

  return 'idle'
}

export function buildBatterySegments(slots: SlotData[], nowIndex: number): TrackSegment[] {
  const n = slots.length
  if (n === 0) return []
  const out: TrackSegment[] = []
  let i = 0
  while (i < n) {
    const k = batKind(slots[i]!)
    const fut = i > nowIndex
    const start = i
    while (i < n) {
      if (batKind(slots[i]!) !== k) break
      if ((i > nowIndex) !== fut) break
      i++
    }
    const count = i - start
    const widthPct = (count / n) * 100
    let color = '#88878012'
    let textColor = '#5F5E5A'
    let label = '–'
    if (k === 'fve') {
      color = '#1D9E751A'
      textColor = '#0F6E56'
      label = 'nabíjení FVE'
    } else if (k === 'grid') {
      color = '#378ADD1A'
      textColor = '#185FA5'
      label = 'nabíjení sítě'
    } else if (k === 'dis') {
      color = '#EF9F271A'
      textColor = '#854F0B'
      label = 'vybíjení'
    }
    const range = slotRangeLabel(slots, start, i - 1)
    out.push({
      widthPct,
      label,
      color,
      textColor,
      isFuture: fut,
      tooltip: `${range} · ${label}`,
    })
  }
  return out
}

export type DeviceKind = 'ev1' | 'ev2' | 'tc'

function evSegmentKind(sp: number | null): 'charge' | 'idle' | 'off' {
  if (sp === null) return 'off'
  if (sp > 0) return 'charge'
  return 'idle'
}

function tcRunning(s: SlotData): boolean {
  if (s.heat_pump_enabled === true) return true
  if (s.heat_pump_enabled === false) return false
  return (s.heat_pump_setpoint_w ?? 0) > 0
}

export function buildDeviceSegments(
  slots: SlotData[],
  nowIndex: number,
  device: DeviceKind,
): TrackSegment[] {
  const n = slots.length
  if (n === 0) return []
  const out: TrackSegment[] = []

  if (device === 'tc') {
    let i = 0
    while (i < n) {
      const on = tcRunning(slots[i]!)
      const fut = i > nowIndex
      const start = i
      while (i < n) {
        if (tcRunning(slots[i]!) !== on) break
        if ((i > nowIndex) !== fut) break
        i++
      }
      const count = i - start
      const widthPct = (count / n) * 100
      out.push({
        widthPct,
        label: on ? '6kW' : '–',
        color: on ? '#D4537E1A' : '#88878012',
        textColor: on ? '#8B3055' : '#5F5E5A',
        isFuture: fut,
        tooltip: `${slotRangeLabel(slots, start, i - 1)} · ${on ? 'TČ běží' : 'TČ odstaveno'}`,
      })
    }
    return out
  }

  const pick = (s: SlotData) => (device === 'ev1' ? s.ev1_setpoint_w : s.ev2_setpoint_w)

  let i = 0
  while (i < n) {
    const ek = evSegmentKind(pick(slots[i]!))
    const fut = i > nowIndex
    const start = i
    const pws: number[] = []
    while (i < n) {
      const s = slots[i]!
      if (evSegmentKind(pick(s)) !== ek) break
      if ((i > nowIndex) !== fut) break
      const sp = pick(s)
      if (sp != null && sp > 0) pws.push(sp)
      i++
    }
    const count = i - start
    const widthPct = (count / n) * 100
    if (ek === 'off') {
      out.push({
        widthPct,
        label: 'nepřipojeno',
        color: '#88878008',
        textColor: '#5F5E5A',
        isFuture: fut,
        tooltip: `${slotRangeLabel(slots, start, i - 1)} · vozidlo nepřipojeno`,
      })
    } else if (ek === 'charge') {
      const avgW = avg(pws.length ? pws : [0])
      out.push({
        widthPct,
        label: `${(avgW / 1000).toFixed(1)} kW`,
        color: '#534AB71A',
        textColor: '#3D3480',
        isFuture: fut,
        tooltip: `${slotRangeLabel(slots, start, i - 1)} · nabíjení ${(avgW / 1000).toFixed(1)} kW`,
      })
    } else {
      out.push({
        widthPct,
        label: '–',
        color: '#88878012',
        textColor: '#5F5E5A',
        isFuture: fut,
        tooltip: `${slotRangeLabel(slots, start, i - 1)} · klid`,
      })
    }
  }
  return out
}

function isFourHourTick(iso: string): boolean {
  const d = new Date(iso)
  const parts = new Intl.DateTimeFormat('en-GB', {
    timeZone: 'Europe/Prague',
    hour: '2-digit',
    minute: '2-digit',
    hour12: false,
  }).formatToParts(d)
  const hi = parts.find((p) => p.type === 'hour')
  const mi = parts.find((p) => p.type === 'minute')
  if (!hi || !mi) return false
  const h = parseInt(hi.value, 10)
  const m = parseInt(mi.value, 10)
  return m === 0 && h % 4 === 0
}

function TickRow({ slots }: { slots: SlotData[] }) {
  const n = slots.length
  if (n === 0) return null
  return (
    <div className="relative mt-0.5 h-4 w-full">
      {slots.map((s, i) =>
        isFourHourTick(s.interval_start) ? (
          <span
            key={`${s.interval_start}-${i}`}
            className="absolute top-0 -translate-x-1/2 text-[9px] tabular-nums text-slate-500"
            style={{ left: `${((i + 0.5) / n) * 100}%` }}
          >
            {TIME_PRAGUE.format(new Date(s.interval_start))}
          </span>
        ) : null,
      )}
    </div>
  )
}

function SegmentBar({
  segments,
  nowIndex,
  showNowLabel,
}: {
  segments: TrackSegment[]
  nowIndex: number
  showNowLabel?: boolean
}) {
  const n = TOTAL_SLOTS
  const leftPct = (nowIndex / n) * 100
  return (
    <div className="relative min-h-[28px]">
      <div className="flex h-[28px] w-full overflow-hidden rounded-sm border border-slate-800/80">
        {segments.map((seg, idx) => (
          <div
            key={idx}
            title={seg.tooltip}
            className="relative flex min-w-0 shrink-0 items-center justify-center overflow-hidden px-0.5 text-center font-medium leading-tight"
            style={{
              width: `${seg.widthPct}%`,
              background: seg.color,
              opacity: seg.isFuture ? 0.6 : 1,
              borderLeft: seg.isFuture ? '1px dashed rgba(148,163,184,0.45)' : 'none',
              color: seg.textColor,
              fontSize: 9,
            }}
          >
            <span className="truncate">{seg.label}</span>
            {seg.exportBanOverlay ? (
              <div
                className="pointer-events-none absolute inset-0 flex items-center justify-center text-[9px] font-bold"
                style={{ background: '#E24B4A28', color: '#993C1D' }}
              >
                0!
              </div>
            ) : null}
          </div>
        ))}
      </div>
      <div
        className="pointer-events-none absolute inset-0 z-10"
        aria-hidden
      >
        {showNowLabel ? (
          <span
            className="absolute -top-5 z-20 whitespace-nowrap text-[9px] font-semibold text-[#378ADD]"
            style={{ left: `${leftPct}%`, transform: 'translateX(-50%)' }}
          >
            teď
          </span>
        ) : null}
        <div
          className="absolute bottom-0 top-0 w-[1.5px] bg-[#378ADD]"
          style={{ left: `${leftPct}%`, transform: 'translateX(-50%)' }}
        />
      </div>
    </div>
  )
}

function TrackRow({
  label,
  segments,
  nowIndex,
  showNowLabel,
}: {
  label: string
  segments: TrackSegment[]
  nowIndex: number
  showNowLabel?: boolean
}) {
  return (
    // Mobil: label nad trackem (plná šířka); md+: label vlevo vedle tracku.
    <div className="grid grid-cols-1 items-center gap-x-1 gap-y-0.5 md:grid-cols-[52px_1fr] md:gap-y-0">
      <div className="pr-1 text-left text-[10px] font-medium text-slate-400 md:text-right">{label}</div>
      <SegmentBar segments={segments} nowIndex={nowIndex} showNowLabel={showNowLabel} />
    </div>
  )
}

function StatePanelRaw({ slots, nowIndex }: StatePanelProps) {
  const gridSegs = useMemo(() => buildGridSegments(slots, nowIndex), [slots, nowIndex])
  const batSegs = useMemo(() => buildBatterySegments(slots, nowIndex), [slots, nowIndex])
  const ev1Segs = useMemo(() => buildDeviceSegments(slots, nowIndex, 'ev1'), [slots, nowIndex])
  const ev2Segs = useMemo(() => buildDeviceSegments(slots, nowIndex, 'ev2'), [slots, nowIndex])
  const tcSegs = useMemo(() => buildDeviceSegments(slots, nowIndex, 'tc'), [slots, nowIndex])

  if (slots.length === 0) return null

  return (
    <div className="space-y-5 rounded-xl border border-slate-800 bg-slate-900/40 p-3">
      <div>
        <p className="mb-2 text-xs font-semibold uppercase tracking-wide text-slate-400">
          Energetický tok
        </p>
        <p className="mb-2 text-[10px] text-slate-500">
          Deye režim (plán):{' '}
          {(() => {
            const b = deyeModeBadge(slots[nowIndex]!)
            return (
              <span
                className={`inline-flex items-center rounded-md px-2 py-0.5 text-[10px] font-semibold ${b.klass}`}
                title={b.title}
              >
                {b.label}
              </span>
            )
          })()}
          <span className="ml-2 font-mono text-slate-500">{deyeModeLabel(slots[nowIndex]!)}</span>
        </p>
        <div className="space-y-2">
          <TrackRow label="Síť" segments={gridSegs} nowIndex={nowIndex} showNowLabel />
          <TrackRow label="Baterie" segments={batSegs} nowIndex={nowIndex} />
        </div>
        <div className="mt-1 grid grid-cols-1 gap-x-1 md:grid-cols-[52px_1fr]">
          <div className="hidden md:block" />
          <TickRow slots={slots} />
        </div>
        <ul className="mt-2 flex flex-wrap gap-x-4 gap-y-1 text-[10px] text-slate-500">
          <li className="flex items-center gap-1">
            <span className="h-2 w-3 rounded-sm" style={{ background: '#E24B4A1A' }} />
            Import
          </li>
          <li className="flex items-center gap-1">
            <span className="h-2 w-3 rounded-sm" style={{ background: '#1D9E751A' }} />
            Export
          </li>
          <li className="flex items-center gap-1">
            <span className="h-2 w-3 rounded-sm" style={{ background: '#88878012' }} />
            Klid
          </li>
          <li className="flex items-center gap-1">
            <span className="h-2 w-3 rounded-sm" style={{ background: '#E24B4A28' }} />
            Zákaz exportu (0!)
          </li>
        </ul>
      </div>

      <div className="border-t border-slate-800 pt-4">
        <p className="mb-2 text-xs font-semibold uppercase tracking-wide text-slate-400">
          Variabilní zátěže
        </p>
        <div className="space-y-2">
          <TrackRow label="Tesla" segments={ev1Segs} nowIndex={nowIndex} />
          <TrackRow label="Zoe" segments={ev2Segs} nowIndex={nowIndex} />
          <TrackRow label="TČ" segments={tcSegs} nowIndex={nowIndex} />
        </div>
        <div className="mt-1 grid grid-cols-1 gap-x-1 md:grid-cols-[52px_1fr]">
          <div className="hidden md:block" />
          <TickRow slots={slots} />
        </div>
        <ul className="mt-2 flex flex-wrap gap-x-4 gap-y-1 text-[10px] text-slate-500">
          <li className="flex items-center gap-1">
            <span className="h-2 w-3 rounded-sm" style={{ background: '#534AB71A' }} />
            EV nabíjení
          </li>
          <li className="flex items-center gap-1">
            <span className="h-2 w-3 rounded-sm" style={{ background: '#88878008' }} />
            Nepřipojeno
          </li>
          <li className="flex items-center gap-1">
            <span className="h-2 w-3 rounded-sm" style={{ background: '#D4537E1A' }} />
            TČ běh
          </li>
        </ul>
      </div>
    </div>
  )
}

export const StatePanel = memo(StatePanelRaw, (prev, next) => {
  return prev.slots === next.slots && prev.nowIndex === next.nowIndex
})
