'use client'

import { useEffect, useMemo, useState } from 'react'
import {
  Area,
  AreaChart,
  CartesianGrid,
  Line,
  LineChart,
  ReferenceLine,
  ResponsiveContainer,
  Tooltip,
  XAxis,
  YAxis,
} from 'recharts'

import { Segmented } from '@/components/ui/controls'
import { Badge, EmptyState, Skeleton } from '@/components/ui/display'
import { useI18n } from '@/components/providers/i18n-provider'
import { api } from '@/lib/api/client'
import { cn } from '@/lib/cn'
import { formatNumber } from '@/lib/i18n/translate'

/**
 * The live charts beside the scene (§26–§29).
 *
 * They are *synchronised* in the strong sense: the asset code is a prop, so selecting a
 * transformer in the 3D view changes what every chart is plotting in the same render. No
 * chart holds its own idea of what is selected, which is the only way nine charts can be
 * guaranteed to be showing the same asset.
 *
 * The series comes from the same engine the scene reads, so the last point of a chart and
 * the label floating above the asset are the same number by construction rather than by
 * coincidence.
 */

interface Point {
  ts: number
  loadPct: number
  loadMw: number
  voltageKv: number
  currentA: number
  activePowerMw: number
  reactivePowerMvar: number
  powerFactor: number
  tempC: number
  frequencyHz: number
  riskScore: number
}

interface History {
  assetCode: string
  windowMin: number
  kind: string
  points: Point[]
  nominalVoltageKv: number
  ratedTempC: number
  capacityMw: number
}

const WINDOWS = [
  { value: '1', label: '1m' },
  { value: '5', label: '5m' },
  { value: '15', label: '15m' },
  { value: '60', label: '1h' },
  { value: '360', label: '6h' },
  { value: '1440', label: '24h' },
] as const

type WindowValue = (typeof WINDOWS)[number]['value']

interface SeriesSpec {
  key: keyof Point
  labelKey: string
  unit: string
  colour: string
  digits: number
  /** A reference line drawn from the asset's own nameplate, where one applies. */
  reference?: (history: History) => number | null
  band?: 'area' | 'line'
}

const SERIES: SeriesSpec[] = [
  { key: 'voltageKv', labelKey: 'liveGrid.chart.voltage', unit: 'kV', colour: '#38bdf8', digits: 2, reference: (h) => h.nominalVoltageKv },
  { key: 'currentA', labelKey: 'liveGrid.chart.current', unit: 'A', colour: '#a78bfa', digits: 0 },
  { key: 'activePowerMw', labelKey: 'liveGrid.chart.activePower', unit: 'MW', colour: '#24d07f', digits: 2, band: 'area', reference: (h) => h.capacityMw },
  { key: 'reactivePowerMvar', labelKey: 'liveGrid.chart.reactivePower', unit: 'MVAr', colour: '#2f9e8f', digits: 2 },
  { key: 'frequencyHz', labelKey: 'liveGrid.chart.frequency', unit: 'Hz', colour: '#8fa3bd', digits: 3, reference: () => 60 },
  { key: 'powerFactor', labelKey: 'liveGrid.chart.powerFactor', unit: '', colour: '#c084fc', digits: 3 },
  { key: 'tempC', labelKey: 'liveGrid.chart.temperature', unit: '°C', colour: '#f97316', digits: 1, reference: (h) => h.ratedTempC },
  { key: 'loadPct', labelKey: 'liveGrid.chart.load', unit: '%', colour: '#fbbf24', digits: 1, band: 'area', reference: () => 100 },
  { key: 'riskScore', labelKey: 'liveGrid.chart.risk', unit: '', colour: '#ef4444', digits: 1, band: 'area' },
]

export function LiveCharts({
  assetCode,
  assetName,
  /** Bumped by the console on every stream tick, so the series follows the scene. */
  refreshToken,
  className,
}: {
  assetCode: string | null
  assetName: string | null
  refreshToken: number
  className?: string
}) {
  const { t, locale } = useI18n()
  const [windowMin, setWindowMin] = useState<WindowValue>('15')
  const [history, setHistory] = useState<History | null>(null)
  const [loading, setLoading] = useState(false)
  const [error, setError] = useState<string | null>(null)

  useEffect(() => {
    if (!assetCode) {
      setHistory(null)
      return
    }
    let cancelled = false
    setLoading(true)
    setError(null)

    const path = Number(windowMin) > 60 ? 'history' : 'telemetry'
    api
      .get<History>(`/api/live-grid/assets/${assetCode}/${path}?window=${windowMin}`)
      .then((result) => {
        if (!cancelled) setHistory(result)
      })
      .catch((caught: unknown) => {
        if (!cancelled) setError(caught instanceof Error ? caught.message : t('common.error'))
      })
      .finally(() => {
        if (!cancelled) setLoading(false)
      })

    return () => {
      cancelled = true
    }
  }, [assetCode, windowMin, refreshToken, t])

  const timeLabel = useMemo(
    () =>
      new Intl.DateTimeFormat(locale === 'ar' ? 'ar-SA' : 'en-GB', {
        hour: '2-digit',
        minute: '2-digit',
        hourCycle: 'h23',
      }),
    [locale],
  )

  if (!assetCode) {
    return (
      <div className={className}>
        <EmptyState title={t('liveGrid.chart.noSelection')} body={t('liveGrid.chart.selectHint')} />
      </div>
    )
  }

  return (
    <div className={cn('space-y-3', className)} data-testid="live-charts" data-chart-asset={assetCode}>
      <div className="flex flex-wrap items-center justify-between gap-2">
        <div className="min-w-0">
          <p className="truncate text-[12px] font-medium text-text">
            {assetName ?? assetCode}{' '}
            <span className="font-mono text-[11px] text-text-faint">{assetCode}</span>
          </p>
        </div>
        <div className="flex items-center gap-2">
          {history ? (
            <Badge tone="accent">
              {history.kind === 'simulated'
                ? t('liveGrid.kind.simulated')
                : t('liveGrid.kind.synthetic')}
            </Badge>
          ) : null}
          <Segmented
            value={windowMin}
            onChange={setWindowMin}
            ariaLabel={t('liveGrid.chart.window')}
            options={WINDOWS.map((entry) => ({ value: entry.value, label: entry.label }))}
          />
        </div>
      </div>

      {error ? <p className="text-[11px] text-critical">{error}</p> : null}

      {loading && !history ? (
        <div className="grid gap-2 sm:grid-cols-2">
          {Array.from({ length: 4 }).map((_, index) => (
            <Skeleton key={index} className="h-24" />
          ))}
        </div>
      ) : null}

      {history ? (
        <div className="grid gap-2 sm:grid-cols-2 2xl:grid-cols-3">
          {SERIES.map((series) => {
            const reference = series.reference?.(history) ?? null
            const values = history.points.map((point) => point[series.key] as number)
            const latest = values[values.length - 1] ?? 0
            const min = Math.min(...values)
            const max = Math.max(...values)
            // A flat series would otherwise render as a line pinned to an axis edge; a
            // small pad keeps a steady reading legible as a steady reading.
            const pad = Math.max((max - min) * 0.15, Math.abs(max) * 0.01, 0.001)

            return (
              <figure
                key={series.key}
                className="rounded-lg border border-border bg-surface-2/40 p-2.5"
                data-series={series.key}
              >
                <figcaption className="mb-1 flex items-baseline justify-between gap-2">
                  <span className="text-[10px] uppercase tracking-wide text-text-faint">
                    {t(series.labelKey)}
                  </span>
                  <span className="font-mono text-[12px] tabular-nums" style={{ color: series.colour }}>
                    {formatNumber(locale, latest, { maximumFractionDigits: series.digits })}
                    {series.unit ? ` ${series.unit}` : ''}
                  </span>
                </figcaption>

                <ResponsiveContainer width="100%" height={74}>
                  {series.band === 'area' ? (
                    <AreaChart data={history.points} margin={{ top: 2, right: 2, bottom: 0, left: 2 }}>
                      <defs>
                        <linearGradient id={`fill-${series.key}`} x1="0" y1="0" x2="0" y2="1">
                          <stop offset="0%" stopColor={series.colour} stopOpacity={0.45} />
                          <stop offset="100%" stopColor={series.colour} stopOpacity={0.03} />
                        </linearGradient>
                      </defs>
                      <CartesianGrid stroke="#1c2941" strokeDasharray="2 4" vertical={false} />
                      <XAxis dataKey="ts" hide />
                      <YAxis domain={[min - pad, max + pad]} hide />
                      <Tooltip
                        contentStyle={tooltipStyle}
                        labelFormatter={(value) => timeLabel.format(Number(value))}
                        formatter={(value) => [
                          `${formatNumber(locale, Number(value ?? 0), { maximumFractionDigits: series.digits })}${series.unit ? ` ${series.unit}` : ''}`,
                          t(series.labelKey),
                        ]}
                      />
                      {reference !== null ? (
                        <ReferenceLine y={reference} stroke="#5b6f89" strokeDasharray="3 3" />
                      ) : null}
                      <Area
                        type="monotone"
                        dataKey={series.key}
                        stroke={series.colour}
                        strokeWidth={1.6}
                        fill={`url(#fill-${series.key})`}
                        isAnimationActive={false}
                        dot={false}
                      />
                    </AreaChart>
                  ) : (
                    <LineChart data={history.points} margin={{ top: 2, right: 2, bottom: 0, left: 2 }}>
                      <CartesianGrid stroke="#1c2941" strokeDasharray="2 4" vertical={false} />
                      <XAxis dataKey="ts" hide />
                      <YAxis domain={[min - pad, max + pad]} hide />
                      <Tooltip
                        contentStyle={tooltipStyle}
                        labelFormatter={(value) => timeLabel.format(Number(value))}
                        formatter={(value) => [
                          `${formatNumber(locale, Number(value ?? 0), { maximumFractionDigits: series.digits })}${series.unit ? ` ${series.unit}` : ''}`,
                          t(series.labelKey),
                        ]}
                      />
                      {reference !== null ? (
                        <ReferenceLine y={reference} stroke="#5b6f89" strokeDasharray="3 3" />
                      ) : null}
                      <Line
                        type="monotone"
                        dataKey={series.key}
                        stroke={series.colour}
                        strokeWidth={1.6}
                        isAnimationActive={false}
                        dot={false}
                      />
                    </LineChart>
                  )}
                </ResponsiveContainer>
              </figure>
            )
          })}
        </div>
      ) : null}
    </div>
  )
}

const tooltipStyle: React.CSSProperties = {
  background: 'var(--color-surface)',
  border: '1px solid var(--color-border)',
  borderRadius: 8,
  fontSize: 11,
  padding: '4px 8px',
}
