import { useEffect, useMemo, useRef, useState } from 'react'
import type { MouseEvent as ReactMouseEvent } from 'react'
import { Chart } from 'chart.js/auto'
import type { TooltipItem } from 'chart.js'

import { useIsCoarsePointer } from '../../hooks/useMediaQuery'
import type { SlotData } from '../../types/dashboard'
import { CHART_LAYOUT_PADDING } from './chartConstants'
import {
  computeNegWeekendRanges,
  createNowLinePluginRef,
  createSlotBackgroundPluginRefs,
} from './chartPlugins'

type Props = {
  slots: SlotData[]
  nowIndex: number
  /** Stejný zdroj jako horní karta SOC (živá telemetrie); bod v aktuálním slotu. */
  liveBatSoc?: number | null
}

export function SocTuvChart({ slots, nowIndex, liveBatSoc = null }: Props) {
  const canvasRef = useRef<HTMLCanvasElement>(null)
  const chartRef = useRef<Chart | null>(null)
  const wrapRef = useRef<HTMLDivElement>(null)

  // Touch zařízení: hover tooltip vypnutý; tap vybere slot do panelu nad grafem.
  const isCoarse = useIsCoarsePointer()
  const [touchIdx, setTouchIdx] = useState<number | null>(null)

  const slotsRef = useRef<SlotData[]>([])
  const negRangesRef = useRef<ReturnType<typeof computeNegWeekendRanges>>([])
  const nowIndexRef = useRef(0)
  const labelsRef = useRef<string[]>([])

  slotsRef.current = slots
  nowIndexRef.current = nowIndex

  const labels = useMemo(
    () =>
      slots.map((s) => {
        const d = new Date(s.interval_start)
        return d.toLocaleTimeString('cs-CZ', {
          hour: '2-digit',
          minute: '2-digit',
          timeZone: 'Europe/Prague',
        })
      }),
    [slots],
  )
  labelsRef.current = labels

  const negRanges = useMemo(() => computeNegWeekendRanges(slots, nowIndex), [slots, nowIndex])
  negRangesRef.current = negRanges

  const windowKey = useMemo(
    () => (slots.length ? `${slots[0]!.interval_start}|${slots.length}` : ''),
    [slots],
  )

  const series = useMemo(() => {
    const socReal = slots.map((s, i) => {
      if (i > nowIndex) return null
      if (
        i === nowIndex &&
        liveBatSoc != null &&
        Number.isFinite(liveBatSoc)
      ) {
        return liveBatSoc
      }
      return s.soc_actual_pct
    })
    const socPlan = slots.map((s) => s.soc_plan_pct)
    const tuvReal = slots.map((s, i) => (i <= nowIndex ? s.tuv_actual_c : null))
    const tuvPlan = slots.map((s) => s.tuv_plan_c)
    return { socReal, socPlan, tuvReal, tuvPlan }
  }, [slots, nowIndex, liveBatSoc])

  const bgPlugin = useMemo(
    () => createSlotBackgroundPluginRefs(slotsRef, negRangesRef),
    [],
  )
  const nowPlugin = useMemo(() => createNowLinePluginRef(nowIndexRef, 'teď'), [])

  useEffect(() => {
    const canvas = canvasRef.current
    if (!canvas || !windowKey) return

    const chart = new Chart(canvas, {
      type: 'line',
      plugins: [bgPlugin, nowPlugin],
      data: {
        labels: [...labels],
        datasets: [
          {
            label: 'SoC ■',
            data: series.socReal,
            borderColor: '#1D9E75',
            backgroundColor: '#1D9E7526',
            fill: true,
            borderWidth: 1.2,
            pointRadius: 0,
            tension: 0.2,
            yAxisID: 'y',
          },
          {
            label: 'SoC plán',
            data: series.socPlan,
            borderColor: '#1D9E75',
            borderDash: [5, 4],
            fill: false,
            borderWidth: 1,
            pointRadius: 0,
            tension: 0.2,
            yAxisID: 'y',
          },
          {
            label: 'TUV ■',
            data: series.tuvReal,
            borderColor: '#EF9F27',
            backgroundColor: '#EF9F2726',
            fill: true,
            borderWidth: 1.2,
            pointRadius: 0,
            tension: 0.2,
            yAxisID: 'y1',
          },
          {
            label: 'TUV cíl',
            data: series.tuvPlan,
            borderColor: '#EF9F27',
            borderDash: [5, 4],
            fill: false,
            borderWidth: 1,
            pointRadius: 0,
            tension: 0.2,
            yAxisID: 'y1',
          },
          {
            label: '_layout',
            data: slots.map(() => 0),
            borderColor: 'transparent',
            backgroundColor: 'transparent',
            borderWidth: 0,
            pointRadius: 0,
            yAxisID: 'y2',
            order: 100,
          },
        ],
      },
      options: {
        responsive: true,
        maintainAspectRatio: false,
        interaction: { mode: 'index', intersect: false },
        layout: { padding: { ...CHART_LAYOUT_PADDING } },
        plugins: {
          legend: { display: false },
          tooltip: {
            enabled: !isCoarse,
            callbacks: {
              title(items: TooltipItem<'line'>[]) {
                const i = items[0]?.dataIndex ?? 0
                return labelsRef.current[i] ?? ''
              },
              label(ctx: TooltipItem<'line'>) {
                if (ctx.dataset.label === '_layout') return ''
                if (!ctx.dataset.label) return ''
                const v = ctx.parsed.y as number | null
                if (v == null || Number.isNaN(v)) return `${ctx.dataset.label}: —`
                if (ctx.dataset.yAxisID === 'y') return `${ctx.dataset.label}: ${v.toFixed(1)} %`
                return `${ctx.dataset.label}: ${v.toFixed(1)} °C`
              },
            },
          },
        },
        scales: {
          x: {
            type: 'category',
            offset: false,
            grid: { color: 'rgba(148,163,184,0.1)' },
            ticks: {
              color: '#94a3b8',
              maxRotation: 0,
              autoSkip: false,
              callback(_v: string | number, i: number) {
                return i % 8 === 0 ? labelsRef.current[i] ?? '' : ''
              },
            },
          },
          y: {
            position: 'left',
            min: 0,
            max: 100,
            grid: { color: 'rgba(148,163,184,0.12)' },
            ticks: { color: '#1D9E75', font: { size: 9 } },
            title: { display: true, text: '% SoC', color: '#1D9E75', font: { size: 10 } },
          },
          y1: {
            position: 'right',
            min: 30,
            max: 75,
            grid: { drawOnChartArea: false },
            ticks: { color: '#EF9F27', font: { size: 9 } },
            title: { display: true, text: 'TUV °C', color: '#EF9F27', font: { size: 10 } },
          },
          y2: {
            type: 'linear',
            position: 'right',
            display: false,
            min: 0,
            max: 1,
            grid: { display: false },
            ticks: { display: false },
            weight: 0.35,
          },
        },
      },
    })

    chartRef.current = chart
    const ro = new ResizeObserver(() => chart.resize())
    ro.observe(canvas.parentElement ?? canvas)
    return () => {
      ro.disconnect()
      chart.destroy()
      chartRef.current = null
    }
  }, [windowKey, bgPlugin, nowPlugin, isCoarse])

  useEffect(() => {
    const ch = chartRef.current
    if (!ch || !slots.length) return
    ch.data.labels = [...labels]
    const dss = ch.data.datasets
    if (!dss?.length) return
    const s = series
    if (dss[0]) dss[0].data = s.socReal
    if (dss[1]) dss[1].data = s.socPlan
    if (dss[2]) dss[2].data = s.tuvReal
    if (dss[3]) dss[3].data = s.tuvPlan
    if (dss[4]) dss[4].data = slots.map(() => 0)
    ch.update('none')
  }, [labels, series, slots, slots.length])

  // Tap mimo graf zruší vybraný slot (touch panel).
  useEffect(() => {
    if (touchIdx == null) return
    const onDocDown = (e: PointerEvent) => {
      const el = wrapRef.current
      if (el && e.target instanceof Node && !el.contains(e.target)) setTouchIdx(null)
    }
    document.addEventListener('pointerdown', onDocDown)
    return () => document.removeEventListener('pointerdown', onDocDown)
  }, [touchIdx])

  const handleCanvasTap = (ev: ReactMouseEvent<HTMLCanvasElement>) => {
    if (!isCoarse) return
    const ch = chartRef.current
    if (!ch) return
    // getElementsAtEventForMode je v runtime Chart, ale verejne typy chart.js 4.4 ji nedeklaruji
    const chWithHit = ch as unknown as {
      getElementsAtEventForMode(
        e: Event,
        mode: string,
        options: { intersect: boolean },
        useFinalPosition: boolean,
      ): Array<{ index: number }>
    }
    const els = chWithHit.getElementsAtEventForMode(ev.nativeEvent, 'index', { intersect: false }, false)
    setTouchIdx(els.length ? els[0]!.index : null)
  }

  // Texty panelu reusují stejné formátování jako tooltip callbacks (% / °C).
  const touchInfo = useMemo(() => {
    if (!isCoarse || touchIdx == null || touchIdx < 0 || touchIdx >= slots.length) return null
    const fmt = (v: number | null | undefined, unit: string) =>
      v == null || Number.isNaN(v) ? '—' : `${v.toFixed(1)} ${unit}`
    return {
      title: labels[touchIdx] ?? '',
      rows: [
        { key: 'soc', label: 'SoC ■', text: fmt(series.socReal[touchIdx], '%'), color: '#1D9E75' },
        { key: 'soc_plan', label: 'SoC plán', text: fmt(series.socPlan[touchIdx], '%'), color: '#1D9E75' },
        { key: 'tuv', label: 'TUV ■', text: fmt(series.tuvReal[touchIdx], '°C'), color: '#EF9F27' },
        { key: 'tuv_plan', label: 'TUV cíl', text: fmt(series.tuvPlan[touchIdx], '°C'), color: '#EF9F27' },
      ],
    }
  }, [isCoarse, touchIdx, series, labels, slots.length])

  return (
    <div ref={wrapRef} className="relative">
      {touchInfo ? (
        <div className="absolute inset-x-1 bottom-full z-20 mb-1 rounded-lg border border-slate-700 bg-slate-950/95 px-3 py-2 shadow-xl">
          <div className="mb-1 flex items-center justify-between gap-2 text-[11px] font-semibold text-slate-100">
            <span>{touchInfo.title}</span>
            <button
              type="button"
              onClick={() => setTouchIdx(null)}
              className="px-1 text-slate-400"
              aria-label="Zavřít detail slotu"
            >
              ✕
            </button>
          </div>
          <div className="flex flex-wrap gap-x-3 gap-y-0.5 text-[10px]">
            {touchInfo.rows.map((r) => (
              <span key={r.key} style={{ color: r.color }}>
                {r.label}: <span className="text-slate-200">{r.text}</span>
              </span>
            ))}
          </div>
        </div>
      ) : null}
      <div className="h-[80px] w-full sm:h-[100px]">
        <canvas
          ref={canvasRef}
          onClick={handleCanvasTap}
          className="max-h-[80px] w-full sm:max-h-[100px]"
          role="img"
          aria-label="SoC a TUV"
        />
      </div>
    </div>
  )
}
