import { useEffect, useState } from 'react'
import AdminPanel from './AdminPanel'

type Account = { code: string; name: string; balance: number }
type Inquiry = Record<string, unknown>

const won = (n: number) => n.toLocaleString('ko-KR') + '원'
const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms))

function genBmi(sender: string): string {
  const d = new Date()
  const date = `${d.getFullYear()}${String(d.getMonth() + 1).padStart(2, '0')}${String(d.getDate()).padStart(2, '0')}`
  const serial = String(Date.now() % 10_000_000_000).padStart(10, '0')
  return date + sender.padStart(4, '0') + serial
}

// epoch(ms) -> YYYYMMDDHH24MISS (14자리)
function fmtTs(ms?: unknown): string {
  if (typeof ms !== 'number' || !ms) return '-'
  const d = new Date(ms)
  const p = (n: number) => String(n).padStart(2, '0')
  return `${d.getFullYear()}${p(d.getMonth() + 1)}${p(d.getDate())}${p(d.getHours())}${p(d.getMinutes())}${p(d.getSeconds())}`
}

const STATUS_KO: Record<string, string> = {
  RCVD: '접수', ACTC: '승인', PDNG: '대기', ACSP: '예약', ACCC: '입금처리완료', RJCT: '반려', IN_FLIGHT: '처리중',
}
const TIME_FIELDS = new Set(['updatedAt', 'createdAt'])
const statusColor = (s?: string) =>
  s === 'ACCC' ? '#1a7f37' : s === 'RJCT' ? '#c00' : s ? '#8a6d00' : '#555'

function prettyXml(xml: string): string {
  return xml.replace(/></g, '>\n<')
}

export default function App() {
  const [accounts, setAccounts] = useState<Account[]>([])
  const [labels, setLabels] = useState<Record<string, string>>({})
  const [err, setErr] = useState<string | null>(null)

  // 자금이체 신청
  const [from, setFrom] = useState('1001')
  const [to, setTo] = useState('1002')
  const [amount, setAmount] = useState(150)
  const [busy, setBusy] = useState(false)
  const [result, setResult] = useState<null | {
    bmi: string; recv: string; recvReason?: string; final?: string; finalReason?: string | null; pending?: boolean
  }>(null)

  // 거래 조회
  const [bmi, setBmi] = useState('')
  const [inquiry, setInquiry] = useState<Inquiry | null>(null)
  const [rawXml, setRawXml] = useState<string | null>(null)

  const [view, setView] = useState<'ops' | 'admin'>('ops')

  const loadAccounts = async () => {
    setErr(null)
    try {
      const r = await fetch('/accounts')
      if (!r.ok) throw new Error('HTTP ' + r.status)
      setAccounts(await r.json())
    } catch (e: any) {
      setErr('계좌 조회 실패: ' + e.message + ' (Chanel :8091 기동 확인)')
    }
  }

  const loadLabels = async () => {
    try { setLabels(await (await fetch('/meta/labels')).json()) } catch { /* 라벨 없으면 영문키 표시 */ }
  }

  const submitTransfer = async () => {
    setErr(null); setResult(null)
    if (from === to) { setErr('송신기관과 수신기관이 같을 수 없습니다.'); return }
    if (!amount || amount <= 0) { setErr('이체금액은 1원 이상이어야 합니다.'); return }
    setBusy(true)
    const newBmi = genBmi(from)
    try {
      const xml =
        `<?xml version="1.0" encoding="UTF-8"?>` +
        `<Document xmlns="urn:iso:std:iso:20022:tech:xsd:pacs.008.001.08"><FIToFICstmrCdtTrf>` +
        `<GrpHdr><MsgId>${newBmi}</MsgId><CreDtTm>${new Date().toISOString().replace(/\.\d+Z$/, '')}</CreDtTm>` +
        `<NbOfTxs>1</NbOfTxs><SttlmInf><SttlmMtd>CLRG</SttlmMtd></SttlmInf></GrpHdr>` +
        `<CdtTrfTxInf><PmtId><EndToEndId>${newBmi}</EndToEndId></PmtId>` +
        `<IntrBkSttlmAmt Ccy="KRW">${amount}</IntrBkSttlmAmt><ChrgBr>SLEV</ChrgBr>` +
        `<Dbtr><Nm>BANK-${from}</Nm></Dbtr><DbtrAcct><Id><Othr><Id>ACC-${from}</Id></Othr></Id></DbtrAcct>` +
        `<DbtrAgt><FinInstnId><ClrSysMmbId><MmbId>${from}</MmbId></ClrSysMmbId></FinInstnId></DbtrAgt>` +
        `<CdtrAgt><FinInstnId><ClrSysMmbId><MmbId>${to}</MmbId></ClrSysMmbId></FinInstnId></CdtrAgt>` +
        `<Cdtr><Nm>BANK-${to}</Nm></Cdtr><CdtrAcct><Id><Othr><Id>ACC-${to}</Id></Othr></Id></CdtrAcct>` +
        `</CdtTrfTxInf></FIToFICstmrCdtTrf></Document>`
      const res = await fetch('/pay/customer', { method: 'POST', headers: { 'Content-Type': 'application/xml' }, body: xml })
      const doc = new DOMParser().parseFromString(await res.text(), 'application/xml')
      const recv = doc.querySelector('TxSts')?.textContent ?? '?'
      const clrRef = doc.querySelector('ClrSysRef')?.textContent ?? ''
      if (recv !== 'RCVD') { setResult({ bmi: newBmi, recv, recvReason: clrRef }); setBusy(false); return }
      setResult({ bmi: newBmi, recv, pending: true })
      let final: any = null
      for (let i = 0; i < 8; i++) {
        await sleep(700)
        const j = await (await fetch('/inquiry/' + newBmi)).json()
        if (j.status === 'ACCC' || j.status === 'RJCT') { final = j; break }
      }
      setResult({ bmi: newBmi, recv, final: final?.status ?? '처리중', finalReason: final?.reason, pending: !final })
      await loadAccounts()
      setBmi(newBmi) // 조회창에 자동 채움
    } catch (e: any) {
      setErr('이체 신청 실패: ' + e.message)
    } finally { setBusy(false) }
  }

  const doInquiry = async () => {
    setErr(null); setInquiry(null); setRawXml(null)
    const key = bmi.trim()
    if (!key) return
    try {
      const [inq, raw] = await Promise.all([
        fetch('/inquiry/' + encodeURIComponent(key)).then((r) => r.json()),
        fetch('/rawmessage/' + encodeURIComponent(key)).then((r) => r.json()).catch(() => null),
      ])
      setInquiry(inq)
      setRawXml(raw?.found ? raw.rawXml : null)
    } catch (e: any) {
      setErr('거래 조회 실패: ' + e.message)
    }
  }

  useEffect(() => { loadAccounts(); loadLabels() }, [])

  const box: React.CSSProperties = { border: '1px solid #e2e2e2', borderRadius: 8, padding: 16, marginTop: 20 }
  const cell: React.CSSProperties = { padding: '6px 10px', borderBottom: '1px solid #eee' }

  const renderVal = (k: string, v: unknown) => {
    if (k === 'status') {
      const s = String(v)
      return <b style={{ color: statusColor(s) }}>{s}{STATUS_KO[s] ? ` (${STATUS_KO[s]})` : ''}</b>
    }
    if (TIME_FIELDS.has(k)) return <span style={{ fontFamily: 'monospace' }}>{fmtTs(v)}</span>
    if (k === 'amount' && typeof v === 'number') return won(v)
    return String(v ?? '-')
  }

  return (
    <div style={{ fontFamily: 'system-ui, sans-serif', maxWidth: 900, margin: '2rem auto', padding: '0 1rem' }}>
      <h1>RTGS 콘솔 <span style={{ fontSize: 14, color: '#888' }}>(DC1 · :5174)</span></h1>

      <div style={{ display: 'flex', gap: 8, margin: '12px 0' }}>
        <button onClick={() => setView('ops')}
                style={{ padding: '8px 16px', border: '1px solid #ccc', borderRadius: 6, cursor: 'pointer', background: view === 'ops' ? '#0b63c4' : '#fff', color: view === 'ops' ? '#fff' : '#333' }}>운영 콘솔</button>
        <button onClick={() => setView('admin')}
                style={{ padding: '8px 16px', border: '1px solid #ccc', borderRadius: 6, cursor: 'pointer', background: view === 'admin' ? '#0b63c4' : '#fff', color: view === 'admin' ? '#fff' : '#333' }}>🛠 관리자 (Louis Vuitton)</button>
      </div>

      {view === 'admin' && <AdminPanel />}

      {view === 'ops' && (<>
      {/* 자금이체 신청 */}
      <section style={{ ...box, background: '#f7fbff' }}>
        <h2 style={{ marginTop: 0 }}>💸 자금이체 신청 (pacs.008)</h2>
        <div style={{ display: 'flex', gap: 12, flexWrap: 'wrap', alignItems: 'flex-end' }}>
          <label>송신기관(ORG_S)<br />
            <select value={from} onChange={(e) => setFrom(e.target.value)} style={{ padding: 8, minWidth: 200 }}>
              {accounts.map((a) => <option key={a.code} value={a.code}>{a.code} {a.name}</option>)}
            </select>
          </label>
          <label>수신기관(ORG_R)<br />
            <select value={to} onChange={(e) => setTo(e.target.value)} style={{ padding: 8, minWidth: 200 }}>
              {accounts.map((a) => <option key={a.code} value={a.code}>{a.code} {a.name}</option>)}
            </select>
          </label>
          <label>이체금액(원)<br />
            <input type="number" min={1} value={amount} onChange={(e) => setAmount(Number(e.target.value))} style={{ padding: 8, width: 140 }} />
          </label>
          <button onClick={submitTransfer} disabled={busy}
                  style={{ padding: '10px 20px', background: busy ? '#9ac' : '#0b63c4', color: '#fff', border: 0, borderRadius: 6, cursor: 'pointer' }}>
            {busy ? '처리중…' : '이체 신청'}
          </button>
        </div>
        {result && (
          <div style={{ marginTop: 14, padding: 12, background: '#fff', border: '1px solid #ddd', borderRadius: 6 }}>
            <div>거래식별자(BMI): <code>{result.bmi}</code></div>
            <div>접수응답: <b style={{ color: statusColor(result.recv) }}>{result.recv}{STATUS_KO[result.recv] ? ` (${STATUS_KO[result.recv]})` : ''}</b>
              {result.recvReason && <span style={{ color: '#c00' }}> — {result.recvReason}</span>}</div>
            {result.recv === 'RCVD' && (
              <div>최종상태: {result.pending && !result.final
                ? <span style={{ color: '#8a6d00' }}>처리중…</span>
                : <b style={{ color: statusColor(result.final) }}>{result.final}{STATUS_KO[result.final ?? ''] ? ` (${STATUS_KO[result.final!]})` : ''}</b>}
                {result.finalReason && <span style={{ color: '#c00' }}> — {result.finalReason}</span>}
              </div>
            )}
          </div>
        )}
      </section>

      {/* 거래 조회 */}
      <section style={box}>
        <h2 style={{ marginTop: 0 }}>🔎 거래 상태 조회</h2>
        <div style={{ display: 'flex', gap: 8 }}>
          <input value={bmi} onChange={(e) => setBmi(e.target.value)} placeholder="BMI (22자리 거래식별자)"
                 style={{ flex: 1, padding: 8, fontFamily: 'monospace' }} />
          <button onClick={doInquiry} style={{ padding: '8px 16px' }}>조회</button>
        </div>

        {inquiry && (
          <table style={{ borderCollapse: 'collapse', width: '100%', marginTop: 12 }}>
            <thead>
              <tr style={{ borderBottom: '2px solid #ccc', textAlign: 'left' }}>
                <th style={{ ...cell, width: 200 }}>항목(한글)</th><th style={cell}>영문 필드</th><th style={cell}>값</th>
              </tr>
            </thead>
            <tbody>
              {Object.entries(inquiry).filter(([k]) => k !== 'note').map(([k, v]) => (
                <tr key={k}>
                  <td style={{ ...cell, fontWeight: 600 }}>{labels[k] ?? k}</td>
                  <td style={{ ...cell, color: '#888', fontFamily: 'monospace' }}>{k}</td>
                  <td style={cell}>{renderVal(k, v)}</td>
                </tr>
              ))}
            </tbody>
          </table>
        )}

        {rawXml && (
          <details style={{ marginTop: 12 }} open>
            <summary style={{ cursor: 'pointer', fontWeight: 600 }}>📄 원문 ISO20022 pacs.008 전문</summary>
            <pre style={{ background: '#f5f5f5', padding: 12, marginTop: 8, overflowX: 'auto', fontSize: 13 }}>{prettyXml(rawXml)}</pre>
          </details>
        )}
        {inquiry && rawXml === null && <p style={{ color: '#888', marginTop: 8 }}>(원문 전문 없음 — 접수 단계에서 반려되었거나 미저장)</p>}
      </section>

      {/* 계좌 잔액 */}
      <section style={box}>
        <h2 style={{ marginTop: 0 }}>🏦 참가기관 당좌계좌 잔액 <button onClick={loadAccounts} style={{ fontSize: 12 }}>새로고침</button></h2>
        <table style={{ borderCollapse: 'collapse', width: '100%' }}>
          <thead>
            <tr style={{ borderBottom: '2px solid #ccc', textAlign: 'left' }}>
              <th style={cell}>코드</th><th style={cell}>기관</th><th style={{ ...cell, textAlign: 'right' }}>잔액</th>
            </tr>
          </thead>
          <tbody>
            {accounts.map((a) => (
              <tr key={a.code}>
                <td style={{ ...cell, fontFamily: 'monospace' }}>{a.code}</td>
                <td style={cell}>{a.name}</td>
                <td style={{ ...cell, textAlign: 'right', fontFamily: 'monospace' }}>{won(a.balance)}</td>
              </tr>
            ))}
          </tbody>
        </table>
      </section>

      </>)}

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