'use client'

/**
 * AWOOOI AI Center 主頁
 * ====================================
 * 2欄佈局（Sidebar 由 AppLayout 提供）: Feed + RightPanel
 *
 * 統帥鐵律: 使用真實數據 Hook，禁止假數據！
 *
 * @updated 2026-04-02 Claude Code — Metrics Strip 7指標視覺強化
 * @updated 2026-04-03 Claude Code — 監控工具區塊 (Grafana/Prometheus/SigNoz/Gitea)
 *   串接: incidents(count/P0/MTTR/autoRemediation) + dashboard(serviceHealth/pendingApprovals/podHealth)
 * @updated 2026-04-03 Claude Code — 完整對齊 figma-v2 設計
 *   figma-v2 重點: 7指標(含今日事件) + 監控工具左彩色條 + 可點擊連結 + meta行
 */

import React from 'react'
import { useTranslations } from 'next-intl'
import { useState, useEffect } from 'react'
import { useGlobalPulseMetrics } from '@/hooks/useGlobalPulseMetrics'
import { useIncidents } from '@/hooks/useIncidents'
import { useHosts, useDashboardStore } from '@/stores/dashboard.store'
import { IncidentCard } from '@/components/incident'
import { OpenClawPanel } from '@/components/ai/openclaw-panel'
import { HostGrid, type HostInfo, type HostService } from '@/components/infra/host-grid'
import { AppLayout } from '@/components/layout'
import { PageTabs, type TabConfig } from '@/components/layout/page-tabs'
import { PulseSkeleton, CardSkeleton } from '@/components/shared/pulse-skeleton'
import { ServiceTopology } from '@/components/topology'
import { BarChart3, Flame, Telescope, FlaskConical, Activity, GitBranch } from 'lucide-react'
import { DispositionMini } from '@/components/shared/disposition-mini'
import { RecentActivity } from '@/components/shared/recent-activity'
import { PendingApprovalsCard } from '@/components/shared/pending-approvals-card'
import { AIModelStatus } from '@/components/shared/ai-model-status'
import { FlywheelKPICard } from '@/components/dashboard/flywheel-kpi-card'

const API_BASE = process.env.NEXT_PUBLIC_API_URL ?? ''

// =============================================================================
// Tab 2: 告警 & 授權 (串接真實 API)
// =============================================================================

function AlertsAndApprovalsTab() {
  const t = useTranslations('dashboard')
  const tc = useTranslations('common')
  const [alerts, setAlerts] = useState<any[]>([])
  const [approvals, setApprovals] = useState<any[]>([])
  const [loading, setLoading] = useState(true)

  useEffect(() => {
    Promise.all([
      fetch(`${API_BASE}/api/v1/incidents`).then(r => r.ok ? r.json() : { incidents: [] }).catch(() => ({ incidents: [] })),
      fetch(`${API_BASE}/api/v1/approvals/pending`).then(r => r.ok ? r.json() : []).catch(() => []),
    ]).then(([incData, apprData]) => {
      setAlerts(incData.incidents ?? incData ?? [])
      setApprovals(Array.isArray(apprData) ? apprData : apprData.approvals ?? [])
    }).finally(() => setLoading(false))
  }, [])

  if (loading) return <CardSkeleton lines={4} />

  return (
    <div style={{ display: 'flex', gap: 20, padding: '16px 20px', flex: 1, overflow: 'hidden' }}>
      {/* 左: 告警列表 */}
      <div style={{ flex: 1, overflowY: 'auto' }}>
        <div style={{ fontSize: 14, fontWeight: 700, marginBottom: 12, color: '#141413' }}>{t('alertEvents')} ({alerts.length})</div>
        {alerts.length === 0 ? (
          <div style={{ padding: 24, textAlign: 'center', color: '#87867f' }}>{t('noActiveAlerts')}</div>
        ) : alerts.map((a: any, i: number) => (
          <div key={a.incident_id || i} style={{ background: '#fff', border: '0.5px solid #e0ddd4', borderRadius: 10, padding: '10px 14px', marginBottom: 8 }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
              <span style={{ fontSize: 10, fontWeight: 700, padding: '2px 6px', borderRadius: 3, background: 'rgba(204,34,0,0.1)', color: '#cc2200' }}>{a.severity || 'P2'}</span>
              <span style={{ fontSize: 13, fontWeight: 600 }}>{a.title || a.incident_id}</span>
            </div>
            <div style={{ fontSize: 11, color: '#555550', marginTop: 4 }}>{a.affected_services?.join(', ') || '--'} · {a.status || '--'}</div>
          </div>
        ))}
      </div>
      {/* 右: 授權待批准 */}
      <div style={{ width: 400, flexShrink: 0, overflowY: 'auto' }}>
        <div style={{ fontSize: 14, fontWeight: 700, marginBottom: 12, color: '#141413' }}>{t('pendingApprovalsTitle')} ({approvals.length})</div>
        {approvals.length === 0 ? (
          <div style={{ padding: 24, textAlign: 'center', color: '#87867f' }}>{t('noPendingApprovals')}</div>
        ) : approvals.map((ap: any, i: number) => (
          <div key={ap.id || i} style={{ background: '#faf9f3', border: '0.5px solid #e0ddd4', borderRadius: 8, padding: '10px 12px', marginBottom: 8 }}>
            <div style={{ fontSize: 12, fontWeight: 600, color: '#cc2200' }}>{ap.action || ap.title || '--'}</div>
            <div style={{ fontSize: 10, color: '#555550', marginTop: 2, fontFamily: "'JetBrains Mono', monospace" }}>{ap.resource || '--'}</div>
            <div style={{ display: 'flex', gap: 6, marginTop: 6 }}>
              <button
                onClick={() => {
                  fetch(`${API_BASE}/api/v1/approvals/${ap.id}/sign`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ signer: 'web-ui' }) })
                    .then(() => setApprovals(prev => prev.filter(x => x.id !== ap.id)))
                    .catch(() => {})
                }}
                style={{ flex: 1, padding: '5px 0', border: 'none', borderRadius: 5, fontSize: 11, fontWeight: 600, cursor: 'pointer', background: '#22C55E', color: '#fff' }}
              >{t('approve')}</button>
              <button
                onClick={() => {
                  fetch(`${API_BASE}/api/v1/approvals/${ap.id}/reject`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ reason: 'rejected-from-web' }) })
                    .then(() => setApprovals(prev => prev.filter(x => x.id !== ap.id)))
                    .catch(() => {})
                }}
                style={{ flex: 1, padding: '5px 0', border: '0.5px solid #e0ddd4', borderRadius: 5, fontSize: 11, cursor: 'pointer', background: '#fff', color: '#87867f' }}
              >{t('reject')}</button>
            </div>
          </div>
        ))}
      </div>
    </div>
  )
}

// =============================================================================
// Tab 3: 活動串流 (串接真實 SSE)
// =============================================================================

function ActivityStreamTab() {
  const t = useTranslations('dashboard')
  const [events, setEvents] = useState<any[]>([])
  const [connected, setConnected] = useState(false)
  const [selectedIdx, setSelectedIdx] = useState<number | null>(null)

  useEffect(() => {
    const es = new EventSource(`${API_BASE}/api/v1/dashboard/stream`)
    es.onopen = () => setConnected(true)
    es.onmessage = (e) => {
      try {
        const data = JSON.parse(e.data)
        setEvents(prev => [{ ...data, _time: new Date().toLocaleTimeString('zh-TW', { hour: '2-digit', minute: '2-digit', second: '2-digit' }) }, ...prev].slice(0, 50))
      } catch {}
    }
    es.onerror = () => setConnected(false)
    return () => es.close()
  }, [])

  const selected = selectedIdx !== null ? events[selectedIdx] : null
  const cot = selected?.data?.incident?.decision?.proposal_data ?? selected?.data?.proposal_data ?? null

  return (
    <div style={{ padding: '16px 20px', flex: 1, overflowY: 'auto' }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 12 }}>
        <div style={{ width: 6, height: 6, borderRadius: '50%', background: connected ? '#22C55E' : '#cc2200' }} />
        <span style={{ fontSize: 14, fontWeight: 700 }}>{t('activityStream')}</span>
        <span style={{ fontSize: 11, color: '#87867f' }}>{connected ? t('sseConnected') : t('sseDisconnected')} · {events.length}</span>
      </div>
      {events.length === 0 ? (
        <div style={{ padding: 32, textAlign: 'center', color: '#87867f' }}>{t('waitingEvents')}</div>
      ) : (
        <div style={{ display: 'grid', gridTemplateColumns: cot ? '1fr 1fr' : '1fr', gap: 12 }}>
          {/* Event list */}
          <div>
            {events.map((ev, i) => (
              <div
                key={i}
                onClick={() => setSelectedIdx(i === selectedIdx ? null : i)}
                style={{
                  display: 'flex', gap: 8, padding: '7px 8px', borderBottom: '0.5px solid #f0ede5',
                  fontSize: 12, cursor: 'pointer', borderRadius: 5,
                  background: i === selectedIdx ? 'rgba(74,144,217,0.06)' : 'transparent',
                }}
              >
                <span style={{ fontSize: 10, color: '#87867f', fontFamily: "'JetBrains Mono', monospace", width: 60, flexShrink: 0 }}>{ev._time}</span>
                <span style={{ width: 5, height: 5, borderRadius: '50%', background: ev.type === 'HOST_UPDATE' ? '#22C55E' : '#4A90D9', marginTop: 5, flexShrink: 0 }} />
                <span style={{ flex: 1, lineHeight: 1.4 }}>
                  <b>{ev.type || 'EVENT'}</b>
                  {ev.data?.overall_status && ` · ${t('statusLabel')}: ${ev.data.overall_status}`}
                  {ev.data?.hosts && ` · ${ev.data.hosts.length} ${t('hostsLabel')}`}
                  {(ev.data?.incident?.decision?.proposal_data || ev.data?.proposal_data) && (
                    <span style={{ marginLeft: 4, fontSize: 9, background: 'rgba(74,144,217,0.12)', color: '#4A90D9', borderRadius: 3, padding: '1px 5px', fontWeight: 600 }}>COT</span>
                  )}
                </span>
              </div>
            ))}
            {selectedIdx === null && events.length > 0 && (
              <div style={{ marginTop: 8, fontSize: 10, color: '#87867f', textAlign: 'center' }}>{t('cotClickHint')}</div>
            )}
          </div>

          {/* Chain of Thought panel */}
          {cot && (
            <div style={{ background: '#fff', border: '0.5px solid #e0ddd4', borderRadius: 10, padding: '14px 16px', fontSize: 12 }}>
              <div style={{ fontSize: 13, fontWeight: 700, color: '#141413', marginBottom: 10 }}>{t('cotTitle')}</div>
              {/* Provider + confidence row */}
              <div style={{ display: 'flex', gap: 8, marginBottom: 10, flexWrap: 'wrap' }}>
                {cot.provider && (
                  <span style={{ fontSize: 10, background: 'rgba(74,144,217,0.1)', color: '#4A90D9', borderRadius: 4, padding: '2px 8px', fontWeight: 600 }}>
                    {t('cotProvider')}: {cot.provider}
                  </span>
                )}
                {cot.confidence !== undefined && (
                  <span style={{ fontSize: 10, background: cot.confidence >= 0.8 ? 'rgba(34,197,94,0.1)' : 'rgba(245,158,11,0.1)', color: cot.confidence >= 0.8 ? '#22C55E' : '#F59E0B', borderRadius: 4, padding: '2px 8px', fontWeight: 600 }}>
                    {t('cotConfidence')}: {Math.round(cot.confidence * 100)}%
                  </span>
                )}
                {cot.nemotron_latency_ms !== undefined && (
                  <span style={{ fontSize: 10, background: 'rgba(168,85,247,0.08)', color: '#A855F7', borderRadius: 4, padding: '2px 8px', fontWeight: 600 }}>
                    {t('cotLatency')}: {cot.nemotron_latency_ms}ms
                  </span>
                )}
              </div>
              {/* Tools used */}
              {Array.isArray(cot.nemotron_tools) && cot.nemotron_tools.length > 0 && (
                <div style={{ marginBottom: 10 }}>
                  <div style={{ fontSize: 10, fontWeight: 700, textTransform: 'uppercase', color: '#87867f', marginBottom: 4 }}>{t('cotTools')}</div>
                  <div style={{ display: 'flex', flexWrap: 'wrap', gap: 4 }}>
                    {cot.nemotron_tools.map((tool: string, i: number) => (
                      <span key={i} style={{ fontSize: 10, background: '#f5f4ed', border: '0.5px solid #e0ddd4', borderRadius: 3, padding: '2px 6px', fontFamily: "'JetBrains Mono', monospace" }}>{tool}</span>
                    ))}
                  </div>
                </div>
              )}
              {/* Reasoning */}
              {cot.reasoning && (
                <div>
                  <div style={{ fontSize: 10, fontWeight: 700, textTransform: 'uppercase', color: '#87867f', marginBottom: 4 }}>{t('cotReasoning')}</div>
                  <div style={{ fontSize: 11, color: '#555550', lineHeight: 1.5, background: '#faf9f3', border: '0.5px solid #e0ddd4', borderRadius: 6, padding: '8px 10px', maxHeight: 180, overflowY: 'auto', fontFamily: "'JetBrains Mono', monospace", whiteSpace: 'pre-wrap' }}>
                    {cot.reasoning}
                  </div>
                </div>
              )}
            </div>
          )}
        </div>
      )}
    </div>
  )
}

// =============================================================================
// Tab 4: 處置統計 (串接真實 /stats/disposition)
// =============================================================================

function DispositionTab() {
  const t = useTranslations('dashboard')
  const [data, setData] = useState<any>(null)
  const [loading, setLoading] = useState(true)

  useEffect(() => {
    fetch(`${API_BASE}/api/v1/stats/disposition`)
      .then(r => r.json())
      .then(d => setData(d))
      .catch(() => {})
      .finally(() => setLoading(false))
  }, [])

  if (loading) return <CardSkeleton lines={4} />

  const s = data?.summary
  if (!s || s.total === 0) return (
    <div style={{ padding: 48, textAlign: 'center', color: '#87867f' }}>
      <div style={{ fontSize: 32, marginBottom: 8, opacity: 0.3 }}>--</div>
      <div>{t('noDispositionData')}</div>
    </div>
  )

  const autoRate = Math.round(s.auto_rate * 100)

  return (
    <div style={{ padding: '16px 20px', flex: 1, overflowY: 'auto' }}>
      {/* KPI 3 卡 */}
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 12, marginBottom: 16 }}>
        <div style={{ background: '#fff', border: '0.5px solid #e0ddd4', borderRadius: 10, padding: '14px 16px' }}>
          <div style={{ fontSize: 10, textTransform: 'uppercase', letterSpacing: 0.5, color: '#87867f', fontWeight: 500 }}>{t('totalDispositions')}</div>
          <div style={{ fontSize: 28, fontWeight: 700, color: '#4A90D9', marginTop: 4 }}>{s.total}</div>
        </div>
        <div style={{ background: '#fff', border: '0.5px solid #e0ddd4', borderRadius: 10, padding: '14px 16px' }}>
          <div style={{ fontSize: 10, textTransform: 'uppercase', letterSpacing: 0.5, color: '#87867f', fontWeight: 500 }}>{t('autoRate')}</div>
          <div style={{ fontSize: 28, fontWeight: 700, color: '#22C55E', marginTop: 4 }}>{autoRate}%</div>
        </div>
        <div style={{ background: '#fff', border: '0.5px solid #e0ddd4', borderRadius: 10, padding: '14px 16px' }}>
          <div style={{ fontSize: 10, textTransform: 'uppercase', letterSpacing: 0.5, color: '#87867f', fontWeight: 500 }}>{t('humanRate')}</div>
          <div style={{ fontSize: 28, fontWeight: 700, color: '#F59E0B', marginTop: 4 }}>{Math.round(s.human_rate * 100)}%</div>
        </div>
      </div>
      {/* 四大計數 */}
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: 10, marginBottom: 16 }}>
        {[
          { label: t('autoRepairLabel'), count: s.auto_repair, color: '#22C55E', bg: 'rgba(34,197,94,0.06)', border: 'rgba(34,197,94,0.25)' },
          { label: t('humanApprovedLabel'), count: s.human_approved, color: '#F59E0B', bg: 'rgba(249,115,22,0.06)', border: 'rgba(249,115,22,0.25)' },
          { label: t('manualResolvedLabel'), count: s.manual_resolved, color: '#A855F7', bg: 'rgba(168,85,247,0.06)', border: 'rgba(168,85,247,0.25)' },
          { label: t('coldStartLabel'), count: s.cold_start_trust, color: '#4A90D9', bg: 'rgba(59,130,246,0.06)', border: 'rgba(59,130,246,0.25)' },
        ].map(item => (
          <div key={item.label} style={{ background: item.bg, border: `0.5px solid ${item.border}`, borderRadius: 10, padding: 14, textAlign: 'center' }}>
            <div style={{ fontSize: 10, fontWeight: 700, textTransform: 'uppercase', letterSpacing: 0.5, color: item.color, marginBottom: 6 }}>{item.label}</div>
            <div style={{ fontSize: 28, fontWeight: 700, color: item.color }}>{item.count}</div>
          </div>
        ))}
      </div>
      {/* 堆疊分佈條 */}
      <div style={{ background: '#fff', border: '0.5px solid #e0ddd4', borderRadius: 10, padding: '14px 16px', marginBottom: 16 }}>
        <div style={{ fontSize: 10, fontWeight: 700, textTransform: 'uppercase', letterSpacing: 0.5, color: '#87867f', marginBottom: 8 }}>{t('dispositionBreakdown')}</div>
        <div style={{ display: 'flex', height: 12, borderRadius: 6, overflow: 'hidden' }}>
          {s.total > 0 && <>
            <div style={{ width: `${(s.auto_repair/s.total)*100}%`, background: '#22C55E' }} />
            <div style={{ width: `${(s.cold_start_trust/s.total)*100}%`, background: '#4A90D9' }} />
            <div style={{ width: `${(s.human_approved/s.total)*100}%`, background: '#F59E0B' }} />
            <div style={{ width: `${(s.manual_resolved/s.total)*100}%`, background: '#A855F7' }} />
          </>}
        </div>
      </div>

      {/* By Anomaly Top 5 */}
      {Array.isArray(data?.by_anomaly) && data.by_anomaly.length > 0 && (() => {
        const top5 = [...data.by_anomaly]
          .sort((a: any, b: any) => (b.disposition?.total ?? 0) - (a.disposition?.total ?? 0))
          .slice(0, 5)
        const maxCount = top5[0]?.disposition?.total || 1
        return (
          <div style={{ background: '#fff', border: '0.5px solid #e0ddd4', borderRadius: 10, padding: '14px 16px', marginBottom: 16 }}>
            <div style={{ fontSize: 10, fontWeight: 700, textTransform: 'uppercase', letterSpacing: 0.5, color: '#87867f', marginBottom: 10 }}>{t('byAnomalyTitle')}</div>
            {top5.map((item: any, i: number) => {
              const disp = item.disposition ?? {}
              const count = disp.total ?? 0
              const autoRate = Math.round((disp.auto_rate ?? 0) * 100)
              const label = item.alert_name || item.anomaly_key || '--'
              return (
                <div key={i} style={{ marginBottom: 8 }}>
                  <div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 11, marginBottom: 3 }}>
                    <span style={{ color: '#141413', fontWeight: 500, maxWidth: '70%', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{label}</span>
                    <span style={{ color: '#87867f', fontFamily: "'JetBrains Mono', monospace", fontSize: 10 }}>
                      {count} · {t('byAnomalyAutoRate', { pct: autoRate })}
                    </span>
                  </div>
                  <div style={{ height: 6, background: '#f0ede5', borderRadius: 3, overflow: 'hidden' }}>
                    <div style={{ height: '100%', width: `${(count / maxCount) * 100}%`, background: autoRate >= 80 ? '#22C55E' : autoRate >= 50 ? '#F59E0B' : '#cc2200', borderRadius: 3, transition: 'width 0.4s ease' }} />
                  </div>
                </div>
              )
            })}
          </div>
        )
      })()}

      {/* MTTR */}
      {(() => {
        const mttr = data?.mttr
        if (!mttr) return (
          <div style={{ background: '#fff', border: '0.5px solid #e0ddd4', borderRadius: 10, padding: '14px 16px' }}>
            <div style={{ fontSize: 10, fontWeight: 700, textTransform: 'uppercase', letterSpacing: 0.5, color: '#87867f', marginBottom: 6 }}>{t('mttrTitle')}</div>
            <div style={{ fontSize: 11, color: '#87867f' }}>{t('mttrNoData')}</div>
          </div>
        )
        const mttrVal = typeof mttr === 'number' ? mttr : mttr.avg_seconds ?? mttr.value ?? null
        const mttrMin = mttrVal !== null ? (mttrVal / 60).toFixed(1) : '--'
        return (
          <div style={{ background: '#fff', border: '0.5px solid #e0ddd4', borderRadius: 10, padding: '14px 16px' }}>
            <div style={{ fontSize: 10, fontWeight: 700, textTransform: 'uppercase', letterSpacing: 0.5, color: '#87867f', marginBottom: 6 }}>{t('mttrTitle')}</div>
            <div style={{ display: 'flex', alignItems: 'baseline', gap: 4 }}>
              <span style={{ fontSize: 32, fontWeight: 700, color: '#4A90D9' }}>{mttrMin}</span>
              <span style={{ fontSize: 11, color: '#87867f' }}>{t('mttrUnit')}</span>
            </div>
          </div>
        )
      })()}
    </div>
  )
}

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

interface MetricItem {
  label: string
  value: string | number
  sub?: string
  badge?: { text: string; color: string; bg: string }
  valueColor?: string
  trend?: { text: string; color: string }  // figma: value-row 右側趨勢箭頭
  extra?: React.ReactNode                  // figma: metric-extra 第三行
}

// =============================================================================
// Mini Sparkline (SVG inline)
// =============================================================================

function MiniSparkline({ values, color }: { values: number[]; color: string }) {
  if (!values || values.length < 2) return null
  const min = Math.min(...values)
  const max = Math.max(...values)
  const range = max - min || 1
  const w = 48, h = 16
  const pts = values.map((v, i) => {
    const x = (i / (values.length - 1)) * w
    const y = h - ((v - min) / range) * h
    return `${x},${y}`
  }).join(' ')
  return (
    <svg width={w} height={h} style={{ display: 'block', flexShrink: 0 }}>
      <polyline points={pts} fill="none" stroke={color} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
    </svg>
  )
}

// =============================================================================
// Monitoring Tools Component — figma-v2 style
// Left 3px accent bar + clickable links + meta row
// =============================================================================

interface MonitoringTool {
  name: string
  status: string
  version: string | null
  stats: string | null
  description: string
  firing_count?: number
  checked_at: string
  url?: string
}

// figma-v2 左側彩色條顏色
const TOOL_ACCENT_COLOR: Record<string, string> = {
  Grafana:    '#F59E0B',
  Prometheus: '#E85530',
  Sentry:     '#7B52BF',
  Langfuse:   '#0077CC',
  SigNoz:     '#4A90D9',
  Gitea:      '#22C55E',
}

// 圖示 Lucide icon (feedback_no_emoji_use_icons.md)
const TOOL_ICON: Record<string, React.ReactNode> = {
  Grafana:    <BarChart3 size={16} />,
  Prometheus: <Flame size={16} />,
  Sentry:     <Telescope size={16} />,
  Langfuse:   <FlaskConical size={16} />,
  SigNoz:     <Activity size={16} />,
  Gitea:      <GitBranch size={16} />,
}

function MonitoringTools() {
  const tDash = useTranslations('dashboard')
  const tCommon = useTranslations('common')
  const [tools, setTools] = useState<MonitoringTool[]>([])
  const [loading, setLoading] = useState(true)

  useEffect(() => {
    const load = () => {
      fetch(`${API_BASE}/api/v1/monitoring/status`)
        .then(r => r.json())
        .then(d => { setTools(d.tools ?? []); setLoading(false) })
        .catch(() => setLoading(false))
    }
    load()
    const t = setInterval(load, 60000)
    return () => clearInterval(t)
  }, [])

  if (loading) return (
    <div style={{ padding: '12px 14px', fontSize: 12, color: '#87867f' }}>{tCommon('loading')}</div>
  )
  if (tools.length === 0) return (
    <div style={{ padding: '12px 14px', fontSize: 12, color: '#cc2200' }}>{tDash('connectionError')}</div>
  )

  // S10: 監控工具元資訊 (設計稿 3×2 精簡版)
  const TOOL_META: Record<string, string> = {
    SigNoz: 'Traces · Logs', Grafana: '3 Dashboards', Prometheus: '-- targets',
    Langfuse: 'LLMOps', Sentry: '2 Projects', Gitea: 'CI/CD',
  }

  return (
    <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 6, padding: '10px 14px' }}>
      {tools.map((tool) => {
        const accentColor = TOOL_ACCENT_COLOR[tool.name] ?? '#b0ad9f'
        const link = tool.url ?? '#'
        const meta = TOOL_META[tool.name] ?? tool.description ?? ''

        return (
          <a key={tool.name} href={link} target="_blank" rel="noopener noreferrer"
            style={{
              display: 'flex', overflow: 'hidden',
              border: '0.5px solid #e0ddd4', borderRadius: 6,
              background: '#faf9f3', cursor: 'pointer',
              textDecoration: 'none', color: 'inherit',
              transition: 'border-color 0.1s',
            }}
          >
            <div style={{ width: 3, flexShrink: 0, background: accentColor }} />
            <div style={{ padding: '5px 7px', flex: 1, minWidth: 0 }}>
              <div style={{ fontSize: 11, fontWeight: 600, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', color: '#141413' }}>{tool.name}</div>
              <div style={{ fontSize: 10, color: '#87867f', marginTop: 2 }}>{meta}</div>
            </div>
          </a>
        )
      })}
    </div>
  )
}

// =============================================================================
// Main Page
// =============================================================================

// =============================================================================
// Static Host Service Catalog
// 定義每台主機完整服務清單（API 只回傳部分，此處補全靜態資訊）
// =============================================================================

const HOST_CATALOG: Record<string, { services: HostService[]; isK3s?: boolean; role?: string }> = {
  '192.168.0.110': {
    services: [
      { name: 'Harbor',     healthy: false, port: 5000,  description: 'Container Registry' },
      { name: 'Gitea',      healthy: false, port: 3001,  description: 'Git · CI/CD' },
      { name: 'Sentry',     healthy: false, port: 9000,  description: 'Error Tracking' },
      { name: 'Langfuse',   healthy: false, port: 3100,  description: 'LLM Tracing' },
      { name: 'Grafana',    healthy: false, port: 3002,  description: '監控面板' },
      { name: 'Prometheus', healthy: false, port: 9090,  description: '告警規則' },
    ],
  },
  '192.168.0.112': {
    services: [
      { name: 'Scanner API', healthy: false, port: 8080, description: '漏洞掃描' },
    ],
  },
  '192.168.0.120': {
    isK3s: true,
    role: 'Control Plane #1',
    services: [
      { name: 'K3s API',      healthy: false, port: 6443, description: 'kubectl',         isK3s: true },
      { name: 'Traefik',      healthy: false,              description: 'Ingress',          isK3s: true },
      { name: 'awoooi-prod',  healthy: false,              description: 'Namespace',        isK3s: true },
      { name: 'keepalived',   healthy: false,              description: 'VIP MASTER',       isK3s: true },
    ],
  },
  '192.168.0.121': {
    isK3s: true,
    role: 'Control Plane #2 (HA)',
    services: [
      { name: 'K3s API',      healthy: false, port: 6443,  description: 'kubectl',        isK3s: true },
      { name: 'API',          healthy: false, port: 32334, description: 'NodePort',       isK3s: true },
      { name: 'Web',          healthy: false, port: 32335, description: 'NodePort',       isK3s: true },
      { name: 'keepalived',   healthy: false,               description: 'VIP BACKUP',    isK3s: true },
    ],
  },
  '192.168.0.188': {
    services: [
      { name: 'Nginx',      healthy: false, port: 443,   description: 'Reverse Proxy' },
      { name: 'PostgreSQL', healthy: false, port: 5432,  description: 'K3s Datastore' },
      { name: 'Redis',      healthy: false, port: 6380,  description: 'Cache' },
      { name: 'Ollama',     healthy: false, port: 11434, description: 'LLM' },
      { name: 'OpenClaw',   healthy: false, port: 8088,  description: 'AI Agent' },
      { name: 'SigNoz',     healthy: false, port: 3301,  description: 'APM · OTEL' },
    ],
  },
}

/** 合併 API 動態健康狀態 + 靜態服務清單 */
function buildHostInfo(
  ip: string,
  hostname: string,
  cpuPct: number | null,
  ramPct: number | null,
  dynamicServices: { name: string; status: string }[],
): HostInfo {
  const catalog = HOST_CATALOG[ip]
  const services: HostService[] = catalog
    ? catalog.services.map(s => {
        const dyn = dynamicServices.find(d => d.name.toLowerCase() === s.name.toLowerCase())
        return {
          ...s,
          healthy: dyn ? (dyn.status === 'up' || dyn.status === 'healthy') : false,
        }
      })
    : dynamicServices.map(s => ({
        name: s.name,
        healthy: s.status === 'up' || s.status === 'healthy',
      }))
  return {
    hostname,
    ip,
    cpuPct,
    ramPct,
    services,
    isK3s: catalog?.isK3s,
    role: catalog?.role,
  }
}

export default function Home({ params }: { params: { locale: string } }) {
  const tDashboard = useTranslations('dashboard')
  const tCommon = useTranslations('common')
  const tTopo = useTranslations('topology')
  const locale = params.locale
  const hosts = useHosts()

  // dashboard store — pending approvals + overall pod health
  const pendingApprovals = useDashboardStore(s => s.pendingApprovals)
  const dashboardHosts = useDashboardStore(s => s.hosts)

  // Gold metrics (RPS / Error Rate / P99 / AI Success + sparklines)
  const { metrics: pulseMetrics } = useGlobalPulseMetrics({
    pollInterval: 30000,
    enablePolling: true,
  })

  // Real incidents
  const {
    incidents,
    isLoading: isIncidentsLoading,
    error: incidentsError,
  } = useIncidents({
    pollInterval: 15000,
    enablePolling: true,
  })

  // ── Metrics 計算 ────────────────────────────────────────────────────────────

  // 服務健康: dashboard hosts healthy services count
  const { healthyServices, totalServices } = (() => {
    let healthy = 0, total = 0
    for (const h of dashboardHosts) {
      for (const s of h.services) {
        total++
        if (s.status === 'up' || s.status === 'healthy') healthy++
      }
    }
    return { healthyServices: healthy, totalServices: total }
  })()

  // P0 count
  const p0Count = incidents?.filter(i => i.severity === 'P0').length ?? 0

  // 2026-04-07 Claude Code: Sprint 4 E2 — 從 disposition API 取得真實自動化率
  const [dispositionRate, setDispositionRate] = useState<{ auto_rate: number; total: number } | null>(null)
  useEffect(() => {
    fetch(`${API_BASE}/api/v1/stats/disposition`)
      .then(r => r.json())
      .then(d => {
        if (d?.summary) setDispositionRate({ auto_rate: d.summary.auto_rate, total: d.summary.total })
      })
      .catch(() => {})
  }, [])

  // 自動處置率 — 優先使用 disposition API，fallback 到 incidents 推算
  const autoRemediationRate = (() => {
    if (dispositionRate && dispositionRate.total > 0) {
      return `${Math.round(dispositionRate.auto_rate * 100)}%`
    }
    if (!incidents?.length) return '--'
    const resolved = incidents.filter(i => i.status === 'resolved' || i.status === 'closed').length
    return `${((resolved / incidents.length) * 100).toFixed(0)}%`
  })()

  // 自動處置率數值 (for progress bar)
  const autoRemediationPct = (() => {
    if (dispositionRate && dispositionRate.total > 0) {
      return Math.round(dispositionRate.auto_rate * 100)
    }
    if (!incidents?.length) return 0
    const resolved = incidents.filter(i => i.status === 'resolved' || i.status === 'closed').length
    return Math.round((resolved / incidents.length) * 100)
  })()

  // MTTR 均值 + 趨勢（前半 vs 後半比較）
  const { mttrAvg, mttrTrend } = (() => {
    if (!incidents?.length) return { mttrAvg: '--', mttrTrend: undefined }
    const resolved = incidents.filter(i => i.updated_at && (i.status === 'resolved' || i.status === 'closed'))
    if (!resolved.length) return { mttrAvg: '--', mttrTrend: undefined }
    const durs = resolved.map(i => new Date(i.updated_at).getTime() - new Date(i.created_at).getTime())
    const avgMs = durs.reduce((a, b) => a + b, 0) / durs.length
    const mins = Math.round(avgMs / 60000)
    const avgStr = mins < 60 ? `${mins}m` : `${(mins / 60).toFixed(1)}h`
    // 趨勢：比較前半與後半（需至少4筆）
    let trend: { text: string; color: string } | undefined
    if (durs.length >= 4) {
      const half = Math.floor(durs.length / 2)
      const older = durs.slice(0, half).reduce((a, b) => a + b, 0) / half
      const newer = durs.slice(half).reduce((a, b) => a + b, 0) / (durs.length - half)
      const diffMins = Math.round((newer - older) / 60000)
      if (Math.abs(diffMins) >= 1) {
        trend = diffMins < 0
          ? { text: `↓${Math.abs(diffMins)}m`, color: '#22C55E' }
          : { text: `↑${diffMins}m`, color: '#d97757' }
      }
    }
    return { mttrAvg: avgStr, mttrTrend: trend }
  })()

  // 今日事件 sparkline: 過去 6 小時每小時事件數 (真實數據)
  const todaySparkValues = (() => {
    if (!incidents?.length) return null
    const now = Date.now()
    const buckets = Array.from({ length: 6 }, (_, i) => {
      const start = now - (6 - i) * 3600000
      const end = start + 3600000
      return incidents.filter(inc => {
        const t = new Date(inc.created_at).getTime()
        return t >= start && t < end
      }).length
    })
    return buckets.some(v => v > 0) ? buckets : null
  })()

  // MTTR sparkline: 每筆已解決 incident 的修復時間 (分鐘) 序列 (真實數據)
  const mttrSparkValues = (() => {
    if (!incidents?.length) return null
    const resolved = incidents
      .filter(i => i.updated_at && (i.status === 'resolved' || i.status === 'closed'))
      .map(i => Math.round((new Date(i.updated_at).getTime() - new Date(i.created_at).getTime()) / 60000))
      .filter(m => m > 0)
    return resolved.length >= 2 ? resolved.slice(-6) : null
  })()

  // POD health: healthy services / total
  const podHealthStr = totalServices > 0 ? `${healthyServices}/${totalServices}` : '--'
  const podAllRunning = totalServices > 0 && healthyServices === totalServices

  // ── 5 KPI Cards (Sprint 5R 設計稿批准版) ────────────────────────────────────

  const hasPendingApprovals = pendingApprovals !== null && pendingApprovals !== undefined && pendingApprovals > 0
  const incidentCount = incidents?.length ?? 0
  const p1Count = incidents?.filter(i => i.severity === 'P1').length ?? 0
  const p2Count = incidents?.filter(i => i.severity === 'P2').length ?? 0

  // 本週操作數
  const [weeklyOps, setWeeklyOps] = useState<number | null>(null)
  useEffect(() => {
    fetch(`${API_BASE}/api/v1/audit-logs/stats`)
      .then(r => r.ok ? r.json() : null)
      .then(d => { if (d?.total_executions != null) setWeeklyOps(d.total_executions) })
      .catch(() => {})
  }, [])

  // 系統健康百分比
  const systemHealthPct = totalServices > 0 ? Math.round((healthyServices / totalServices) * 100) : 0

  // Sprint 5: 4 Tab 配置 (統帥批准 2026-04-08)
  const alertsCount = incidents?.length ?? 0
  const tabs: TabConfig[] = [
    { id: 'overview', label: tDashboard('tabs.overview'), content: null },
    { id: 'alerts', label: tDashboard('tabs.alerts'), badge: alertsCount > 0 ? alertsCount : undefined, content: <AlertsAndApprovalsTab /> },
    { id: 'stream', label: tDashboard('tabs.stream'), content: <ActivityStreamTab /> },
    { id: 'disposition', label: tDashboard('tabs.disposition'), content: <DispositionTab /> },
  ]

  // Sprint 5: 從 URL 讀取當前 Tab
  const [activeTabId, setActiveTabId] = useState('overview')
  const [infraView, setInfraView] = useState<'host' | 'topo'>('topo')
  const [selectedHost, setSelectedHost] = useState<any>(null)

  // I1 修正: popstate 取代 100ms 輪詢
  useEffect(() => {
    const syncTab = () => {
      const tab = new URLSearchParams(window.location.search).get('tab') || 'overview'
      setActiveTabId(prev => prev !== tab ? tab : prev)
    }
    syncTab()
    window.addEventListener('popstate', syncTab)
    // PageTabs router.push 後 URL 改變，用 hashchange + 定期低頻同步(1s)作為備援
    const fallback = setInterval(syncTab, 1000)
    return () => { window.removeEventListener('popstate', syncTab); clearInterval(fallback) }
  }, [])

  return (
    <AppLayout locale={locale} showBackground={false} fullBleed>
      {/* Sprint 5: Tab Bar */}
      <PageTabs
        tabs={tabs.map(t => ({ ...t, content: t.id === 'overview' ? <></> : t.content }))}
        defaultTab="overview"
        syncWithUrl={true}
      />

      {/* Tab 1 戰情總覽: 顯示現有首頁完整內容 */}
      {activeTabId === 'overview' && (
      <div style={{
        display: 'flex',
        flexDirection: 'column',
        height: 'calc(100vh - 68px)',
        background: '#f5f4ed',
        fontFamily: 'var(--font-body), monospace',
        overflow: 'hidden',
      }}>

        {/* ── KPI Strip (5 卡片 — Sprint 5R 設計稿) ──────────────────────── */}
        <div style={{ display: 'flex', gap: 12, padding: '10px 20px', flexShrink: 0 }}>
          {/* 系統健康 */}
          <div style={{ flex: 1, background: '#fff', border: '0.5px solid #e0ddd4', borderRadius: 8, padding: '8px 12px' }}>
            <div style={{ fontSize: 10, textTransform: 'uppercase', letterSpacing: '0.5px', color: '#87867f', fontWeight: 500 }}>{tDashboard('serviceHealth')}</div>
            <div style={{ fontSize: 22, fontWeight: 700, color: '#22C55E', marginTop: 2 }}>
              {totalServices > 0 ? `${Math.round((healthyServices / totalServices) * 100)}%` : '--'}
            </div>
            {totalServices > 0 && (
              <div style={{ height: 3, borderRadius: 2, background: '#ebe8df', marginTop: 4, overflow: 'hidden' }}>
                <div style={{ width: `${systemHealthPct}%`, height: '100%', borderRadius: 2, background: '#22C55E' }} />
              </div>
            )}
          </div>
          {/* 活動事件 */}
          <div style={{ flex: 1, background: '#fff', border: '0.5px solid #e0ddd4', borderRadius: 8, padding: '8px 12px' }}>
            <div style={{ fontSize: 10, textTransform: 'uppercase', letterSpacing: '0.5px', color: '#87867f', fontWeight: 500 }}>{tDashboard('activeIncidents')}</div>
            <div style={{ display: 'flex', alignItems: 'baseline', gap: 6, marginTop: 2 }}>
              <span style={{ fontSize: 22, fontWeight: 700, color: incidentCount > 0 ? '#d97757' : '#141413' }}>{incidentCount || '--'}</span>
              {incidentCount > 0 && <span style={{ fontSize: 9, color: '#87867f' }}>P1:{p1Count} P2:{p2Count}</span>}
            </div>
          </div>
          {/* 自動修復率 */}
          <div style={{ flex: 1, background: '#fff', border: '0.5px solid #e0ddd4', borderRadius: 8, padding: '8px 12px' }}>
            <div style={{ fontSize: 10, textTransform: 'uppercase', letterSpacing: '0.5px', color: '#87867f', fontWeight: 500 }}>{tDashboard('autoRemediationRate')}</div>
            <div style={{ display: 'flex', alignItems: 'baseline', gap: 6, marginTop: 2 }}>
              <span style={{ fontSize: 22, fontWeight: 700, color: '#22C55E' }}>{autoRemediationRate}</span>
              {autoRemediationPct > 0 && <span style={{ fontSize: 10, fontWeight: 700, color: '#22C55E' }}>{tDashboard('trendUp', { pct: autoRemediationPct })}</span>}
            </div>
            <div style={{ height: 3, borderRadius: 2, background: '#ebe8df', marginTop: 4, overflow: 'hidden' }}>
              <div style={{ width: `${autoRemediationPct}%`, height: '100%', borderRadius: 2, background: 'linear-gradient(90deg,#22C55E,#4ade80)' }} />
            </div>
          </div>
          {/* 待審批 */}
          <div style={{ flex: 1, background: '#fff', border: '0.5px solid #e0ddd4', borderRadius: 8, padding: '8px 12px' }}>
            <div style={{ fontSize: 10, textTransform: 'uppercase', letterSpacing: '0.5px', color: '#87867f', fontWeight: 500 }}>{tDashboard('pendingApprovals')}</div>
            <div style={{ display: 'flex', alignItems: 'baseline', gap: 6, marginTop: 2 }}>
              <span style={{ fontSize: 22, fontWeight: 700, color: hasPendingApprovals ? '#F59E0B' : '#141413' }}>{pendingApprovals ?? '--'}</span>
              {hasPendingApprovals && <span style={{ fontSize: 9, color: '#F59E0B' }}>{tDashboard('awaitingConfirm')}</span>}
            </div>
          </div>
          {/* 本週操作 */}
          <div style={{ flex: 1, background: '#fff', border: '0.5px solid #e0ddd4', borderRadius: 8, padding: '8px 12px' }}>
            <div style={{ fontSize: 10, textTransform: 'uppercase', letterSpacing: '0.5px', color: '#87867f', fontWeight: 500 }}>{tDashboard('todayIncidents')}</div>
            <div style={{ fontSize: 22, fontWeight: 700, color: '#141413', marginTop: 2 }}>{weeklyOps != null ? weeklyOps.toLocaleString() : '--'}</div>
          </div>
        </div>

        {/* ── 主體 2 欄 ─────────────────────────────────────────────────────── */}
        <div style={{ display: 'flex', flex: 1, overflow: 'hidden', padding: '14px 20px', gap: 20, background: '#f5f4ed' }}>

          {/* ── 左欄 (60%): 活躍事件 + 處置統計 + 最近活動 ─────────────── */}
          <div style={{
            flex: 6, minWidth: 0, overflowY: 'auto',
            display: 'flex', flexDirection: 'column', gap: 14,
            paddingBottom: 40,
          }}>

            {/* 活躍事件 */}
            <div style={{
              background: '#fff', border: '0.5px solid #e0ddd4', borderRadius: 10,
              overflow: 'hidden', boxShadow: '0 1px 3px rgba(0,0,0,0.04)', flexShrink: 0,
            }}>
              <div style={{
                padding: '10px 14px', borderBottom: '0.5px solid #e0ddd4',
                display: 'flex', alignItems: 'center', gap: 8, background: '#faf9f3',
              }}>
                <div style={{ width: 6, height: 6, borderRadius: '50%', background: '#d97757', flexShrink: 0 }} />
                <span style={{ fontSize: 14, fontWeight: 700, color: '#141413', letterSpacing: '0.5px' }}>
                  {tDashboard('activeIncidents')}
                </span>
                {(incidents?.length ?? 0) > 0 && (
                  <span style={{
                    fontSize: 12, background: 'rgba(217,119,87,0.1)', color: '#a04010',
                    padding: '2px 8px', fontWeight: 700,
                    border: '0.5px solid rgba(217,119,87,0.25)', borderRadius: 10,
                  }}>
                    {incidents?.length}
                  </span>
                )}
                <span style={{ marginLeft: 'auto', fontSize: 11, color: '#4A90D9', cursor: 'pointer', fontWeight: 500 }}>查看全部告警 →</span>
              </div>

              <div style={{ padding: '14px' }}>
                {isIncidentsLoading ? (
                  <PulseSkeleton count={3} height={12} />
                ) : incidentsError ? (
                  <div style={{ padding: 16, fontSize: 13, color: '#cc2200' }}>{incidentsError}</div>
                ) : (incidents?.length ?? 0) === 0 ? (
                  <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', padding: 48, gap: 8 }}>
                    <div style={{ width: 8, height: 8, borderRadius: '50%', background: '#22C55E' }} />
                    <span style={{ fontSize: 13, color: '#87867f' }}>{tDashboard('stable')} · 0 {tDashboard('activeIncidents')}</span>
                  </div>
                ) : (
                  <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
                    {incidents?.map((incident) => (
                      <IncidentCard
                        key={incident.incident_id}
                        incident={incident}
                        decision={incident.decision}
                      />
                    ))}
                  </div>
                )}
              </div>
            </div>

            {/* 處置統計迷你版 (S4) */}
            <DispositionMini />

            {/* 最近活動 (S5) */}
            <RecentActivity />

          </div>

          {/* ── 右欄 (40%): OpenClaw + 基礎架構 + 監控工具 ─────────────── */}
          <div style={{
            flex: 4, minWidth: 0,
            overflowY: 'auto',
            display: 'flex',
            flexDirection: 'column',
            gap: 14,
            paddingBottom: 40,
          }}>

            {/* WoooClaw + Reasoning Stream */}
            <div style={{
              background: '#fff',
              border: '0.5px solid #e0ddd4',
              borderRadius: 12,
              overflow: 'hidden',
              boxShadow: '0 1px 4px rgba(0,0,0,0.05)',
              flexShrink: 0,
            }}>
              <div style={{
                padding: '10px 14px',
                borderBottom: '0.5px solid #e0ddd4',
                fontSize: 14, fontWeight: 700, color: '#141413',
                letterSpacing: '0.5px',
                fontFamily: 'var(--font-body), monospace', background: '#faf9f3',
                display: 'flex', alignItems: 'center', gap: 8,
              }}>
                <div style={{ width: 6, height: 6, borderRadius: '50%', background: '#d97757', flexShrink: 0 }} />
                {tDashboard('openclawEngine')}
              </div>
              <OpenClawPanel
                status={(incidents?.length ?? 0) > 0 ? 'analyzing' : 'patrolling'}
              />
            </div>

            {/* 待審批任務 (S7) */}
            <PendingApprovalsCard />

            {/* 飛輪健康度 KPI (ADR-073-C C2) */}
            <FlywheelKPICard />

            {/* 基礎架構 — Toggle: 拓撲圖 / 主機網格 */}
            <div style={{
              background: '#fff',
              border: '0.5px solid #e0ddd4',
              borderRadius: 12,
              overflow: 'hidden',
              boxShadow: '0 1px 4px rgba(0,0,0,0.05)',
              flexShrink: 0,
            }}>
              <div style={{
                padding: '10px 14px',
                borderBottom: '0.5px solid #e0ddd4',
                fontSize: 14, fontWeight: 700, color: '#141413',
                letterSpacing: '0.5px',
                fontFamily: 'var(--font-body), monospace', background: '#faf9f3',
                display: 'flex', alignItems: 'center', gap: 8,
                flexShrink: 0,
              }}>
                <div style={{ width: 6, height: 6, borderRadius: '50%', background: '#d97757', flexShrink: 0 }} />
                {tDashboard('infrastructure')}
                {/* Toggle 切換 */}
                <div style={{ marginLeft: 'auto', display: 'flex', background: '#f5f4ed', borderRadius: 5, padding: 2 }}>
                  <button
                    onClick={() => setInfraView('host')}
                    style={{
                      padding: '3px 10px', borderRadius: 3, fontSize: 10, fontWeight: infraView === 'host' ? 600 : 400,
                      cursor: 'pointer', border: 'none',
                      background: infraView === 'host' ? '#fff' : 'transparent',
                      color: infraView === 'host' ? '#d97757' : '#87867f',
                      boxShadow: infraView === 'host' ? '0 1px 2px rgba(0,0,0,0.06)' : 'none',
                    }}
                  >{tDashboard('hostView')}</button>
                  <button
                    onClick={() => setInfraView('topo')}
                    style={{
                      padding: '3px 10px', borderRadius: 3, fontSize: 10, fontWeight: infraView === 'topo' ? 600 : 400,
                      cursor: 'pointer', border: 'none',
                      background: infraView === 'topo' ? '#fff' : 'transparent',
                      color: infraView === 'topo' ? '#d97757' : '#87867f',
                      boxShadow: infraView === 'topo' ? '0 1px 2px rgba(0,0,0,0.06)' : 'none',
                    }}
                  >{tDashboard('topoView')}</button>
                </div>
              </div>
              {/* 拓撲群組 2×2 (設計稿 L514-519) */}
              {infraView === 'topo' && (
                <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 8, padding: 14 }}>
                  {[
                    { name: `${tTopo('groupInfra')} (.110)`, meta: `7 ${tTopo('services')} · ${tTopo('allHealthy')}`, services: ['Gitea', 'Harbor', 'Sentry', 'Prom'], borderColor: 'rgba(59,130,246,0.2)', bg: 'rgba(59,130,246,0.01)' },
                    { name: `${tTopo('groupAiData')} (.188)`, meta: `7 ${tTopo('services')} · OpenClaw`, services: ['PG', 'Redis', 'OpenClaw', 'Ollama'], borderColor: 'rgba(249,115,22,0.25)', bg: 'rgba(249,115,22,0.01)' },
                    { name: tTopo('groupK3s'), meta: `5 ${tTopo('services')} · ${incidentCount > 0 ? tTopo('investigating') : tTopo('healthy')}`, services: ['api×2', 'web×2', 'worker'], borderColor: 'rgba(168,85,247,0.25)', bg: 'rgba(168,85,247,0.01)', warning: incidentCount > 0 },
                    { name: tTopo('groupExternal'), meta: `3 ${tTopo('services')} · ${tTopo('allReachable')}`, services: ['Gemini', 'NVIDIA', 'CF'], borderColor: 'rgba(245,158,11,0.2)', bg: 'rgba(245,158,11,0.01)' },
                  ].map(g => (
                    <div key={g.name} style={{
                      border: `0.5px solid ${g.borderColor}`, borderRadius: 8, padding: '8px 10px',
                      background: g.bg, cursor: 'pointer', transition: 'all 0.12s',
                      ...(g.warning ? { boxShadow: '0 0 8px rgba(245,158,11,0.15)' } : {}),
                    }}>
                      <div style={{ fontSize: 12, fontWeight: 600, marginBottom: 2 }}>{g.name}</div>
                      <div style={{ fontSize: 10, color: '#555550' }}>{g.meta}</div>
                      <div style={{ display: 'flex', flexWrap: 'wrap', gap: 2, marginTop: 4 }}>
                        {g.services.map(s => (
                          <span key={s} style={{
                            display: 'flex', alignItems: 'center', gap: 3,
                            padding: '2px 7px', background: '#fff', border: '0.5px solid #e0ddd4',
                            borderRadius: 4, fontSize: 10,
                          }}>
                            <span style={{ width: 3, height: 3, borderRadius: '50%', background: s.includes('worker') && g.warning ? '#F59E0B' : '#22C55E' }} />
                            {s}
                          </span>
                        ))}
                      </div>
                    </div>
                  ))}
                </div>
              )}
              {/* 主機網格 2×2 (設計稿 L522-527) */}
              {infraView === 'host' && (
                <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 8, padding: 14 }}>
                  {[
                    { name: tTopo('hostDevops'), ip: '192.168.0.110', cpu: 35, ram: 55 },
                    { name: tTopo('hostAiData'), ip: '192.168.0.188', cpu: 67, ram: 72 },
                    { name: tTopo('hostK3sMaster'), ip: '192.168.0.120', cpu: 45, ram: 60 },
                    { name: tTopo('hostK3sWorker'), ip: '192.168.0.121', cpu: null as number | null, ram: null as number | null },
                  ].map(h => {
                    const apiHost = hosts.find(ah => ah.ip === h.ip)
                    const cpu = apiHost?.metrics?.cpu_percent ?? h.cpu
                    const ram = apiHost?.metrics?.memory_percent ?? h.ram
                    const isSelected = selectedHost?.ip === h.ip
                    return (
                      <div
                        key={h.ip}
                        onClick={() => setSelectedHost(isSelected ? null : { ...h, cpu, ram, services: apiHost?.services ?? [], status: apiHost?.status ?? 'unknown', role: apiHost?.role })}
                        style={{
                          border: `0.5px solid ${isSelected ? '#4A90D9' : '#e0ddd4'}`,
                          borderRadius: 8, padding: '8px 10px',
                          background: isSelected ? 'rgba(74,144,217,0.05)' : '#faf9f3',
                          cursor: 'pointer', transition: 'all 0.15s',
                        }}
                      >
                        <div style={{ fontSize: 12, fontWeight: 600, marginBottom: 2 }}>{h.name}</div>
                        <div style={{ fontSize: 10, color: '#555550', fontFamily: "'JetBrains Mono', monospace" }}>{h.ip}</div>
                        <div style={{ display: 'flex', gap: 6, marginTop: 5 }}>
                          {['CPU', 'RAM'].map((label, idx) => {
                            const val = idx === 0 ? cpu : ram
                            const color = val != null ? (val > 60 ? '#F59E0B' : '#22C55E') : '#e0ddd4'
                            return (
                              <div key={label} style={{ flex: 1 }}>
                                <div style={{ fontSize: 7, color: '#87867f', display: 'flex', justifyContent: 'space-between', marginBottom: 2 }}>
                                  <span>{label}</span><span>{val != null ? `${val}%` : '--'}</span>
                                </div>
                                <div style={{ height: 3, borderRadius: 2, background: '#ebe8df', overflow: 'hidden' }}>
                                  <div style={{ width: val != null ? `${val}%` : '0%', height: '100%', borderRadius: 2, background: color }} />
                                </div>
                              </div>
                            )
                          })}
                        </div>
                      </div>
                    )
                  })}
                </div>
              )}

              {/* 主機詳情抽屜 — 點擊主機卡滑入 */}
              {infraView === 'host' && selectedHost && (() => {
                const sh = selectedHost
                const relatedIncidents = incidents.filter(inc =>
                  inc.affected_services?.some(s => s.includes(sh.ip))
                ).slice(0, 3)
                return (
                  <div style={{
                    margin: '0 14px 14px',
                    border: '0.5px solid #4A90D9',
                    borderRadius: 10,
                    overflow: 'hidden',
                    background: '#fff',
                    animation: 'slideDown 0.2s ease',
                  }}>
                    {/* 標頭 */}
                    <div style={{ background: 'rgba(74,144,217,0.06)', borderBottom: '0.5px solid #dbeafe', padding: '10px 14px', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
                      <div>
                        <div style={{ fontSize: 13, fontWeight: 700, color: '#141413' }}>{sh.name}</div>
                        <div style={{ fontSize: 10, color: '#87867f', fontFamily: "'JetBrains Mono', monospace" }}>{sh.ip}</div>
                      </div>
                      <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
                        {sh.status && (
                          <span style={{ fontSize: 10, background: sh.status === 'healthy' ? 'rgba(34,197,94,0.12)' : 'rgba(204,34,0,0.1)', color: sh.status === 'healthy' ? '#22C55E' : '#cc2200', borderRadius: 4, padding: '2px 8px', fontWeight: 600 }}>
                            {sh.status}
                          </span>
                        )}
                        <button onClick={() => setSelectedHost(null)} style={{ border: 'none', background: 'none', cursor: 'pointer', fontSize: 14, color: '#87867f', padding: '0 2px' }}>✕</button>
                      </div>
                    </div>

                    <div style={{ padding: '12px 14px', display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
                      {/* 左：Metrics 大字 + 服務清單 */}
                      <div>
                        <div style={{ display: 'flex', gap: 12, marginBottom: 10 }}>
                          {[{ label: 'CPU', val: sh.cpu }, { label: 'RAM', val: sh.ram }].map(m => {
                            const color = m.val != null ? (m.val > 80 ? '#cc2200' : m.val > 60 ? '#F59E0B' : '#22C55E') : '#b0ad9f'
                            return (
                              <div key={m.label} style={{ flex: 1, border: '0.5px solid #e0ddd4', borderRadius: 8, padding: '8px 10px', textAlign: 'center' }}>
                                <div style={{ fontSize: 9, color: '#87867f', fontWeight: 700, textTransform: 'uppercase', letterSpacing: 0.5 }}>{m.label}</div>
                                <div style={{ fontSize: 24, fontWeight: 700, color, marginTop: 2 }}>{m.val != null ? `${m.val}%` : '--'}</div>
                              </div>
                            )
                          })}
                        </div>
                        {/* 服務清單 */}
                        <div style={{ fontSize: 10, fontWeight: 700, textTransform: 'uppercase', color: '#87867f', marginBottom: 5 }}>服務</div>
                        {sh.services.length === 0 ? (
                          <div style={{ fontSize: 11, color: '#b0ad9f' }}>--</div>
                        ) : sh.services.map((svc: any, i: number) => (
                          <div key={i} style={{ display: 'flex', alignItems: 'center', gap: 6, padding: '3px 0', borderBottom: '0.5px solid #f5f4ed', fontSize: 11 }}>
                            <div style={{ width: 5, height: 5, borderRadius: '50%', background: svc.status === 'up' ? '#22C55E' : '#cc2200', flexShrink: 0 }} />
                            <span style={{ flex: 1, color: '#141413' }}>{svc.name}</span>
                            {svc.port && <span style={{ color: '#87867f', fontFamily: "'JetBrains Mono', monospace", fontSize: 10 }}>:{svc.port}</span>}
                            {svc.latency_ms != null && <span style={{ color: '#87867f', fontSize: 10 }}>{svc.latency_ms}ms</span>}
                          </div>
                        ))}
                      </div>

                      {/* 右：相關事件 */}
                      <div>
                        <div style={{ fontSize: 10, fontWeight: 700, textTransform: 'uppercase', color: '#87867f', marginBottom: 5 }}>相關事件</div>
                        {relatedIncidents.length === 0 ? (
                          <div style={{ fontSize: 11, color: '#b0ad9f' }}>無相關事件</div>
                        ) : relatedIncidents.map((inc: any, i: number) => (
                          <div key={i} style={{ padding: '5px 8px', marginBottom: 4, borderRadius: 5, background: '#faf9f3', border: '0.5px solid #e0ddd4' }}>
                            <div style={{ fontSize: 10, fontWeight: 600, color: '#d97757', marginBottom: 2 }}>{inc.severity}</div>
                            <div style={{ fontSize: 11, color: '#141413', lineHeight: 1.3, fontFamily: "'JetBrains Mono', monospace" }}>{inc.incident_id}</div>
                            <div style={{ fontSize: 10, color: '#87867f', marginTop: 2 }}>{inc.status} · {inc.affected_services.slice(0,2).join(', ')}</div>
                          </div>
                        ))}
                      </div>
                    </div>
                  </div>
                )
              })()}
            </div>

            {/* 監控工具 — figma-v2 style: 左彩色條 + 可點擊 + meta行 */}
            <div style={{
              background: '#fff',
              border: '0.5px solid #e0ddd4',
              borderRadius: 12,
              overflow: 'hidden',
              boxShadow: '0 1px 4px rgba(0,0,0,0.05)',
              flexShrink: 0,
            }}>
              <div style={{
                padding: '10px 14px',
                borderBottom: '0.5px solid #e0ddd4',
                fontSize: 14, fontWeight: 700, color: '#141413',
                letterSpacing: '0.5px',
                fontFamily: 'var(--font-body), monospace', background: '#faf9f3',
                display: 'flex', alignItems: 'center', gap: 8,
              }}>
                <div style={{ width: 6, height: 6, borderRadius: '50%', background: '#d97757', flexShrink: 0 }} />
                {tDashboard('monitoringTools')}
              </div>
              <MonitoringTools />
            </div>

            {/* AI 模型狀態 (S9) */}
            <AIModelStatus />

          </div>
        </div>
      </div>
      )}
    </AppLayout>
  )
}
