'use client'

import { useCallback, useEffect, useState } from 'react'
import Link from 'next/link'

import { useI18n } from '@/components/providers/i18n-provider'
import { Button } from '@/components/ui/controls'
import { NationalMap, type MapAsset, type MapRegion } from '@/components/map/national-map'
import { TwinScene2D, type SceneAssetState, type SceneEdge, type SceneNode } from '@/components/twin/twin-scene-2d'
import { api, ApiClientError } from '@/lib/api/client'
import { cn } from '@/lib/cn'

/**
 * The immersive demo (§63–§66).
 *
 * Full screen, no chrome, one idea per step. A judging panel has three minutes and no
 * familiarity with the console, so this is the one surface in the product that is
 * *composed* rather than laid out: each step shows a single visual and a single sentence,
 * and the sequence carries the argument — signal, pattern, future, spread, choice,
 * outcome.
 *
 * Every number in it is computed. The step captions are written; the figures they quote
 * are read from the same engines the operational pages use, so a judge who then opens the
 * console finds the same values waiting for them.
 */

export interface ImmersivePayload {
  assetCode: string
  regionName: string
  regionNameAr: string
  stabilityIndex: number
  gridState: string
  map: { assets: MapAsset[]; regions: MapRegion[] }
  scene: { nodes: SceneNode[]; edges: SceneEdge[] }
  assets: SceneAssetState[]
  weakSignal: { combinedScore: number; traditionalAlarm: boolean; leadMinutes: number | null }
  dna: { code: string; similarity: number; name: string; nameAr: string } | null
  prediction: { etaMinutes: number | null; peakRisk: number; currentRisk: number; confidence: number }
  cascade: Array<{ assetCode: string; offsetMin: number; outcome: string; probability: number }>
  branches: Array<{ key: string; label: string; labelAr: string; risk: number; assetsAffected: number; potentialDowntimeMin: number }>
  strategies: Array<{ label: string; labelAr: string; riskBefore: number; riskAfter: number; score: number; isRecommended: boolean }>
  counterfactual: { achieved: boolean; riskBefore: number; riskAfter: number; doses: Array<{ label: string; labelAr: string }> } | null
  ghost: { nowLoad: number; futureLoad: number; nowTemp: number; futureTemp: number; offsetMin: number } | null
}

const STEPS = 10
const SCENARIOS = ['extreme_heat', 'demand_surge', 'transformer_failure', 'renewable_drop'] as const

export function ImmersiveDemo({ payload }: { payload: ImmersivePayload }) {
  const { t, locale, n } = useI18n()
  const ar = locale === 'ar'

  const [step, setStep] = useState(0)
  const [judge, setJudge] = useState<{ running: boolean; scenario: string | null; risk: number | null; label: string | null }>(
    { running: false, scenario: null, risk: null, label: null },
  )
  const [error, setError] = useState<string | null>(null)

  const next = useCallback(() => setStep((current) => Math.min(current + 1, STEPS)), [])
  const previous = useCallback(() => setStep((current) => Math.max(current - 1, 0)), [])

  // Arrow keys and space, because a presenter's hands are on a clicker, not a mouse.
  useEffect(() => {
    const onKeyDown = (event: KeyboardEvent) => {
      if (event.key === 'ArrowRight' || event.key === ' ' || event.key === 'PageDown') {
        event.preventDefault()
        next()
      } else if (event.key === 'ArrowLeft' || event.key === 'PageUp') {
        event.preventDefault()
        previous()
      }
    }
    window.addEventListener('keydown', onKeyDown)
    return () => window.removeEventListener('keydown', onKeyDown)
  }, [next, previous])

  const runJudgeScenario = async (scenario: (typeof SCENARIOS)[number]) => {
    setJudge({ running: true, scenario, risk: null, label: null })
    setError(null)
    try {
      const overlays: Record<string, Record<string, number | string>> = {
        extreme_heat: { tempDeltaC: 7, loadDeltaPct: 14, regionCode: 'RYD' },
        demand_surge: { loadDeltaPct: 26, regionCode: 'RYD' },
        transformer_failure: { loadDeltaPct: 30, regionCode: 'RYD' },
        renewable_drop: { solarDeltaPct: -55, loadDeltaPct: 10, regionCode: 'RYD' },
      }
      const result = await api.post<{ orchestration: { unifiedRisk: number; recommended: { label: string; labelAr: string } | null } }>(
        '/api/agents/run',
        { assetCode: payload.assetCode, overlay: overlays[scenario] },
      )
      setJudge({
        running: false,
        scenario,
        risk: result.orchestration.unifiedRisk,
        label: result.orchestration.recommended
          ? ar
            ? result.orchestration.recommended.labelAr
            : result.orchestration.recommended.label
          : null,
      })
    } catch (cause) {
      setError(cause instanceof ApiClientError ? (ar ? cause.failure.messageAr : cause.failure.message) : String(cause))
      setJudge({ running: false, scenario, risk: null, label: null })
    }
  }

  const propagating = payload.cascade.filter((entry) => entry.outcome === 'failed')
  const noAction = payload.branches.find((branch) => branch.key === 'no_action')
  const withNabdh = payload.branches.find((branch) => branch.key === 'nabdh_strategy')
  const best = payload.strategies.find((strategy) => strategy.isRecommended) ?? payload.strategies[0]

  return (
    <div className="nabdh-grid-bg nabdh-radial relative flex min-h-dvh flex-col bg-base">
      {/* Progress rail: a judge should always know how much is left. */}
      <div className="flex gap-1 px-6 pt-5">
        {Array.from({ length: STEPS + 1 }, (_, index) => (
          <button
            key={index}
            type="button"
            onClick={() => setStep(index)}
            aria-label={`${index + 1}`}
            aria-current={index === step}
            className={cn(
              'h-0.5 flex-1 rounded-full transition-colors',
              index <= step ? 'bg-brand' : 'bg-border',
            )}
          />
        ))}
      </div>

      <header className="flex items-center justify-between gap-4 px-6 py-4">
        <div>
          <p className="type-h3 text-brand">NABDH · نَبْض</p>
          <p className="text-[11px] text-text-faint">{t('immersive.tagline')}</p>
        </div>
        <Link href="/hackathon" className="text-[11px] font-medium text-text-muted hover:text-text">
          {t('immersive.exit')}
        </Link>
      </header>

      <main className="flex flex-1 flex-col items-center justify-center px-6 pb-10">
        <div className="w-full max-w-5xl">
          {/* ── 0. Title ────────────────────────────────────────────────── */}
          {step === 0 ? (
            <div className="nabdh-enter text-center">
              <p className="type-display text-text">NABDH</p>
              <p className="mt-2 text-lg text-brand">نَبْض</p>
              <p className="mt-6 text-sm text-text-muted">{t('immersive.closing')}</p>
              <Button className="mt-8" size="lg" onClick={next}>
                {t('immersive.start')}
              </Button>
            </div>
          ) : null}

          {/* ── 1. The grid ─────────────────────────────────────────────── */}
          {step === 1 ? (
            <div className="nabdh-enter">
              <Caption index={1} title={t('immersive.step.1')} />
              <div className="mt-4 overflow-hidden rounded-[--radius-panel] border border-border">
                <NationalMap assets={payload.map.assets} regions={payload.map.regions} compact />
              </div>
              <Figures
                items={[
                  { label: t('commandCenter.cards.gridStability'), value: n(payload.stabilityIndex, { maximumFractionDigits: 1 }) },
                  { label: t('states.normal'), value: t(`states.${payload.gridState}`) },
                ]}
              />
            </div>
          ) : null}

          {/* ── 2. Weak signals ─────────────────────────────────────────── */}
          {step === 2 ? (
            <div className="nabdh-enter text-center">
              <Caption index={2} title={t('immersive.step.2')} />
              <p className="type-display mt-8 text-watch">
                {n(payload.weakSignal.combinedScore, { maximumFractionDigits: 0 })}%
              </p>
              <p className="mt-2 text-sm text-text-muted">{t('weakSignals.combined')}</p>
              <p
                className={cn(
                  'mx-auto mt-6 max-w-xl rounded-lg border px-4 py-3 text-sm leading-relaxed',
                  payload.weakSignal.traditionalAlarm
                    ? 'border-critical/30 bg-critical/8 text-critical'
                    : 'border-brand/30 bg-brand/8 text-brand',
                )}
              >
                {payload.weakSignal.traditionalAlarm
                  ? t('weakSignals.traditionalSounding')
                  : t('weakSignals.traditionalSilent')}
              </p>
              {payload.weakSignal.leadMinutes ? (
                <p className="tnum mt-4 text-sm text-normal">
                  {t('hackathon.leadTime')}: {n(payload.weakSignal.leadMinutes)} {t('common.minutes')}
                </p>
              ) : null}
            </div>
          ) : null}

          {/* ── 3. Into the twin ────────────────────────────────────────── */}
          {step === 3 ? (
            <div className="nabdh-enter">
              <Caption index={3} title={t('immersive.step.3')} />
              <div className="mt-4 overflow-hidden rounded-[--radius-panel] border border-border bg-surface/40">
                <TwinScene2D
                  nodes={payload.scene.nodes}
                  edges={payload.scene.edges}
                  assets={payload.assets}
                  view="thermal"
                  layers={{ assets: true, flow: true, risk: true, sensors: false, cascade: false, labels: true }}
                  selectedCode={payload.assetCode}
                />
              </div>
              <Figures
                items={[
                  { label: t('aiOps.focusAsset'), value: payload.assetCode },
                  {
                    label: t('assets.columns.temperature'),
                    value: `${n(payload.assets.find((a) => a.code === payload.assetCode)?.tempC ?? 0, { maximumFractionDigits: 0 })} °C`,
                  },
                  {
                    label: t('assets.columns.load'),
                    value: `${n(payload.assets.find((a) => a.code === payload.assetCode)?.loadPct ?? 0, { maximumFractionDigits: 0 })}%`,
                  },
                ]}
              />
            </div>
          ) : null}

          {/* ── 4. Failure DNA ──────────────────────────────────────────── */}
          {step === 4 ? (
            <div className="nabdh-enter text-center">
              <Caption index={4} title={t('immersive.step.4')} />
              <p className="type-display mt-8 text-accent">
                {payload.dna ? n(payload.dna.similarity, { maximumFractionDigits: 0 }) : '—'}%
              </p>
              <p className="mt-2 font-mono text-sm text-text-muted">{payload.dna?.code}</p>
              <p className="mt-4 text-sm text-text">
                {payload.dna ? (ar ? payload.dna.nameAr : payload.dna.name) : ''}
              </p>
            </div>
          ) : null}

          {/* ── 5. Ghost future ─────────────────────────────────────────── */}
          {step === 5 && payload.ghost ? (
            <div className="nabdh-enter">
              <Caption index={5} title={t('immersive.step.5')} />
              <div className="mt-8 grid gap-6 sm:grid-cols-2">
                <GhostColumn
                  title={t('twin.ghostNow')}
                  load={payload.ghost.nowLoad}
                  temp={payload.ghost.nowTemp}
                  tone="brand"
                  n={n}
                  t={t}
                />
                <GhostColumn
                  title={t('twin.ghostFuture', { minutes: String(payload.ghost.offsetMin) })}
                  load={payload.ghost.futureLoad}
                  temp={payload.ghost.futureTemp}
                  tone="critical"
                  n={n}
                  t={t}
                />
              </div>
              {payload.prediction.etaMinutes !== null ? (
                <p className="tnum mt-8 text-center text-sm text-critical">
                  {t('preventionWindow.eventIn')} ~{n(payload.prediction.etaMinutes)}{' '}
                  {t('common.minutes')} · {t('preventionWindow.estimated')}
                </p>
              ) : null}
            </div>
          ) : null}

          {/* ── 6. Cascade ──────────────────────────────────────────────── */}
          {step === 6 ? (
            <div className="nabdh-enter">
              <Caption index={6} title={t('immersive.step.6')} />
              {propagating.length <= 1 ? (
                <p className="mt-8 text-center text-sm leading-relaxed text-text-muted">
                  {t('cascade.empty')}
                </p>
              ) : (
                <ol className="mx-auto mt-8 max-w-xl space-y-3">
                  {propagating.slice(0, 6).map((entry, index) => (
                    <li key={`${entry.assetCode}-${index}`} className="flex items-center gap-4">
                      <span className="tnum w-16 shrink-0 text-end text-sm text-text-faint">
                        +{n(entry.offsetMin)}
                      </span>
                      <span
                        aria-hidden
                        className="size-2.5 shrink-0 rounded-full bg-critical"
                        style={{ opacity: 0.4 + entry.probability * 0.6 }}
                      />
                      <span className="font-mono text-sm text-text">{entry.assetCode}</span>
                      <span className="tnum ms-auto text-xs text-text-faint">
                        {n(entry.probability * 100, { maximumFractionDigits: 0 })}%
                      </span>
                    </li>
                  ))}
                </ol>
              )}
            </div>
          ) : null}

          {/* ── 7. Two futures ──────────────────────────────────────────── */}
          {step === 7 && noAction && withNabdh ? (
            <div className="nabdh-enter">
              <Caption index={7} title={t('immersive.step.7')} />
              <div className="mt-8 grid gap-4 md:grid-cols-2">
                <BranchColumn
                  title={t('twin.without')}
                  risk={noAction.risk}
                  assets={noAction.assetsAffected}
                  downtime={noAction.potentialDowntimeMin}
                  tone="critical"
                  n={n}
                  t={t}
                />
                <BranchColumn
                  title={t('twin.with')}
                  risk={withNabdh.risk}
                  assets={withNabdh.assetsAffected}
                  downtime={withNabdh.potentialDowntimeMin}
                  tone="normal"
                  n={n}
                  t={t}
                />
              </div>
            </div>
          ) : null}

          {/* ── 8. Strategies ───────────────────────────────────────────── */}
          {step === 8 ? (
            <div className="nabdh-enter">
              <Caption index={8} title={t('immersive.step.8')} />
              <ul className="mx-auto mt-8 max-w-2xl space-y-2">
                {payload.strategies.map((strategy, index) => (
                  <li
                    key={index}
                    className={cn(
                      'flex flex-wrap items-center justify-between gap-3 rounded-lg border px-4 py-3',
                      strategy.isRecommended ? 'border-brand/45 bg-brand/8' : 'border-border bg-surface/50',
                    )}
                  >
                    <span className={cn('text-sm', strategy.isRecommended ? 'text-brand' : 'text-text-muted')}>
                      {ar ? strategy.labelAr : strategy.label}
                    </span>
                    <span className="tnum text-sm">
                      <span className="text-critical">{n(strategy.riskBefore, { maximumFractionDigits: 0 })}%</span>
                      {' → '}
                      <span className="text-normal">{n(strategy.riskAfter, { maximumFractionDigits: 0 })}%</span>
                    </span>
                  </li>
                ))}
              </ul>
            </div>
          ) : null}

          {/* ── 9. Minimum intervention ─────────────────────────────────── */}
          {step === 9 ? (
            <div className="nabdh-enter text-center">
              <Caption index={9} title={t('immersive.step.9')} />
              {payload.counterfactual ? (
                <>
                  <p className="type-display mt-8">
                    <span className="text-critical">
                      {n(payload.counterfactual.riskBefore, { maximumFractionDigits: 0 })}%
                    </span>
                    <span className="mx-4 text-text-faint">→</span>
                    <span className="text-normal">
                      {n(payload.counterfactual.riskAfter, { maximumFractionDigits: 0 })}%
                    </span>
                  </p>
                  <ul className="mx-auto mt-8 max-w-lg space-y-2">
                    {payload.counterfactual.doses.map((dose, index) => (
                      <li
                        key={index}
                        className="rounded-lg border border-brand/30 bg-brand/8 px-4 py-2.5 text-sm text-brand"
                      >
                        {ar ? dose.labelAr : dose.label}
                      </li>
                    ))}
                  </ul>
                </>
              ) : null}
            </div>
          ) : null}

          {/* ── 10. Outcome and judge mode ──────────────────────────────── */}
          {step === 10 ? (
            <div className="nabdh-enter text-center">
              <p className="type-h3 text-brand">{t('immersive.step.10')}</p>
              <p className="type-display mt-6 text-normal">{t('immersive.prevented')}</p>
              {best ? (
                <p className="tnum mt-4 text-lg">
                  <span className="text-critical">{n(best.riskBefore, { maximumFractionDigits: 0 })}%</span>
                  <span className="mx-3 text-text-faint">→</span>
                  <span className="text-normal">{n(best.riskAfter, { maximumFractionDigits: 0 })}%</span>
                </p>
              ) : null}
              <p className="mt-2 text-xs text-accent">{t('futures.estimate')}</p>
              <p className="mt-8 text-sm text-text-muted">{t('immersive.closing')}</p>

              {/* Judge mode (§47, §65) */}
              <div className="mx-auto mt-10 max-w-2xl rounded-[--radius-panel] border border-border bg-surface/60 p-5">
                <p className="type-h3 text-text">{t('immersive.tryIt')}</p>
                <p className="mt-1 text-[11px] text-text-muted">{t('hackathon.judgeHint')}</p>
                <div className="mt-4 flex flex-wrap justify-center gap-2">
                  {SCENARIOS.map((scenario) => (
                    <Button
                      key={scenario}
                      size="sm"
                      variant={judge.scenario === scenario ? 'primary' : 'secondary'}
                      onClick={() => runJudgeScenario(scenario)}
                      loading={judge.running && judge.scenario === scenario}
                    >
                      {t(`resilience.disturbance.${scenario === 'transformer_failure' ? 'multi_failure' : scenario === 'extreme_heat' ? 'heat_wave' : scenario}`)}
                    </Button>
                  ))}
                </div>
                {error ? <p className="mt-3 text-[11px] text-critical">{error}</p> : null}
                {judge.risk !== null ? (
                  <div className="mt-4">
                    <p className="tnum text-2xl font-semibold text-critical">
                      {n(judge.risk, { maximumFractionDigits: 0 })}%
                    </p>
                    <p className="text-[11px] text-text-faint">{t('aiOps.unifiedRisk')}</p>
                    {judge.label ? (
                      <p className="mt-2 text-[11px] text-brand">{judge.label}</p>
                    ) : null}
                  </div>
                ) : null}
              </div>
            </div>
          ) : null}
        </div>
      </main>

      <footer className="flex items-center justify-between gap-4 border-t border-border px-6 py-3">
        <Button variant="ghost" size="sm" onClick={previous} disabled={step === 0}>
          ←
        </Button>
        <p className="tnum text-[11px] text-text-faint">
          {step + 1} / {STEPS + 1}
        </p>
        {step === STEPS ? (
          <Button size="sm" variant="secondary" onClick={() => setStep(0)}>
            {t('immersive.replay')}
          </Button>
        ) : (
          <Button size="sm" onClick={next}>
            {t('immersive.next')} →
          </Button>
        )}
      </footer>
    </div>
  )
}

function Caption({ index, title }: { index: number; title: string }) {
  return (
    <div className="text-center">
      <p className="tnum type-h3 text-text-faint">{String(index).padStart(2, '0')}</p>
      <h2 className="type-h1 mt-1 text-text">{title}</h2>
    </div>
  )
}

function Figures({ items }: { items: Array<{ label: string; value: string }> }) {
  return (
    <div className="mt-5 flex flex-wrap justify-center gap-x-10 gap-y-3">
      {items.map((item) => (
        <div key={item.label} className="text-center">
          <p className="tnum text-2xl font-semibold text-text">{item.value}</p>
          <p className="text-[11px] text-text-faint">{item.label}</p>
        </div>
      ))}
    </div>
  )
}

function GhostColumn({
  title,
  load,
  temp,
  tone,
  n,
  t,
}: {
  title: string
  load: number
  temp: number
  tone: 'brand' | 'critical'
  n: (value: number, options?: Intl.NumberFormatOptions) => string
  t: (key: string) => string
}) {
  return (
    <div
      className={cn(
        'rounded-[--radius-panel] border p-6 text-center',
        tone === 'brand' ? 'border-brand/40 bg-brand/6' : 'border-critical/40 bg-critical/6',
      )}
    >
      <p className="type-h3 text-text-faint">{title}</p>
      <p className={cn('tnum mt-4 text-4xl font-semibold', tone === 'brand' ? 'text-brand' : 'text-critical')}>
        {n(load, { maximumFractionDigits: 0 })}%
      </p>
      <p className="mt-1 text-[11px] text-text-faint">{t('assets.columns.load')}</p>
      <p className="tnum mt-4 text-xl font-semibold text-text">{n(temp, { maximumFractionDigits: 0 })} °C</p>
      <p className="mt-1 text-[11px] text-text-faint">{t('assets.columns.temperature')}</p>
    </div>
  )
}

function BranchColumn({
  title,
  risk,
  assets,
  downtime,
  tone,
  n,
  t,
}: {
  title: string
  risk: number
  assets: number
  downtime: number
  tone: 'critical' | 'normal'
  n: (value: number, options?: Intl.NumberFormatOptions) => string
  t: (key: string) => string
}) {
  return (
    <div
      className={cn(
        'rounded-[--radius-panel] border p-6 text-center',
        tone === 'critical' ? 'border-critical/40 bg-critical/6' : 'border-normal/40 bg-normal/6',
      )}
    >
      <p className="type-h3 text-text-faint">{title}</p>
      <p className={cn('type-display mt-3', tone === 'critical' ? 'text-critical' : 'text-normal')}>
        {n(risk, { maximumFractionDigits: 0 })}%
      </p>
      <dl className="mt-4 space-y-1 text-[11px]">
        <div className="flex justify-between gap-2">
          <dt className="text-text-muted">{t('futures.assets')}</dt>
          <dd className="tnum text-text">{n(assets)}</dd>
        </div>
        <div className="flex justify-between gap-2">
          <dt className="text-text-muted">{t('futures.downtime')}</dt>
          <dd className="tnum text-text">
            {n(downtime)} {t('common.minutes')}
          </dd>
        </div>
      </dl>
    </div>
  )
}
