'use client'

/**
 * AutoRepairPanel — 自動修復面板 (不含 AppLayout)
 * ==================================================
 * Sprint 5: 從 /auto-repair/page.tsx 抽取
 * 供原始頁面和整合頁面 (/automation) 共用
 *
 * 建立時間: 2026-04-09 (台北時區)
 */

import { useState, useEffect, useCallback, useRef } from 'react'
import { useTranslations } from 'next-intl'
import { useIncidents } from '@/hooks/useIncidents'
import { cn } from '@/lib/utils'
import {
  Wrench, RefreshCw, AlertCircle,
  CheckCircle2, XCircle, ShieldAlert,
  Play, ChevronDown, ChevronUp, Zap,
} from 'lucide-react'

// =============================================================================
// Types
// =============================================================================

interface DispositionSummary {
  auto_repair: number
  human_approved: number
  manual_resolved: number
  cold_start_trust: number
  total: number
  auto_rate: number
}

interface AutoRepairStats {
  approved_playbooks: number
  high_quality_playbooks: number
  total_executions: number
  overall_success_rate: number
  auto_repair_eligible: boolean
  disposition_summary?: DispositionSummary
}

interface EvaluateResponse {
  can_auto_repair: boolean
  playbook_id: string | null
  playbook_name: string | null
  reason: string
  risk_level: string
  blocked_by: string | null
  success_rate: number | null
  total_executions: number | null
}

interface ExecuteResponse {
  success: boolean
  incident_id: string
  playbook_id: string
  executed_steps: string[]
  error: string | null
  execution_time_ms: number
}

// =============================================================================
// Helpers
// =============================================================================

const getApiBaseUrl = () => {
  if (typeof window === 'undefined') return ''
  const url = process.env.NEXT_PUBLIC_API_URL
  if (!url) console.error('[AWOOOI ERROR] Missing NEXT_PUBLIC_API_URL') // eslint-disable-line no-console
  return url ?? ''
}

const RISK_STYLE: Record<string, string> = {
  LOW:      'bg-status-healthy/10 text-status-healthy border-status-healthy/20',
  MEDIUM:   'bg-status-warning/10 text-status-warning border-status-warning/20',
  HIGH:     'bg-status-critical/10 text-status-critical border-status-critical/20',
  CRITICAL: 'bg-status-critical/10 text-status-critical border-status-critical/20',
}

// =============================================================================
// StatCard
// =============================================================================

function StatCard({
  label, value, sub, highlight,
}: { label: string; value: string | number; sub?: string; highlight?: boolean }) {
  return (
    <div className={cn(
      'rounded-lg border p-4',
      highlight ? 'bg-claw-blue/5 border-claw-blue/20' : 'bg-white border-nothing-gray-200'
    )}>
      <p className="text-[11px] font-body text-nothing-gray-500 uppercase tracking-wider mb-1">{label}</p>
      <p className={cn('text-2xl font-bold font-body tabular-nums', highlight ? 'text-claw-blue' : 'text-nothing-black')}>
        {value}
      </p>
      {sub && <p className="text-[11px] font-body text-nothing-gray-400 mt-0.5">{sub}</p>}
    </div>
  )
}

// =============================================================================
// IncidentEvalRow
// =============================================================================

function IncidentEvalRow({
  incidentId, severity,
}: { incidentId: string; severity: string }) {
  const t = useTranslations('autoRepair')
  const [eval_, setEval] = useState<EvaluateResponse | null>(null)
  const [loading, setLoading] = useState(false)
  const [executing, setExecuting] = useState(false)
  const [result, setResult] = useState<ExecuteResponse | null>(null)
  const [expanded, setExpanded] = useState(false)

  const fetchEval = useCallback(async () => {
    const base = getApiBaseUrl()
    if (!base) return
    setLoading(true)
    try {
      const res = await fetch(`${base}/api/v1/auto-repair/evaluate/${incidentId}`)
      if (res.ok) {
        setEval(await res.json())
      }
    } catch {
      // API 不可用時靜默處理
    } finally {
      setLoading(false)
    }
  }, [incidentId])

  useEffect(() => { fetchEval() }, [fetchEval])

  const handleExecute = async () => {
    if (!eval_?.playbook_id) return
    setExecuting(true)
    try {
      const base = getApiBaseUrl()
      // Phase 20: CSRF Protection — 先取得 token 再執行
      const csrfRes = await fetch(`${base}/api/v1/csrf/token`, { method: 'GET', credentials: 'include' })
      if (!csrfRes.ok) throw new Error(`CSRF fetch failed: ${csrfRes.status}`)
      const csrfData = await csrfRes.json()
      const csrfHeaders: Record<string, string> = csrfData.token ? { 'X-CSRF-Token': String(csrfData.token) } : {}
      const res = await fetch(`${base}/api/v1/auto-repair/execute`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json', ...csrfHeaders },
        body: JSON.stringify({ incident_id: incidentId, playbook_id: eval_.playbook_id }),
      })
      if (res.ok) setResult(await res.json())
    } finally {
      setExecuting(false)
    }
  }

  return (
    <div className="border border-nothing-gray-200 rounded-lg overflow-hidden">
      <div
        className="flex items-center gap-3 px-4 py-3 bg-nothing-gray-50 cursor-pointer hover:bg-nothing-gray-100 transition-colors"
        onClick={() => setExpanded(v => !v)}
      >
        <span className={cn(
          'px-2 py-0.5 rounded font-body text-[11px] font-bold',
          severity === 'P0' ? 'bg-status-critical/10 text-status-critical' :
          severity === 'P1' ? 'bg-status-warning/10 text-status-warning' :
          'bg-nothing-gray-100 text-nothing-gray-600'
        )}>{severity}</span>
        <span className="font-body text-sm text-nothing-black flex-1 truncate">{incidentId}</span>

        {loading && <RefreshCw className="w-4 h-4 animate-spin text-nothing-gray-400" />}
        {!loading && eval_ && (
          eval_.can_auto_repair
            ? <span className="flex items-center gap-1 text-[11px] font-body text-status-healthy"><CheckCircle2 className="w-3.5 h-3.5" />{t('canAutoRepair')}</span>
            : <span className="flex items-center gap-1 text-[11px] font-body text-nothing-gray-400"><XCircle className="w-3.5 h-3.5" />{t('notEligibleShort')}</span>
        )}
        {expanded ? <ChevronUp className="w-4 h-4 text-nothing-gray-400" /> : <ChevronDown className="w-4 h-4 text-nothing-gray-400" />}
      </div>

      {expanded && eval_ && (
        <div className="px-4 py-4 bg-white space-y-3">
          <div className="grid grid-cols-2 gap-3 text-sm">
            <div>
              <span className="text-[10px] font-body text-nothing-gray-500 uppercase">Playbook</span>
              <p className="font-body text-nothing-black mt-0.5">{eval_.playbook_name ?? '—'}</p>
            </div>
            <div>
              <span className="text-[10px] font-body text-nothing-gray-500 uppercase">{t('riskLevel')}</span>
              <p className="mt-0.5">
                <span className={cn('px-2 py-0.5 rounded border text-[11px] font-body font-bold', RISK_STYLE[eval_.risk_level] ?? RISK_STYLE.MEDIUM)}>
                  {eval_.risk_level}
                </span>
              </p>
            </div>
            {eval_.success_rate != null && (
              <div>
                <span className="text-[10px] font-body text-nothing-gray-500 uppercase">{t('successRate')}</span>
                <p className="font-body text-status-healthy font-bold mt-0.5">{(eval_.success_rate * 100).toFixed(1)}%</p>
              </div>
            )}
            {eval_.total_executions != null && (
              <div>
                <span className="text-[10px] font-body text-nothing-gray-500 uppercase">{t('execCount')}</span>
                <p className="font-body text-nothing-black mt-0.5">{eval_.total_executions}</p>
              </div>
            )}
          </div>

          <div className="p-3 bg-nothing-gray-50 rounded-lg">
            <span className="text-[10px] font-body text-nothing-gray-500 uppercase">{t('decisionReason')}</span>
            <p className="text-sm font-body text-nothing-gray-700 mt-1">{eval_.reason}</p>
          </div>

          {result && (
            <div className={cn(
              'p-3 rounded-lg border',
              result.success ? 'bg-status-healthy/5 border-status-healthy/20' : 'bg-status-critical/5 border-status-critical/20'
            )}>
              <div className="flex items-center gap-2 mb-2">
                {result.success
                  ? <CheckCircle2 className="w-4 h-4 text-status-healthy" />
                  : <XCircle className="w-4 h-4 text-status-critical" />}
                <span className={cn('text-sm font-body font-bold', result.success ? 'text-status-healthy' : 'text-status-critical')}>
                  {result.success ? t('execSuccess', { ms: result.execution_time_ms }) : t('execFailed', { error: result.error ?? '' })}
                </span>
              </div>
              {result.executed_steps.length > 0 && (
                <ul className="space-y-1">
                  {result.executed_steps.map((step, i) => (
                    <li key={i} className="text-xs font-body text-nothing-gray-600 flex items-start gap-1.5">
                      <Zap className="w-3 h-3 mt-0.5 text-claw-blue flex-shrink-0" />
                      {step}
                    </li>
                  ))}
                </ul>
              )}
            </div>
          )}

          {eval_.can_auto_repair && !result && (
            <button
              onClick={handleExecute}
              disabled={executing}
              className={cn(
                'flex items-center gap-2 px-4 py-2 rounded-lg',
                'bg-claw-blue text-white font-body text-sm font-semibold',
                'hover:bg-claw-blue/90 transition-colors',
                'disabled:opacity-50 disabled:cursor-not-allowed'
              )}
            >
              {executing
                ? <><RefreshCw className="w-4 h-4 animate-spin" />{t('executing')}</>
                : <><Play className="w-4 h-4" />{t('execute')}</>}
            </button>
          )}
        </div>
      )}
    </div>
  )
}

// =============================================================================
// AutoRepairPanel
// =============================================================================

export function AutoRepairPanel() {
  const t = useTranslations('autoRepair')
  const tNav = useTranslations('nav')
  const tCommon = useTranslations('common')

  const [stats, setStats] = useState<AutoRepairStats | null>(null)
  const [statsLoading, setStatsLoading] = useState(true)
  const [statsError, setStatsError] = useState<string | null>(null)
  const [disposition, setDisposition] = useState<{ total: number; auto_repair: number; human_approved: number; manual_resolved: number; cold_start_trust: number; auto_rate: number } | null>(null)
  const abortRef = useRef<AbortController | null>(null)

  const { incidents, isLoading: incidentsLoading } = useIncidents({
    pollInterval: 30000,
    enablePolling: true,
  })

  const eligibleIncidents = (incidents ?? []).filter(i =>
    i.severity === 'P1' || i.severity === 'P2'
  )

  const fetchStats = useCallback(async () => {
    const base = getApiBaseUrl()
    if (!base) return
    abortRef.current?.abort()
    const ctrl = new AbortController()
    abortRef.current = ctrl
    setStatsLoading(true)
    setStatsError(null)
    try {
      const [res, dispRes] = await Promise.all([
        fetch(`${base}/api/v1/auto-repair/stats`, { signal: ctrl.signal }),
        fetch(`${base}/api/v1/stats/disposition`, { signal: ctrl.signal }).catch(() => null),
      ])
      if (!res.ok) throw new Error(`HTTP ${res.status}`)
      setStats(await res.json())
      if (dispRes?.ok) {
        const d = await dispRes.json()
        setDisposition(d.summary ?? null)
      }
    } catch (e) {
      if (e instanceof Error && e.name === 'AbortError') return
      setStatsError(e instanceof Error ? e.message : 'Unknown error')
    } finally {
      setStatsLoading(false)
    }
  }, [])

  useEffect(() => {
    fetchStats()
    return () => { abortRef.current?.abort() }
  }, [fetchStats])

  return (
    <>
      {/* Header */}
      <div className="flex items-center justify-between mb-6">
        <div>
          <h2 className="font-heading text-2xl font-bold text-nothing-black flex items-center gap-2">
            <Wrench className="w-6 h-6" />
            {tNav('autoRepair')}
          </h2>
          <p className="mt-1 text-sm text-nothing-gray-500 font-body">
            {t('subtitle')}
          </p>
        </div>
        <button
          onClick={fetchStats}
          disabled={statsLoading}
          className={cn(
            'flex items-center gap-1.5 px-3 py-1.5 rounded-lg',
            'text-xs font-body bg-nothing-gray-100 text-nothing-gray-600',
            'hover:bg-nothing-gray-200 transition-colors',
            'disabled:opacity-50 disabled:cursor-not-allowed'
          )}
        >
          <RefreshCw className={cn('w-3.5 h-3.5', statsLoading && 'animate-spin')} />
          {tCommon('refresh')}
        </button>
      </div>

      {/* Error */}
      {statsError && (
        <div className="mb-4 p-4 rounded-lg bg-status-critical/10 border border-status-critical/20 flex items-center gap-2">
          <AlertCircle className="w-4 h-4 text-status-critical" />
          <span className="text-sm font-body text-status-critical">{statsError}</span>
        </div>
      )}

      {/* Stats */}
      {stats && (
        <div className="grid grid-cols-2 md:grid-cols-4 gap-3 mb-6">
          <StatCard label={t('approvedPlaybooks')} value={stats.approved_playbooks} />
          <StatCard label={t('highQualityPlaybooks')} value={stats.high_quality_playbooks} sub={t('highQualitySub')} highlight />
          <StatCard label={t('totalExecutions')} value={stats.total_executions} />
          <StatCard label={t('overallSuccessRate')} value={`${(stats.overall_success_rate * 100).toFixed(1)}%`} sub={stats.auto_repair_eligible ? t('eligible') : t('notEligible')} />
        </div>
      )}

      {/* Disposition summary */}
      {disposition && disposition.total > 0 && (
        <div className="grid grid-cols-4 gap-2 mb-6">
          <div className="rounded-lg border border-green-500/25 bg-green-500/5 p-3 text-center">
            <p className="text-[10px] font-bold text-green-500 uppercase tracking-wider">{t('dispositionAuto')}</p>
            <p className="text-xl font-bold text-green-500 tabular-nums mt-1">{disposition.auto_repair}</p>
          </div>
          <div className="rounded-lg border border-orange-500/25 bg-orange-500/5 p-3 text-center">
            <p className="text-[10px] font-bold text-orange-500 uppercase tracking-wider">{t('dispositionHuman')}</p>
            <p className="text-xl font-bold text-orange-500 tabular-nums mt-1">{disposition.human_approved}</p>
          </div>
          <div className="rounded-lg border border-purple-500/25 bg-purple-500/5 p-3 text-center">
            <p className="text-[10px] font-bold text-purple-500 uppercase tracking-wider">{t('dispositionManual')}</p>
            <p className="text-xl font-bold text-purple-500 tabular-nums mt-1">{disposition.manual_resolved}</p>
          </div>
          <div className="rounded-lg border border-blue-500/25 bg-blue-500/5 p-3 text-center">
            <p className="text-[10px] font-bold text-blue-500 uppercase tracking-wider">{t('dispositionCold')}</p>
            <p className="text-xl font-bold text-blue-500 tabular-nums mt-1">{disposition.cold_start_trust}</p>
          </div>
        </div>
      )}

      {/* Eligible indicator */}
      {stats && (
        <div className={cn(
          'flex items-center gap-3 p-4 rounded-lg border mb-6',
          stats.auto_repair_eligible
            ? 'bg-status-healthy/5 border-status-healthy/20'
            : 'bg-nothing-gray-50 border-nothing-gray-200'
        )}>
          {stats.auto_repair_eligible
            ? <CheckCircle2 className="w-5 h-5 text-status-healthy" />
            : <ShieldAlert className="w-5 h-5 text-nothing-gray-400" />}
          <div>
            <p className={cn('text-sm font-body font-semibold', stats.auto_repair_eligible ? 'text-status-healthy' : 'text-nothing-gray-600')}>
              {stats.auto_repair_eligible ? t('ready') : t('notReady')}
            </p>
            <p className="text-xs font-body text-nothing-gray-400">
              {stats.auto_repair_eligible
                ? t('readyDesc', { count: stats.high_quality_playbooks })
                : t('notReadyDesc')}
            </p>
          </div>
        </div>
      )}

      {/* Incident evaluation list */}
      <div>
        <h3 className="text-[11px] font-body text-nothing-gray-500 uppercase tracking-widest mb-3">
          {t('incidentEval')}
        </h3>

        {incidentsLoading && (
          <div className="flex items-center justify-center py-10">
            <RefreshCw className="w-5 h-5 animate-spin text-nothing-gray-400" />
          </div>
        )}

        {!incidentsLoading && eligibleIncidents.length === 0 && (
          <div className="text-center py-10 border border-dashed border-nothing-gray-200 rounded-lg">
            <CheckCircle2 className="w-8 h-8 text-status-healthy mx-auto mb-2" />
            <p className="font-body text-sm text-nothing-gray-500">{t('noEligible')}</p>
          </div>
        )}

        <div className="space-y-2">
          {eligibleIncidents.map(incident => (
            <IncidentEvalRow
              key={incident.incident_id}
              incidentId={incident.incident_id}
              severity={incident.severity}
            />
          ))}
        </div>
      </div>
    </>
  )
}
