'use client'

import { useState } from 'react'

import { useI18n } from '@/components/providers/i18n-provider'
import { RiskDelta } from '@/components/charts/risk-gauge'
import { Button, Notice } from '@/components/ui/controls'
import { Badge, Panel, PanelBody, PanelHeader } from '@/components/ui/display'
import { api, ApiClientError, failureMessage } from '@/lib/api/client'
import { cn } from '@/lib/cn'
import { styleForRisk } from '@/lib/ui/state-styles'

export interface RecommendationAction {
  key: string
  actionType: string
  title: string
  titleAr: string
  description: string
  descriptionAr: string
  magnitudeMw: number
  durationMin: number
  costEstimateSar: number
  requiresRole: string
  riskBefore: number
  riskAfter: number
  riskReduction: number
  loadAfterPct: number
  tempAfterC: number
  /** Present when this candidate has a persisted recommendation row behind it. */
  recordId?: string
  status?: string
}

interface SimulationOutcome {
  riskBefore: number
  riskAfter: number
  loadBeforePct: number
  loadAfterPct: number
  tempBeforeC: number
  tempAfterC: number
  totalMw: number
  totalCostSar: number
  chosen: string[]
  evaluatedAtMin: number
  etaMinutes: number | null
  customersProtected: number
  downtimeAvoidedMin: number
  comparison: Array<{
    key: string
    label: string
    labelAr: string
    risk: number
    loadPct: number
    tempC: number
  }>
}

/**
 * The recommendation list and the SIMULATE control (§7).
 *
 * The order of operations is deliberate and enforced on the server too: an action can be
 * approved only after it has been simulated. Everything an operator sees here — the
 * expected reduction, the combined result — is measured by re-running the digital twin,
 * never a stored constant.
 */
export function RecommendationsPanel({
  assetCode,
  actions,
  etaMinutes,
  canSimulate,
  canApprove,
  canExecute,
  className,
}: {
  assetCode: string
  actions: RecommendationAction[]
  etaMinutes: number | null
  canSimulate: boolean
  canApprove: boolean
  canExecute: boolean
  className?: string
}) {
  const { t, locale, n, duration } = useI18n()

  const actionable = actions.filter((action) => action.riskReduction > 0.05)
  const [selected, setSelected] = useState<string[]>(() =>
    actionable.slice(0, 2).map((action) => action.key),
  )
  const [outcome, setOutcome] = useState<SimulationOutcome | null>(null)
  const [running, setRunning] = useState(false)
  const [error, setError] = useState<string | null>(null)
  const [statuses, setStatuses] = useState<Record<string, string>>(() =>
    Object.fromEntries(
      actions.filter((a) => a.recordId).map((a) => [a.recordId!, a.status ?? 'proposed']),
    ),
  )
  const [busyId, setBusyId] = useState<string | null>(null)

  const toggle = (key: string) => {
    setOutcome(null)
    setSelected((current) =>
      current.includes(key) ? current.filter((entry) => entry !== key) : [...current, key],
    )
  }

  const simulate = async () => {
    if (selected.length === 0 || running) return
    setRunning(true)
    setError(null)
    try {
      const result = await api.post<SimulationOutcome>('/api/simulations', {
        kind: 'action',
        assetCode,
        actionKeys: selected,
      })
      setOutcome(result)

      // Mark the selected recommendations as simulated so approval unlocks.
      const toMark = actions.filter(
        (action) => action.recordId && selected.includes(action.key) && statuses[action.recordId] === 'proposed',
      )
      for (const action of toMark) {
        try {
          const updated = await api.post<{ id: string; status: string }>(
            `/api/recommendations/${action.recordId}`,
          )
          setStatuses((current) => ({ ...current, [updated.id]: updated.status }))
        } catch {
          // Marking is a convenience; a failure here must not discard the result the
          // operator just asked for.
        }
      }
    } catch (caught) {
      setError(
        caught instanceof ApiClientError
          ? failureMessage(caught.failure, locale)
          : t('simulations.failed'),
      )
    } finally {
      setRunning(false)
    }
  }

  const decide = async (recordId: string, decision: 'approve' | 'reject' | 'execute') => {
    setBusyId(recordId)
    setError(null)
    try {
      const updated = await api.patch<{ id: string; status: string }>(
        `/api/recommendations/${recordId}`,
        { decision },
      )
      setStatuses((current) => ({ ...current, [updated.id]: updated.status }))
    } catch (caught) {
      setError(
        caught instanceof ApiClientError
          ? failureMessage(caught.failure, locale)
          : t('common.serverError'),
      )
    } finally {
      setBusyId(null)
    }
  }

  if (actionable.length === 0) {
    return (
      <Panel className={className}>
        <PanelHeader title={t('recommendations.title')} />
        <PanelBody>
          <p className="text-sm text-text-muted">{t('recommendations.empty')}</p>
        </PanelBody>
      </Panel>
    )
  }

  return (
    <Panel className={className}>
      <PanelHeader
        title={t('recommendations.title')}
        subtitle={t('recommendations.subtitle')}
        action={
          etaMinutes !== null ? (
            <Badge tone="info">
              {t('predictions.columns.eta')}: {duration(etaMinutes)}
            </Badge>
          ) : null
        }
      />

      <PanelBody className="space-y-3">
        {error ? <Notice tone="danger">{error}</Notice> : null}

        <ul className="space-y-2">
          {actionable.map((action) => {
            const checked = selected.includes(action.key)
            const status = action.recordId ? statuses[action.recordId] : undefined
            return (
              <li
                key={action.key}
                className={cn(
                  'rounded-lg border p-3.5 transition-colors',
                  checked ? 'border-brand/40 bg-brand/6' : 'border-border bg-surface-2/40',
                )}
              >
                <div className="flex items-start gap-3">
                  <input
                    type="checkbox"
                    checked={checked}
                    onChange={() => toggle(action.key)}
                    id={`action-${action.key}`}
                    className="mt-1 size-4 shrink-0 accent-brand"
                  />

                  <div className="min-w-0 flex-1">
                    <label
                      htmlFor={`action-${action.key}`}
                      className="flex cursor-pointer flex-wrap items-center gap-2"
                    >
                      <Badge tone="neutral">{t(`actionType.${action.actionType}`)}</Badge>
                      <span className="text-sm font-medium text-text">
                        {locale === 'ar' ? action.titleAr : action.title}
                      </span>
                      {status && status !== 'proposed' ? (
                        <Badge tone={status === 'executed' ? 'brand' : 'info'}>
                          {t(`recommendationStatus.${status}`)}
                        </Badge>
                      ) : null}
                    </label>

                    <p className="mt-1.5 text-xs leading-relaxed text-text-muted">
                      {locale === 'ar' ? action.descriptionAr : action.description}
                    </p>

                    <dl className="mt-2.5 flex flex-wrap gap-x-5 gap-y-1 text-[11px]">
                      {action.magnitudeMw > 0 ? (
                        <Stat
                          label={t('recommendations.magnitude')}
                          value={`${n(action.magnitudeMw, { maximumFractionDigits: 1 })} ${t('common.units.mw')}`}
                        />
                      ) : null}
                      <Stat label={t('recommendations.duration')} value={duration(action.durationMin)} />
                      {action.costEstimateSar > 0 ? (
                        <Stat
                          label={t('recommendations.cost')}
                          value={`${n(action.costEstimateSar, { maximumFractionDigits: 0 })} ${t('common.units.sar')}`}
                        />
                      ) : null}
                      <Stat
                        label={t('recommendations.requiresRole')}
                        value={t(`role.${action.requiresRole}`)}
                      />
                    </dl>
                  </div>

                  <div className="shrink-0 text-end">
                    <p className="text-[10px] uppercase tracking-wide text-text-faint">
                      {t('recommendations.expectedReduction')}
                    </p>
                    <p className="tnum text-xl font-semibold text-brand">
                      −{n(action.riskReduction, { maximumFractionDigits: 1 })}
                    </p>
                    <p className="tnum mt-0.5 text-[11px] text-text-muted">
                      {n(action.riskBefore, { maximumFractionDigits: 0 })}% →{' '}
                      <span className={styleForRisk(action.riskAfter).text}>
                        {n(action.riskAfter, { maximumFractionDigits: 0 })}%
                      </span>
                    </p>
                  </div>
                </div>

                {action.recordId && (canApprove || canExecute) ? (
                  <div className="mt-3 flex flex-wrap justify-end gap-2 border-t border-border/60 pt-3">
                    {canApprove && status === 'simulated' ? (
                      <>
                        <Button
                          size="sm"
                          variant="outline"
                          loading={busyId === action.recordId}
                          onClick={() => decide(action.recordId!, 'approve')}
                        >
                          {t('recommendations.approve')}
                        </Button>
                        <Button
                          size="sm"
                          variant="ghost"
                          loading={busyId === action.recordId}
                          onClick={() => decide(action.recordId!, 'reject')}
                        >
                          {t('recommendations.reject')}
                        </Button>
                      </>
                    ) : null}

                    {canExecute && status === 'approved' ? (
                      <Button
                        size="sm"
                        loading={busyId === action.recordId}
                        onClick={() => decide(action.recordId!, 'execute')}
                      >
                        {t('recommendations.execute')}
                      </Button>
                    ) : null}

                    {status === 'proposed' && canApprove ? (
                      <p className="text-[11px] text-text-faint">
                        {t('recommendations.simulateFirstNote')}
                      </p>
                    ) : null}
                  </div>
                ) : null}
              </li>
            )
          })}
        </ul>

        {canSimulate ? (
          <div className="flex flex-wrap items-center justify-between gap-3 border-t border-border pt-4">
            <p className="text-xs text-text-muted">{t('recommendations.combinedNote')}</p>
            <Button onClick={simulate} loading={running} disabled={selected.length === 0}>
              {running ? t('common.simulating') : t('common.simulateAction')}
            </Button>
          </div>
        ) : null}

        {outcome ? (
          <div className="nabdh-enter space-y-4 border-t border-border pt-4">
            <RiskDelta
              before={outcome.riskBefore}
              after={outcome.riskAfter}
              beforeLabel={t('simulations.comparison.noAction')}
              afterLabel={t('recommendations.combined')}
              note={t('timeMachine.note')}
            />

            <dl className="grid grid-cols-2 gap-3 sm:grid-cols-4">
              <Metric
                label={t('assets.columns.load')}
                value={`${n(outcome.loadBeforePct, { maximumFractionDigits: 0 })}% → ${n(outcome.loadAfterPct, { maximumFractionDigits: 0 })}%`}
              />
              <Metric
                label={t('assets.columns.temperature')}
                value={`${n(outcome.tempBeforeC, { maximumFractionDigits: 0 })} → ${n(outcome.tempAfterC, { maximumFractionDigits: 0 })} ${t('common.units.celsius')}`}
              />
              <Metric
                label={t('recommendations.magnitude')}
                value={`${n(outcome.totalMw, { maximumFractionDigits: 1 })} ${t('common.units.mw')}`}
              />
              <Metric
                label={t('recommendations.cost')}
                value={`${n(outcome.totalCostSar, { maximumFractionDigits: 0 })} ${t('common.units.sar')}`}
              />
            </dl>

            {/* Baseline vs single action vs full strategy (§24) */}
            <div className="overflow-x-auto">
              <table className="w-full text-xs">
                <caption className="sr-only">{t('simulations.comparison.title')}</caption>
                <thead>
                  <tr className="border-b border-border text-[10px] uppercase tracking-wide text-text-faint">
                    <th scope="col" className="px-2 py-2 text-start">
                      {t('common.scenario')}
                    </th>
                    <th scope="col" className="px-2 py-2 text-end">
                      {t('common.riskScore')}
                    </th>
                    <th scope="col" className="px-2 py-2 text-end">
                      {t('assets.columns.load')}
                    </th>
                    <th scope="col" className="px-2 py-2 text-end">
                      {t('assets.columns.temperature')}
                    </th>
                  </tr>
                </thead>
                <tbody>
                  {outcome.comparison.map((row) => (
                    <tr key={row.key} className="border-b border-border/60">
                      <td className="px-2 py-2 text-text">
                        {row.key === 'no_action'
                          ? t('simulations.comparison.noAction')
                          : row.key === 'ai_strategy'
                            ? t('simulations.comparison.aiStrategy')
                            : locale === 'ar'
                              ? row.labelAr
                              : row.label}
                      </td>
                      <td
                        className={`tnum px-2 py-2 text-end font-medium ${styleForRisk(row.risk).text}`}
                      >
                        {n(row.risk, { maximumFractionDigits: 0 })}%
                      </td>
                      <td className="tnum px-2 py-2 text-end text-text-muted">
                        {n(row.loadPct, { maximumFractionDigits: 0 })}%
                      </td>
                      <td className="tnum px-2 py-2 text-end text-text-muted">
                        {n(row.tempC, { maximumFractionDigits: 0 })}
                      </td>
                    </tr>
                  ))}
                </tbody>
              </table>
            </div>

            {outcome.customersProtected > 0 ? (
              <Notice tone="success">
                {t('demo.prevented.customersProtected')}:{' '}
                {n(outcome.customersProtected, { maximumFractionDigits: 0 })} ·{' '}
                {t('demo.prevented.downtimeAvoided')}: {duration(outcome.downtimeAvoidedMin)} ·{' '}
                {t('demo.prevented.note')}
              </Notice>
            ) : null}
          </div>
        ) : null}
      </PanelBody>
    </Panel>
  )
}

function Stat({ label, value }: { label: string; value: string }) {
  return (
    <div>
      <dt className="inline text-text-faint">{label}: </dt>
      <dd className="tnum inline font-medium text-text-muted">{value}</dd>
    </div>
  )
}

function Metric({ label, value }: { label: string; value: string }) {
  return (
    <div className="rounded-lg border border-border bg-surface-2/40 px-3 py-2.5">
      <dt className="text-[10px] uppercase tracking-wide text-text-faint">{label}</dt>
      <dd className="tnum mt-1 text-sm font-medium text-text">{value}</dd>
    </div>
  )
}
