'use client'

import { useEffect, useMemo, useRef, useState } from 'react'
import { useRouter } from 'next/navigation'
import Link from 'next/link'

import { useI18n } from '@/components/providers/i18n-provider'
import { TimeSeriesChart } from '@/components/charts/time-series'
import { RiskGauge } from '@/components/charts/risk-gauge'
import { Button, Segmented, Select } from '@/components/ui/controls'
import {
  Badge,
  KeyValue,
  Meter,
  Panel,
  PanelBody,
  PanelHeader,
  StateBadge,
} from '@/components/ui/display'
import { cn } from '@/lib/cn'
import { riskToState, type GridState } from '@/lib/domain/enums'
import { CHART_COLORS, styleForRisk } from '@/lib/ui/state-styles'
import type { TimeMachineResult } from '@/lib/services/time-machine-service'

const OFFSET_LABEL_KEY: Record<number, string> = {
  0: 'now',
  5: '5',
  15: '15',
  30: '30',
  60: '60',
  180: '180',
  360: '360',
  720: '720',
  1440: '1440',
}

/**
 * The Energy Time Machine control.
 *
 * Moving the offset does not fetch anything: the whole trajectory arrives with the page,
 * so stepping through time is instantaneous. That matters for a demo — an audience
 * should see the future change the moment the presenter presses the button, not a
 * spinner.
 */
export function TimeMachine({
  result,
  assets,
}: {
  result: TimeMachineResult
  assets: Array<{ code: string; name: string; nameAr: string; risk: number }>
}) {
  const { t, locale, n, time, dateTime, duration } = useI18n()
  const router = useRouter()

  const [offset, setOffset] = useState(0)
  const [playing, setPlaying] = useState(false)
  const timerRef = useRef<number | undefined>(undefined)

  // Nearest computed frame to the requested offset.
  const frame = useMemo(() => {
    return result.frames.reduce((closest, candidate) =>
      Math.abs(candidate.offsetMin - offset) < Math.abs(closest.offsetMin - offset)
        ? candidate
        : closest,
    )
  }, [result.frames, offset])

  useEffect(() => {
    if (!playing) return
    timerRef.current = window.setInterval(() => {
      setOffset((current) => {
        const index = result.offsets.indexOf(current)
        if (index === -1 || index >= result.offsets.length - 1) {
          setPlaying(false)
          return current
        }
        return result.offsets[index + 1]
      })
    }, 1400)
    return () => window.clearInterval(timerRef.current)
  }, [playing, result.offsets])

  const chartData = result.frames
    .filter((entry) => entry.offsetMin <= Math.max(360, offset * 2 || 360))
    .map((entry) => ({
      ts: entry.ts,
      risk: entry.risk,
      riskWithAction: entry.riskWithAction,
    }))

  const breach = result.frames.find((entry) => entry.breached)
  const state = riskToState(frame.risk) as GridState

  return (
    <div className="space-y-6">
      <Panel>
        <PanelHeader
          title={t('timeMachine.selectAsset')}
          action={
            <div className="flex flex-wrap items-center gap-2">
              <Select
                aria-label={t('timeMachine.selectAsset')}
                value={result.assetCode}
                onChange={(event) => router.push(`/time-machine?asset=${event.target.value}`)}
                className="w-auto min-w-44"
              >
                {assets.map((asset) => (
                  <option key={asset.code} value={asset.code}>
                    {asset.code} — {Math.round(asset.risk)}%
                  </option>
                ))}
              </Select>
              <Link
                href={`/assets/${encodeURIComponent(result.assetCode)}`}
                className="text-xs font-medium text-brand hover:underline"
              >
                {t('commandCenter.openAsset')}
              </Link>
            </div>
          }
        />

        <PanelBody className="space-y-5">
          {/* Offset control */}
          <div className="flex flex-wrap items-center justify-between gap-3">
            <Segmented
              ariaLabel={t('timeMachine.offset')}
              value={String(offset)}
              onChange={(value) => {
                setPlaying(false)
                setOffset(Number(value))
              }}
              options={result.offsets.map((value) => ({
                value: String(value),
                label: t(`timeMachine.offsets.${OFFSET_LABEL_KEY[value] ?? value}`),
              }))}
            />
            <Button
              size="sm"
              variant={playing ? 'secondary' : 'outline'}
              onClick={() => {
                if (offset === result.offsets[result.offsets.length - 1]) setOffset(0)
                setPlaying((current) => !current)
              }}
            >
              {playing ? t('timeMachine.pause') : t('timeMachine.play')}
            </Button>
          </div>

          {/* Projected state */}
          <div className="grid gap-5 lg:grid-cols-[220px_1fr]">
            <div className="flex flex-col items-center rounded-lg border border-border bg-surface-2/40 p-4">
              <RiskGauge value={frame.risk} size={150} />
              <p className="mt-2 text-[11px] text-text-muted">{dateTime(frame.ts)}</p>
              {frame.riskWithAction !== null ? (
                <div className="mt-4 w-full border-t border-border pt-3 text-center">
                  <p className="text-[10px] uppercase tracking-wide text-text-faint">
                    {t('timeMachine.withAction')}
                  </p>
                  <p className={cn('tnum text-2xl font-semibold', styleForRisk(frame.riskWithAction).text)}>
                    {n(frame.riskWithAction, { maximumFractionDigits: 0 })}%
                  </p>
                </div>
              ) : null}
            </div>

            <div>
              <div className="mb-3 flex flex-wrap items-center gap-2">
                <StateBadge
                  state={state}
                  label={t(`states.${state}`)}
                  pulse={frame.risk >= 75}
                />
                <Badge tone="muted">
                  {t('timeMachine.projectedState')} ·{' '}
                  {offset === 0 ? t('common.now') : `+${duration(offset)}`}
                </Badge>
                {frame.breached ? (
                  <Badge tone="neutral">{t('incidents.replay.failure')}</Badge>
                ) : null}
              </div>

              <dl className="grid gap-x-8 gap-y-1 sm:grid-cols-2">
                <KeyValue
                  label={t('assets.columns.load')}
                  mono
                  value={
                    <>
                      {n(frame.loadPct, { maximumFractionDigits: 1 })}%
                      {frame.loadWithActionPct !== null ? (
                        <span className="ms-2 text-brand">
                          → {n(frame.loadWithActionPct, { maximumFractionDigits: 1 })}%
                        </span>
                      ) : null}
                    </>
                  }
                />
                <KeyValue
                  label={t('assets.columns.temperature')}
                  mono
                  value={
                    <>
                      {n(frame.tempC, { maximumFractionDigits: 1 })}
                      {t('common.units.celsius')}
                      {frame.tempWithActionC !== null ? (
                        <span className="ms-2 text-brand">
                          → {n(frame.tempWithActionC, { maximumFractionDigits: 1 })}
                        </span>
                      ) : null}
                    </>
                  }
                />
                <KeyValue
                  label={t('grid.electrical.voltage')}
                  mono
                  value={`${n(frame.voltageKv, { maximumFractionDigits: 2 })} ${t('common.units.kv')}`}
                />
                <KeyValue
                  label={t('grid.columns.temperature')}
                  mono
                  value={`${n(frame.ambientC, { maximumFractionDigits: 1 })}${t('common.units.celsius')}`}
                />
              </dl>

              <Meter value={frame.loadPct} max={130} state={state} className="mt-4" label={t('assets.columns.load')} showValue />

              <p className="mt-4 rounded-lg border border-border bg-surface/60 px-3 py-2.5 text-xs leading-relaxed text-text-muted">
                {result.etaMinutes !== null
                  ? t('timeMachine.breachAt', { time: time(result.ts + result.etaMinutes * 60_000) })
                  : t('timeMachine.noBreach')}{' '}
                {t('timeMachine.note')}
              </p>
            </div>
          </div>
        </PanelBody>
      </Panel>

      <Panel>
        <PanelHeader
          title={t('timeMachine.trajectory')}
          subtitle={
            result.strategyActions.length > 0
              ? result.strategyActions
                  .map((action) => (locale === 'ar' ? action.titleAr : action.title))
                  .join(' · ')
              : t('recommendations.empty')
          }
        />
        <PanelBody>
          <TimeSeriesChart
            data={chartData}
            height={280}
            yDomain={[0, 100]}
            ariaLabel={t('timeMachine.trajectory')}
            valueFormatter={(value) => `${n(value, { maximumFractionDigits: 0 })}%`}
            markers={[
              { x: result.ts, label: t('common.now'), color: CHART_COLORS.muted },
              ...(breach
                ? [
                    {
                      x: breach.ts,
                      label: t('incidents.replay.failure'),
                      color: CHART_COLORS.danger,
                    },
                  ]
                : []),
              { x: frame.ts, label: t('timeMachine.offset'), color: CHART_COLORS.tertiary },
            ]}
            series={[
              {
                key: 'risk',
                label: t('timeMachine.withoutAction'),
                color: CHART_COLORS.danger,
                type: 'area',
              },
              {
                key: 'riskWithAction',
                label: t('timeMachine.withAction'),
                color: CHART_COLORS.primary,
                type: 'line',
              },
            ]}
          />
        </PanelBody>
      </Panel>

      <Panel>
        <PanelHeader title={t('timeMachine.timeline')} />
        <PanelBody>
          <ol className="space-y-1.5">
            {result.offsets.map((value) => {
              const candidate = result.frames.reduce((closest, entry) =>
                Math.abs(entry.offsetMin - value) < Math.abs(closest.offsetMin - value)
                  ? entry
                  : closest,
              )
              const candidateState = riskToState(candidate.risk) as GridState
              const active = value === offset
              return (
                <li key={value}>
                  <button
                    type="button"
                    onClick={() => {
                      setPlaying(false)
                      setOffset(value)
                    }}
                    className={cn(
                      'flex w-full items-center gap-4 rounded-lg border px-3.5 py-2.5 text-start transition-colors',
                      active
                        ? 'border-brand/45 bg-brand/8'
                        : 'border-border bg-surface-2/40 hover:border-border-strong',
                    )}
                  >
                    <span className="tnum w-20 shrink-0 font-mono text-xs text-text-muted">
                      {time(candidate.ts)}
                    </span>
                    <StateBadge
                      state={candidateState}
                      label={t(`states.${candidateState}`)}
                      size="sm"
                    />
                    <span className="tnum text-xs text-text-muted">
                      {n(candidate.loadPct, { maximumFractionDigits: 0 })}% ·{' '}
                      {n(candidate.tempC, { maximumFractionDigits: 0 })}
                      {t('common.units.celsius')}
                    </span>
                    <span className="ms-auto flex items-center gap-3">
                      {candidate.riskWithAction !== null ? (
                        <span className="tnum text-[11px] text-brand">
                          {n(candidate.riskWithAction, { maximumFractionDigits: 0 })}%
                        </span>
                      ) : null}
                      <span
                        className={cn(
                          'tnum text-sm font-semibold',
                          styleForRisk(candidate.risk).text,
                        )}
                      >
                        {n(candidate.risk, { maximumFractionDigits: 0 })}%
                      </span>
                    </span>
                  </button>
                </li>
              )
            })}
          </ol>
        </PanelBody>
      </Panel>
    </div>
  )
}
