'use client'

import { useCallback, useEffect, useRef, useState } from 'react'

import { Button, Notice, Segmented } from '@/components/ui/controls'
import { Badge, KeyValue, Panel, PanelBody, PanelHeader, StateBadge } from '@/components/ui/display'
import { useI18n } from '@/components/providers/i18n-provider'
import { cn } from '@/lib/cn'
import type { GridState } from '@/lib/domain/enums'
import { formatDateTime, formatNumber } from '@/lib/i18n/translate'

/**
 * Decision Proof and Replay (4.1).
 *
 * The screen answers one question — *why should I believe this?* — in the only way that
 * survives scrutiny: by showing what the platform actually had at the time. The model
 * version, the twin version, the snapshot it read, the physics verdict, the weakest link
 * in the chain, and every event in order.
 *
 * Playback reads frames the proof already holds. It never recomputes them: a replay that
 * re-derived each step would be a fresh analysis wearing a timeline, and could contradict
 * the decision it claims to be replaying.
 *
 * The third future is labelled by its own `kind`. In this build every outcome is
 * synthetic, and the column says so — a demo result is never presented as a failure that
 * was really prevented.
 */

export interface ProofViewModel {
  code: string
  assetCode: string
  decisionCode: string | null
  bundleCode: string
  modelVersion: string
  twinVersion: string
  dataSnapshotId: string
  twinSnapshotCode: string
  riskBefore: number
  riskAfter: number
  recommendation: string
  recommendationAr: string
  physicsVerdict: string
  weakestLinkKey: string
  weakestLinkScore: number
  measuredSharePct: number
  outcome: string
  evidenceKind: string
  createdAt: number
  frameCount: number
}

export interface FrameViewModel {
  seq: number
  ts: number
  stage: string
  title: string
  titleAr: string
  detail: string
  detailAr: string
  riskScore: number
  loadPct: number
  tempC: number
  state: string
  sourceType: string
  confidence: number
}

export interface ReplayViewModel {
  proof: ProofViewModel
  integrity: {
    hashed: boolean
    valid: boolean
    computed: string
    expected: string
    note: string
  }
  physics: {
    method: string
    converged: boolean
    iterations: number
    convergence: number
    impedanceSource: string
  }
  framePhysics: Record<
    number,
    {
      hasPhysics: boolean
      voltagePu: number
      angleDeg: number
      activeMw: number
      reactiveMvar: number
      currentA: number
      loadingPct: number
    }
  >
  timeline: {
    frames: FrameViewModel[]
    startTs: number
    endTs: number
    durationMin: number
    firstSignal: FrameViewModel | null
    predictedEvent: FrameViewModel | null
    decision: FrameViewModel | null
    outcome: FrameViewModel | null
    preventionWindowMin: number | null
    simulatedOnly: boolean
  }
  preventionWindowMin: number | null
  futures: Array<{
    key: string
    label: string
    labelAr: string
    riskAt: number
    loadPctAt: number
    tempCAt: number
    state: string
    kind: string
    available: boolean
  }>
  alternatives: {
    options: Array<{
      key: string
      label: string
      labelAr: string
      riskAfter: number
      costSar: number
      executionMin: number
      confidence: number
      rank: number
      isChosen: boolean
      deltaRisk: number
    }>
    chosen: { key: string } | null
    lowestRisk: { key: string } | null
  }
  similar: Array<{
    code: string
    title: string
    titleAr: string
    similarity: number
    outcomeStatus: string
    evidenceKind: string
    headline: string
    headlineAr: string
  }>
}

const SPEEDS = ['1', '2', '4'] as const

const STATES: readonly GridState[] = ['normal', 'watch', 'warning', 'critical', 'emergency']

function stateOf(value: string): GridState {
  return STATES.includes(value as GridState) ? (value as GridState) : 'normal'
}

export function DecisionReplay({ replay }: { replay: ReplayViewModel }) {
  const { t, locale } = useI18n()
  const frames = replay.timeline.frames

  const [index, setIndex] = useState(0)
  const [playing, setPlaying] = useState(false)
  const [speed, setSpeed] = useState<(typeof SPEEDS)[number]>('1')
  const timer = useRef<ReturnType<typeof setTimeout> | null>(null)

  const num = (value: number, digits = 0) =>
    formatNumber(locale, value, { maximumFractionDigits: digits })

  const step = useCallback(
    (delta: number) => setIndex((current) => Math.min(frames.length - 1, Math.max(0, current + delta))),
    [frames.length],
  )

  // Playback advances one recorded event at a time rather than interpolating between
  // them: the events are what happened, and the gaps between them are not.
  useEffect(() => {
    if (!playing || frames.length === 0) return
    if (index >= frames.length - 1) {
      setPlaying(false)
      return
    }
    timer.current = setTimeout(() => setIndex((current) => current + 1), 1_400 / Number(speed))
    return () => {
      if (timer.current) clearTimeout(timer.current)
    }
  }, [playing, index, speed, frames.length])

  if (frames.length === 0) {
    return <Notice tone="warning">{t('replay.empty')}</Notice>
  }

  const current = frames[Math.min(index, frames.length - 1)]
  const progress = frames.length > 1 ? index / (frames.length - 1) : 1

  return (
    <div className="space-y-4" data-testid="decision-replay">
      <Notice tone="info">{t('replay.note')}</Notice>
      {replay.timeline.simulatedOnly ? (
        <Notice tone="warning">{t('replay.syntheticWarning')}</Notice>
      ) : null}

      {/* ── Integrity (§26) ──────────────────────────────────────────────── */}
      <div
        className={cn(
          'rounded-[--radius-panel] border px-3.5 py-2.5 text-[11px] leading-relaxed',
          !replay.integrity.hashed
            ? 'border-border bg-surface-2/40 text-text-muted'
            : replay.integrity.valid
              ? 'border-normal/30 bg-normal/8 text-normal'
              : 'border-critical/40 bg-critical/8 text-critical',
        )}
        data-testid="proof-integrity"
        data-integrity={replay.integrity.hashed ? (replay.integrity.valid ? 'valid' : 'broken') : 'unhashed'}
      >
        <span className="font-medium">
          {!replay.integrity.hashed
            ? t('proof.integrityUnhashed')
            : replay.integrity.valid
              ? t('proof.integrityValid')
              : t('proof.integrityBroken')}
        </span>
        {replay.integrity.hashed ? (
          <span className="ms-2 font-mono text-[10px] opacity-80">
            {replay.integrity.expected.slice(0, 16)}…
          </span>
        ) : null}
        <p className="mt-1 text-text-muted">{replay.integrity.note}</p>
      </div>

      {/* ── Proof ────────────────────────────────────────────────────────────── */}
      <Panel>
        <PanelHeader
          title={t('proof.title')}
          subtitle={t('proof.note')}
          action={
            <Badge tone="accent">
              {replay.proof.evidenceKind === 'observed'
                ? t('proof.evidenceObserved')
                : t('proof.evidenceSimulated')}
            </Badge>
          }
        />
        <PanelBody>
          <dl className="grid gap-x-6 gap-y-1 sm:grid-cols-2" data-testid="proof-bundle">
            <KeyValue label={t('proof.bundle')} value={replay.proof.bundleCode} mono />
            <KeyValue label={t('proof.asset')} value={replay.proof.assetCode} mono />
            <KeyValue label={t('proof.modelVersion')} value={replay.proof.modelVersion} mono />
            <KeyValue label={t('proof.twinVersion')} value={replay.proof.twinVersion} mono />
            <KeyValue label={t('proof.snapshot')} value={replay.proof.dataSnapshotId} mono />
            <KeyValue label={t('proof.twinSnapshot')} value={replay.proof.twinSnapshotCode || '—'} mono />
            <KeyValue label={t('proof.physics')} value={replay.proof.physicsVerdict} />
            <KeyValue
              label={t('proof.weakestLink')}
              value={`${replay.proof.weakestLinkKey || '—'} · ${num(replay.proof.weakestLinkScore, 1)}%`}
            />
            <KeyValue
              label={t('proof.measuredShare')}
              value={`${num(replay.proof.measuredSharePct, 1)}%`}
            />
            <KeyValue label={t('proof.frames')} value={num(replay.proof.frameCount)} />
            <KeyValue label={t('proof.flowMethod')} value={replay.physics.method} mono />
            <KeyValue
              label={t('proof.convergence')}
              value={
                replay.physics.method === 'none'
                  ? t('proof.noFlow')
                  : replay.physics.converged
                    ? `${t('proof.converged')} · ${num(replay.physics.iterations)} · ${replay.physics.convergence.toExponential(1)}`
                    : t('proof.notConverged')
              }
              mono
            />
            <KeyValue label={t('proof.impedanceSource')} value={t(`proof.impedance.${replay.physics.impedanceSource}`)} />
            <KeyValue label={t('proof.riskBefore')} value={num(replay.proof.riskBefore, 1)} />
            <KeyValue label={t('proof.riskAfter')} value={num(replay.proof.riskAfter, 1)} />
          </dl>
          <p className="mt-2 text-[11px] leading-relaxed text-text-faint">
            {t('proof.weakestLinkNote')} {t('proof.measuredShareNote')}
          </p>
          <p className="mt-2 text-[12px] leading-relaxed">
            {locale === 'ar' ? replay.proof.recommendationAr : replay.proof.recommendation}
          </p>
        </PanelBody>
      </Panel>

      {/* ── Playback ─────────────────────────────────────────────────────────── */}
      <Panel>
        <PanelHeader
          title={t('replay.title')}
          subtitle={`${num(replay.timeline.durationMin, 0)} ${t('replay.duration')}`}
          action={
            replay.preventionWindowMin === null ? (
              <Badge tone="muted">{t('replay.noWindow')}</Badge>
            ) : (
<span data-testid="prevention-window">
                            <Badge tone="brand">
                {t('replay.preventionWindow')}: {num(replay.preventionWindowMin)} min
              </Badge>
              </span>
            )
          }
        />
        <PanelBody className="space-y-3">
          <div className="flex flex-wrap items-center gap-2">
            <Button size="sm" variant="secondary" onClick={() => step(-1)} disabled={index === 0}>
              {t('replay.stepBack')}
            </Button>
            <Button size="sm" variant="primary" onClick={() => setPlaying((value) => !value)}>
              {playing ? t('replay.pause') : t('replay.play')}
            </Button>
            <Button
              size="sm"
              variant="secondary"
              onClick={() => step(1)}
              disabled={index >= frames.length - 1}
            >
              {t('replay.stepForward')}
            </Button>
            <Button
              size="sm"
              variant="ghost"
              onClick={() => {
                setPlaying(false)
                setIndex(0)
              }}
            >
              {t('replay.restart')}
            </Button>
            <Segmented
              value={speed}
              onChange={setSpeed}
              ariaLabel={t('replay.speed')}
              options={SPEEDS.map((value) => ({ value, label: `${value}×` }))}
            />
          </div>

          {/* Progress across recorded events, not across wall-clock time. */}
          <div className="h-1 w-full overflow-hidden rounded-full bg-surface-2">
            <div
              className="h-full bg-brand transition-[width] duration-300"
              style={{ width: `${progress * 100}%` }}
            />
          </div>

          <div className="rounded-lg border border-border bg-surface-2/40 p-3" data-testid="replay-frame">
            <div className="flex flex-wrap items-center justify-between gap-2">
              <span className="text-[11px] uppercase tracking-wide text-text-faint">
                {t(`replay.stage.${current.stage}`)}
              </span>
              <span className="flex items-center gap-2">
                <StateBadge state={stateOf(current.state)} label={t(`states.${current.state}`)} size="sm" />
                <span className="font-mono text-[11px] tabular-nums text-text-faint">
                  {formatDateTime(locale, current.ts)}
                </span>
              </span>
            </div>
            <p className="mt-2 text-sm font-medium">{locale === 'ar' ? current.titleAr : current.title}</p>
            <p className="mt-1 text-[12px] leading-relaxed text-text-muted">
              {locale === 'ar' ? current.detailAr : current.detail}
            </p>
            <dl className="mt-2 grid grid-cols-2 gap-2 text-[11px] sm:grid-cols-4">
              <Figure label={t('proof.riskBefore')} value={num(current.riskScore, 1)} />
              <Figure label="MW %" value={`${num(current.loadPct, 1)}%`} />
              <Figure label="°C" value={num(current.tempC, 1)} />
              <Figure label={t('riskHunter.confidence')} value={`${num(current.confidence)}%`} />
            </dl>

            {/*
              The electrical state stored against this event (§27). Read from the record,
              never recomputed — a replay that re-derived each frame would be a fresh
              analysis wearing a timeline.
            */}
            {replay.framePhysics[current.seq]?.hasPhysics ? (
              <dl
                className="mt-2 grid grid-cols-2 gap-2 border-t border-border pt-2 text-[11px] sm:grid-cols-4"
                data-testid="frame-physics"
              >
                <Figure label="V pu" value={num(replay.framePhysics[current.seq].voltagePu, 4)} />
                <Figure label="θ°" value={num(replay.framePhysics[current.seq].angleDeg, 3)} />
                <Figure label="P MW" value={num(replay.framePhysics[current.seq].activeMw, 2)} />
                <Figure label="Q MVAr" value={num(replay.framePhysics[current.seq].reactiveMvar, 2)} />
              </dl>
            ) : (
              <p className="mt-2 border-t border-border pt-2 text-[11px] text-text-faint">
                {t('proof.noStoredPhysics')}
              </p>
            )}
          </div>

          {/* Every event, clickable. */}
          <ol className="space-y-1">
            {frames.map((frame, position) => (
              <li key={frame.seq}>
                <button
                  type="button"
                  onClick={() => {
                    setPlaying(false)
                    setIndex(position)
                  }}
                  data-frame={frame.stage}
                  className={cn(
                    'flex w-full flex-wrap items-baseline justify-between gap-2 rounded-lg border px-3 py-1.5 text-start text-[11px] transition-colors',
                    position === index
                      ? 'border-brand/50 bg-brand/8'
                      : 'border-border bg-surface-2/30 hover:border-brand/30',
                  )}
                >
                  <span>
                    <span className="me-2 font-mono text-text-faint">{frame.seq + 1}</span>
                    {locale === 'ar' ? frame.titleAr : frame.title}
                  </span>
                  <span className="font-mono tabular-nums text-text-faint">
                    {t(`replay.stage.${frame.stage}`)} · {formatDateTime(locale, frame.ts)}
                  </span>
                </button>
              </li>
            ))}
          </ol>

          {replay.preventionWindowMin !== null ? (
            <p className="text-[11px] leading-relaxed text-text-faint">
              {t('replay.preventionWindowNote')}
            </p>
          ) : null}
        </PanelBody>
      </Panel>

      {/* ── Three futures ────────────────────────────────────────────────────── */}
      <Panel>
        <PanelHeader title={t('replay.futures')} subtitle={t('replay.futuresNote')} />
        <PanelBody>
          <div className="grid gap-3 sm:grid-cols-3" data-testid="replay-futures">
            {replay.futures.map((future) => (
              <div
                key={future.key}
                data-future={future.key}
                data-future-kind={future.kind}
                className="rounded-lg border border-border bg-surface-2/40 p-3"
              >
                <div className="flex items-center justify-between gap-2">
                  <p className="text-[12px] font-medium">
                    {locale === 'ar' ? future.labelAr : future.label}
                  </p>
                  <Badge tone={future.kind === 'observed' ? 'brand' : 'accent'}>
                    {t(`replay.kind${future.kind[0].toUpperCase()}${future.kind.slice(1)}`)}
                  </Badge>
                </div>
                <p className={cn('mt-2 font-mono text-xl tabular-nums', riskTone(future.riskAt))}>
                  {num(future.riskAt, 1)}
                </p>
                <dl className="mt-2 grid grid-cols-2 gap-2 text-[11px]">
                  <Figure label="MW %" value={`${num(future.loadPctAt, 1)}%`} />
                  <Figure label="°C" value={num(future.tempCAt, 1)} />
                </dl>
                <div className="mt-2">
                  <StateBadge state={stateOf(future.state)} label={t(`states.${future.state}`)} size="sm" />
                </div>
              </div>
            ))}
          </div>
        </PanelBody>
      </Panel>

      {/* ── Alternatives ─────────────────────────────────────────────────────── */}
      {replay.alternatives.options.length > 0 ? (
        <Panel>
          <PanelHeader title={t('replay.alternatives')} subtitle={t('replay.alternativesNote')} />
          <PanelBody>
            <div className="overflow-x-auto">
              <table className="w-full min-w-[560px] text-[12px]">
                <thead className="text-[10px] uppercase tracking-wide text-text-faint">
                  <tr className="border-b border-border">
                    <th className="py-2 text-start font-medium">#</th>
                    <th className="py-2 text-start font-medium">{t('replay.alternatives')}</th>
                    <th className="py-2 text-end font-medium">{t('proof.riskAfter')}</th>
                    <th className="py-2 text-end font-medium">{t('replay.deltaRisk')}</th>
                    <th className="py-2 text-end font-medium">{t('riskHunter.cost')}</th>
                  </tr>
                </thead>
                <tbody>
                  {replay.alternatives.options.map((option) => (
                    <tr
                      key={option.key}
                      data-option={option.key}
                      className={cn('border-b border-border/50', option.isChosen && 'bg-brand/6')}
                    >
                      <td className="py-2 font-mono tabular-nums text-text-faint">{option.rank}</td>
                      <td className="py-2">
                        {locale === 'ar' ? option.labelAr : option.label}
                        {option.isChosen ? (
                          <Badge tone="brand" className="ms-2">
                            {t('replay.chosen')}
                          </Badge>
                        ) : null}
                        {replay.alternatives.lowestRisk?.key === option.key && !option.isChosen ? (
                          <Badge tone="info" className="ms-2">
                            {t('replay.lowestRisk')}
                          </Badge>
                        ) : null}
                      </td>
                      <td className="py-2 text-end font-mono tabular-nums">{num(option.riskAfter, 1)}</td>
                      <td
                        className={cn(
                          'py-2 text-end font-mono tabular-nums',
                          option.deltaRisk < 0 ? 'text-normal' : option.deltaRisk > 0 ? 'text-warning' : 'text-text-faint',
                        )}
                      >
                        {option.deltaRisk > 0 ? '+' : ''}
                        {num(option.deltaRisk, 1)}
                      </td>
                      <td className="py-2 text-end font-mono tabular-nums text-text-muted">
                        {num(option.costSar)}
                      </td>
                    </tr>
                  ))}
                </tbody>
              </table>
            </div>
          </PanelBody>
        </Panel>
      ) : null}

      {/* ── Similar decisions ────────────────────────────────────────────────── */}
      <Panel>
        <PanelHeader title={t('replay.similar')} />
        <PanelBody>
          {replay.similar.length === 0 ? (
            <p className="text-[12px] text-text-muted">{t('replay.noSimilar')}</p>
          ) : (
            <ul className="space-y-1.5">
              {replay.similar.map((entry) => (
                <li
                  key={entry.code}
                  className="flex flex-wrap items-baseline justify-between gap-2 rounded-lg border border-border bg-surface-2/40 px-3 py-2 text-[11px]"
                >
                  <span>{locale === 'ar' ? entry.headlineAr : entry.headline}</span>
                  <span className="flex items-center gap-2">
                    <Badge tone="accent">
                      {entry.evidenceKind === 'observed' ? t('proof.evidenceObserved') : t('proof.evidenceSimulated')}
                    </Badge>
                    <span className="font-mono tabular-nums text-text-faint">{num(entry.similarity)}%</span>
                  </span>
                </li>
              ))}
            </ul>
          )}
        </PanelBody>
      </Panel>
    </div>
  )

  function Figure({ label, value }: { label: string; value: string }) {
    return (
      <div>
        <dt className="text-text-faint">{label}</dt>
        <dd className="font-mono tabular-nums text-text">{value}</dd>
      </div>
    )
  }
}

function riskTone(value: number): string {
  if (value >= 75) return 'text-critical'
  if (value >= 55) return 'text-warning'
  if (value >= 35) return 'text-watch'
  return 'text-normal'
}
