import { useEffect, useRef, useState } from 'react'
import { useAuth, jget } from './auth'
import LoginGate from './AdminLogin'
import { box } from './util'

type View = 'portal' | 'ops' | 'admin'
type Health = { service: string; center: string; pid: number; lastSeen: number; ageMs: number; status: string }
type SvcMetric = { service: string; port: number; reachable: boolean; metrics: Record<string, any> }

/** 6개 주 서비스 카드 메타(순번기는 흐름도 진입 노드로만 표기). 이름은 영문, 역할 설명은 한글 유지. */
const SERVICES: { id: string; name: string; role: string; emoji: string; color: string }[] = [
  { id: 'gucci', name: 'Gucci', role: '게이트웨이 · 기관 인증', emoji: '🛡️', color: '#6b4fbb' },
  { id: 'chanel', name: 'Chanel', role: '접수', emoji: '📥', color: '#0b63c4' },
  { id: 'hermes', name: 'Hermes', role: '결제 · 원장 엔진', emoji: '💰', color: '#c77d0a' },
  { id: 'dior', name: 'Dior', role: '센터간 접수 동기화', emoji: '🔄', color: '#8a4fd0' },
  { id: 'prada', name: 'Prada', role: '센터간 처리 동기화 · 완결', emoji: '✅', color: '#b8860b' },
  { id: 'louisvuitton', name: 'Louis Vuitton', role: '관리자 · 운영', emoji: '🛠️', color: '#1a7f37' },
]

/** 업무 흐름도 노드(순번기→관문→접수→동기화→결제→처리동기화→통보). 서비스명 영문, 단계 설명 한글. */
const FLOW: { id: string; label: string }[] = [
  { id: 'sequencer', label: 'Sequencer' }, { id: 'gucci', label: 'Gucci(관문)' }, { id: 'chanel', label: 'Chanel(접수)' },
  { id: 'dior', label: 'Dior(동기화)' }, { id: 'hermes', label: 'Hermes(결제)' }, { id: 'prada', label: 'Prada(처리동기화)' },
  { id: 'chanel', label: '결과통보' },
]
const ALL_IDS = ['sequencer', 'gucci', 'chanel', 'dior', 'hermes', 'prada', 'louisvuitton']

const stColor = (s: string) => (s === 'UP' ? '#1a7f37' : s === 'STALE' ? '#b58900' : '#c0392b')
const stDot = (s: string) => (s === 'UP' ? '🟢' : s === 'STALE' ? '🟡' : '🔴')

export default function Portal({ onNavigate }: { onNavigate?: (v: View) => void }) {
  return <LoginGate><PortalInner onNavigate={onNavigate} /></LoginGate>
}

function PortalInner({ onNavigate }: { onNavigate?: (v: View) => void }) {
  const { token } = useAuth()
  const [health, setHealth] = useState<Health[]>([])
  const [metrics, setMetrics] = useState<SvcMetric[]>([])
  const [summary, setSummary] = useState<any>(null)
  const [core, setCore] = useState<string>('?') // Gucci가 본 코어(Chanel) 상태
  const [err, setErr] = useState<string | null>(null)
  const [auto, setAuto] = useState(true)
  const [at, setAt] = useState<number>(0)
  const prevTx = useRef<{ n: number; at: number } | null>(null)
  const [tps, setTps] = useState(0)

  const load = async () => {
    setErr(null)
    try {
      const [h, m, s, c] = await Promise.all([
        jget('/admin/health'),
        jget('/admin/metrics/summary'),
        jget('/admin/summary'),
        jget('/gucci/health/centers').catch(() => null),
      ])
      setHealth(h); setMetrics(m?.services ?? []); setSummary(s)
      setCore(c?.centers?.[0]?.['core(chanel)'] ?? '?')
      const now = Date.now()
      const txn = Number(s?.transfers ?? 0)
      if (prevTx.current) {
        const dt = (now - prevTx.current.at) / 1000
        if (dt > 0) setTps(Math.max(0, Math.round(((txn - prevTx.current.n) / dt) * 10) / 10))
      }
      prevTx.current = { n: txn, at: now }
      setAt(now)
    } catch (e: any) { setErr('포탈 데이터 로드 실패: ' + e.message) }
  }

  useEffect(() => { if (token) load() }, [token])
  useEffect(() => {
    if (!auto || !token) return
    const t = setInterval(load, 5000)
    return () => clearInterval(t)
  }, [auto, token])

  const hMap: Record<string, Health> = Object.fromEntries(health.map((h) => [h.service, h]))
  const mMap: Record<string, SvcMetric> = Object.fromEntries(metrics.map((m) => [m.service, m]))
  const statusOf = (id: string): string => {
    const h = hMap[id]
    if (h) return h.status
    if (mMap[id]?.reachable) return 'UP'
    return 'DOWN'
  }
  const upCount = ALL_IDS.filter((id) => statusOf(id) === 'UP').length

  /** transfer 상태별 건수(DB 집계 /admin/summary.byStatus). 초기화 시 자연히 0. */
  const statusCount = (st: string): number => {
    const row = (summary?.byStatus ?? []).find((r: any) => r.status === st)
    return row ? Number(row.cnt) : 0
  }

  /** 서비스별 지표 라인. 처리 건수는 DB 집계 기반(초기화 반영), 성능/자원은 런타임 지표. */
  const metricLines = (id: string): { label: string; value: string }[] => {
    const m = mMap[id]?.metrics ?? {}
    const acccN = statusCount('ACCC')
    switch (id) {
      case 'gucci':
        return [{ label: '코어(샤넬)', value: core }, { label: '등록기관', value: String(summary?.accounts ?? '-') }]
      case 'chanel':
        return [{ label: '누적 접수', value: String(summary?.transfers ?? '-') }, { label: '접수율', value: `${tps} 건/s` }]
      case 'hermes':
        return [
          { label: '결제완료(ACCC)', value: String(acccN) },
          { label: '평균 처리', value: `${m.settleMeanMs ?? 0} ms` },
          { label: '미결(대기)', value: String(Math.max(0, Number(summary?.transfers ?? 0) - acccN - statusCount('RJCT'))) },
        ]
      case 'prada':
        return [{ label: '완결(ACCC)', value: String(acccN) }, { label: '반려(RJCT)', value: String(statusCount('RJCT')) }]
      case 'dior':
        return [{ label: '메모리', value: m.memUsedMb != null ? `${m.memUsedMb} MB` : '-' }, { label: '가동', value: m.uptimeSec != null ? `${m.uptimeSec}s` : '-' }]
      case 'louisvuitton':
        return [{ label: '총 거래', value: String(summary?.transfers ?? '-') }, { label: '최대순번', value: String(summary?.maxSeq ?? '-') }]
      default:
        return []
    }
  }

  /** 서비스별 바로가기 버튼. */
  const actions = (id: string): { label: string; onClick: () => void }[] => {
    switch (id) {
      case 'gucci':
        return [{ label: '감사로그(Kibana)', onClick: () => window.open('http://localhost:5601', '_blank') }]
      case 'chanel':
        return [{ label: '이체 신청/조회', onClick: () => onNavigate?.('ops') }]
      case 'hermes':
        return [{ label: '원장 보기', onClick: () => onNavigate?.('admin') }]
      case 'dior':
        return [{ label: '원장 보기', onClick: () => onNavigate?.('admin') }]
      case 'prada':
        return [{ label: '완결/조회사본', onClick: () => onNavigate?.('admin') }]
      case 'louisvuitton':
        return [
          { label: '관리자 콘솔', onClick: () => onNavigate?.('admin') },
          { label: '로그(Kibana)', onClick: () => window.open('http://localhost:5601', '_blank') },
        ]
      default:
        return []
    }
  }

  const btn: React.CSSProperties = { padding: '6px 12px', border: '1px solid #ccc', borderRadius: 6, cursor: 'pointer', background: '#fff', fontSize: 13 }

  return (
    <div>
      {/* 상단 바 */}
      <div style={{ display: 'flex', alignItems: 'center', gap: 14, flexWrap: 'wrap', marginTop: 8, padding: '10px 14px', background: '#f4f7fb', borderRadius: 8 }}>
        <b style={{ fontSize: 15 }}>🏛 RTGS 포탈</b>
        <span style={{ color: '#666' }}>DC1</span>
        <span style={{ color: stColor(upCount === ALL_IDS.length ? 'UP' : upCount === 0 ? 'DOWN' : 'STALE'), fontWeight: 600 }}>
          ● {upCount}/{ALL_IDS.length} UP
        </span>
        <button onClick={load} style={btn}>새로고침</button>
        <label style={{ fontSize: 13, color: '#444' }}>
          <input type="checkbox" checked={auto} onChange={(e) => setAuto(e.target.checked)} /> 자동갱신 5s
        </label>
        {at > 0 && <span style={{ color: '#999', fontSize: 12 }}>업데이트 {new Date(at).toLocaleTimeString('ko-KR')}</span>}
      </div>

      {/* 업무 흐름도 — 창 폭에 맞춰 결과통보까지 한 화면에(가로 스크롤 없음). */}
      <section style={{ ...box }}>
        <div style={{ fontWeight: 600, marginBottom: 10 }}>업무 흐름</div>
        <div style={{ display: 'flex', alignItems: 'center', gap: 4, width: '100%' }}>
          {FLOW.map((n, i) => {
            const s = statusOf(n.id)
            return (
              <div key={i} style={{ display: 'flex', alignItems: 'center', gap: 4, flex: 1, minWidth: 0 }}>
                <div style={{ flex: 1, minWidth: 0, padding: '8px 6px', borderRadius: 8, border: `2px solid ${stColor(s)}`, background: '#fff', textAlign: 'center' }}>
                  <div style={{ fontSize: 12, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{stDot(s)} {n.label}</div>
                </div>
                {i < FLOW.length - 1 && <span style={{ color: '#999', fontSize: 18, flex: '0 0 auto' }}>→</span>}
              </div>
            )
          })}
        </div>
        <div style={{ color: '#888', fontSize: 12, marginTop: 8 }}>전역순번(Sequencer) 부여 → 관문 인증(Gucci) → 접수(Chanel) → 저널/센터 동기화(Dior) → 결제·원장(Hermes) → 처리 동기화·완결(Prada) → 결과통보(Chanel)</div>
      </section>

      {/* 서비스 카드 6장 */}
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(280px, 1fr))', gap: 14, marginTop: 20 }}>
        {SERVICES.map((svc) => {
          const s = statusOf(svc.id)
          const h = hMap[svc.id]
          return (
            <div key={svc.id} style={{ border: `1px solid #e2e2e2`, borderTop: `4px solid ${svc.color}`, borderRadius: 8, padding: 14 }}>
              <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
                <div style={{ fontSize: 16, fontWeight: 700 }}>{svc.emoji} {svc.name}</div>
                <span style={{ fontSize: 12, fontWeight: 600, color: stColor(s) }}>{stDot(s)} {s}</span>
              </div>
              <div style={{ color: '#666', fontSize: 13, margin: '2px 0 6px' }}>{svc.role}</div>
              <div style={{ color: '#999', fontSize: 11, fontFamily: 'monospace' }}>
                :{mMap[svc.id]?.port ?? '-'}{h ? ` · pid ${h.pid} · ${Math.round(h.ageMs / 1000)}s` : ' · 하트비트 없음'}
              </div>
              <div style={{ marginTop: 10, display: 'flex', flexDirection: 'column', gap: 3 }}>
                {metricLines(svc.id).map((ml, i) => (
                  <div key={i} style={{ display: 'flex', justifyContent: 'space-between', fontSize: 13 }}>
                    <span style={{ color: '#777' }}>{ml.label}</span><b style={{ fontFamily: 'monospace' }}>{ml.value}</b>
                  </div>
                ))}
              </div>
              <div style={{ marginTop: 12, display: 'flex', gap: 6, flexWrap: 'wrap' }}>
                {actions(svc.id).map((a, i) => <button key={i} onClick={a.onClick} style={btn}>{a.label}</button>)}
              </div>
            </div>
          )
        })}
      </div>

      {err && <p style={{ color: '#c00', marginTop: 16 }}>{err}</p>}
    </div>
  )
}
