'use client'

import { useState, useEffect, useRef, useMemo } from 'react'
import { useLocale } from 'next-intl'
import { useAccount, useSignMessage } from 'wagmi'
import { getTrades, getSignalAccuracy } from '@/lib/api'
import type { BotTrade } from '@/types'
import type { SignalAccuracy } from '@/lib/api'
import { getCachedViewEnvelope, getOrCreateViewEnvelope, type SignedEnvelope } from '@/lib/signedRequest'
import { swrFetch } from '@/lib/cache'
import PageHint from '@/components/ui/PageHint'
import InfoTip from '@/components/ui/InfoTip'

type Period = '7d' | '30d' | '90d' | 'All'

function fmtMoney(n: number) {
  if (n == null || isNaN(n)) return '—'
  const abs = Math.abs(n)
  const s = abs.toLocaleString('en-US', { maximumFractionDigits: 0 })
  if (n < 0) return '-$' + s
  if (n > 0) return '+$' + s
  return '$' + s
}

function fmtHold(s: number) {
  if (s < 60) return s + 's'
  const m = Math.floor(s / 60)
  if (m < 60) return m + 'm'
  return Math.floor(m / 60) + 'h ' + (m % 60) + 'm'
}

function fmtAccuracyPct(pct: number | null | undefined) {
  return pct == null || Number.isNaN(pct) ? '—' : `${pct.toFixed(0)}%`
}

function inPeriod(iso: string | null, period: Period) {
  if (!iso) return false   // trades without closed_at are excluded from all windows
  if (period === 'All') return true
  const days = Number.parseInt(period, 10)
  if (Number.isNaN(days)) return true
  const time = new Date(iso).getTime()
  return time >= Date.now() - days * 24 * 60 * 60 * 1000
}

function calcDrawdownPct(trades: BotTrade[]) {
  const ordered = [...trades]
    .filter((t) => t.pnl_usd !== null && t.pnl_usd !== undefined && t.closed_at !== null)
    .sort((a, b) => new Date(a.closed_at!).getTime() - new Date(b.closed_at!).getTime())
  let equity = 0
  let peak = 0
  let maxDrawdownPct = 0

  for (const trade of ordered) {
    equity += trade.pnl_usd as number
    peak = Math.max(peak, equity)
    if (peak > 0) {
      maxDrawdownPct = Math.max(maxDrawdownPct, ((peak - equity) / peak) * 100)
    }
  }

  return maxDrawdownPct
}

export default function AnalyticsPageClient() {
  const locale = useLocale()
  const isZh = false  // i18n shelved — Chinese branches kept as dead code for future revival; see messages/zh.json
  const { address, isConnected } = useAccount()
  const { signMessageAsync } = useSignMessage()
  const [trades, setTrades] = useState<BotTrade[]>([])
  const [accuracy, setAccuracy] = useState<SignalAccuracy | null>(null)
  const [period, setPeriod] = useState<Period>('30d')
  const [tradeMode, setTradeMode] = useState<'live' | 'paper'>('live')
  const [privateLocked, setPrivateLocked] = useState(false)
  const [unlocking, setUnlocking] = useState(false)
  const [unlockErr, setUnlockErr] = useState('')

  const aliveRef = useRef(true)
  useEffect(() => {
    aliveRef.current = true
    return () => { aliveRef.current = false }
  }, [])

  // genRef guards loadAll against stale-closure wallet-switch races.
  // snapAddr === address inside an async function is a stale-closure trap:
  // both refer to the same closed-over value at render time, so the check
  // is always true even when the wallet has changed. genRef is a mutable
  // ref that any closure can read to detect it has been superseded.
  const genRef = useRef(0)
  useEffect(() => { genRef.current++ }, [address])

  // `forcedEnv` (a freshly-minted view_user) lets the in-page Unlock button
  // load private data without a detour through the Settings page. Public
  // signal-accuracy always loads regardless.
  //
  // All displayed stats are computed locally from this single trades list on
  // ONE basis (closed_at, see inPeriod) for EVERY time window — we no longer
  // mix in the backend /performance aggregate for 30d, which used a different
  // basis (it filtered opened_at and capped at 30d) and produced numbers that
  // disagreed with the closed_at-based metric grid on the same screen. Limit
  // raised to 500 so the local computation covers ample history.
  async function loadAll(forcedEnv?: SignedEnvelope) {
    const accuracyPromise = swrFetch('signal-accuracy', 10 * 60_000, () => getSignalAccuracy()).catch(() => null)

    if (!address || !isConnected) {
      setTrades([]); setPrivateLocked(false)
      const a = await accuracyPromise
      if (aliveRef.current) setAccuracy(a)
      return
    }

    const snapAddr = address
    const gen = genRef.current
    const tradesEnv = getCachedViewEnvelope('view_trades', snapAddr)
      ?? (forcedEnv ?? getCachedViewEnvelope('view_user', snapAddr))
    if (aliveRef.current) setPrivateLocked(!tradesEnv)
    try {
      const [t, a] = await Promise.all([
        tradesEnv ? getTrades(snapAddr, tradesEnv, 500, 1).catch(() => []) : Promise.resolve([]),
        accuracyPromise,
      ])
      // Discard if unmounted or if a newer loadAll call has started (wallet/tab change).
      if (aliveRef.current && gen === genRef.current) { setTrades(t); setAccuracy(a) }
    } catch {
      if (aliveRef.current && gen === genRef.current) setTrades([])
    }
  }

  useEffect(() => {
    // B28/B36: clear stale previous-wallet data immediately before the async
    // fetch so the UI never shows another wallet's private P&L.
    setTrades([])
    setPrivateLocked(false)
    // Navigation only uses a cached envelope — never auto-popup the wallet.
    void loadAll()
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [address, isConnected])

  // Mint a view_user envelope (one signature) — unlocks both /performance and
  // /trades (each accepts view_user as fallback) — then reload.
  async function handleUnlock() {
    if (!address) return
    setUnlocking(true)
    setUnlockErr('')
    try {
      const env = await getOrCreateViewEnvelope({
        action: 'view_user', wallet: address, signMessageAsync,
      })
      await loadAll(env)
    } catch (e) {
      const msg = e instanceof Error ? e.message : 'Signature cancelled'
      if (aliveRef.current) setUnlockErr(/reject|denied|cancel/i.test(msg) ? '' : msg)
    } finally {
      if (aliveRef.current) setUnlocking(false)
    }
  }

  // CRITICAL: never mix paper (simulated) and live (real-money) P&L into one
  // number. is_paper comes from the backend (hl_order_id == "paper"). Default
  // to LIVE — this page is the "did the bot make REAL money" view. A Paper/Live
  // toggle appears only when the wallet has both kinds of trades; otherwise we
  // auto-pick whichever set exists so a paper-only user still sees their data
  // (clearly labelled SIMULATED).
  const liveTrades = useMemo(() => trades.filter(t => !t.is_paper), [trades])
  const paperTrades = useMemo(() => trades.filter(t => !!t.is_paper), [trades])
  const hasBoth = liveTrades.length > 0 && paperTrades.length > 0
  const effectiveMode: 'live' | 'paper' =
    hasBoth ? tradeMode : (liveTrades.length > 0 ? 'live' : (paperTrades.length > 0 ? 'paper' : 'live'))
  const modeTrades = effectiveMode === 'paper' ? paperTrades : liveTrades
  const isPaperView = effectiveMode === 'paper'

  const filteredTrades = modeTrades.filter((trade) => inPeriod(trade.closed_at, period))
  const pricedTrades = filteredTrades.filter(
    (t) => t.pnl_usd !== null && t.pnl_usd !== undefined,
  )
  const pnls = pricedTrades.map((t) => t.pnl_usd as number)
  const totalPnl = pnls.reduce((s, p) => s + p, 0)
  const wins = pnls.filter((p) => p > 0).length
  const winRate = pricedTrades.length ? (wins / pricedTrades.length) * 100 : 0
  const bestTrade = pnls.length ? Math.max(...pnls) : 0
  const worstTrade = pnls.length ? Math.min(...pnls) : 0
  const avgTrade = pnls.length ? totalPnl / pnls.length : 0
  const heldTrades = filteredTrades.filter(t => t.hold_seconds !== null)
  const avgHold = heldTrades.length ? heldTrades.reduce((sum, trade) => sum + (trade.hold_seconds ?? 0), 0) / heldTrades.length : 0
  // One basis for every window: derive from the closed_at-filtered trades.
  const maxDrawdown = calcDrawdownPct(filteredTrades)
  const summaryPnl = totalPnl

  const metrics = [
    { k: isZh ? '最大回撤' : 'Max drawdown', v: filteredTrades.length ? maxDrawdown.toFixed(1) + '%' : '—', sub: isZh ? '从高点到低点的最大跌幅' : 'Worst peak-to-trough', down: true,
      tip: 'Largest equity drop from a previous high. Tells you the worst losing streak you would have lived through.' },
    { k: isZh ? '总交易数' : 'Total trades', v: String(filteredTrades.length || '—'), sub: isZh ? '已平仓机器人交易' : 'Closed bot executions',
      tip: 'How many closed positions in this window. Open trades not counted.' },
    { k: isZh ? '平均持仓时间' : 'Avg hold time', v: filteredTrades.length ? fmtHold(Math.round(avgHold)) : '—', sub: isZh ? '按单笔计算' : 'Per trade',
      tip: 'Entry → exit duration averaged across every closed trade.' },
    { k: isZh ? '平均单笔盈亏' : 'Avg trade P&L', v: pnls.length ? fmtMoney(avgTrade) : '—', sub: isZh ? '每笔交易均值' : 'Mean per trade', up: avgTrade > 0,
      tip: 'Total P&L ÷ number of trades. Positive = the strategy has edge per trade.' },
    { k: isZh ? '最佳单笔' : 'Best trade', v: pnls.length ? fmtMoney(bestTrade) : '—', sub: isZh ? '单笔最大盈利' : 'Largest single win', up: true,
      tip: 'Biggest realized gain on one trade in this window.' },
    { k: isZh ? '最差单笔' : 'Worst trade', v: pnls.length ? fmtMoney(worstTrade) : '—', sub: isZh ? '单笔最大亏损' : 'Largest single loss', down: true,
      tip: 'Biggest realized loss on one trade. Should be bounded by your stop-loss setting.' },
  ]

  return (
    <div className="page">
      <div className="page-head">
        <div>
          <h1 className="page-title">{isZh ? '分析面板' : 'Analytics'}</h1>
          <PageHint>
            P&amp;L · win rate · drawdown · signal accuracy — pick a time window on the right.
          </PageHint>
        </div>
        <div style={{ display: 'flex', flexDirection: 'column', gap: 8, alignItems: 'flex-end' }}>
          {hasBoth && (
            <div className="nav-tabs">
              {(['live', 'paper'] as const).map(m => (
                <button key={m}
                  className={`nav-tab ${tradeMode === m ? 'active' : ''}`}
                  onClick={() => setTradeMode(m)}>
                  {m === 'live' ? '💰 Live' : '📝 Paper'}
                </button>
              ))}
            </div>
          )}
          <div className="nav-tabs">
            {(['7d', '30d', '90d', 'All'] as const).map(p => (
              <button key={p} className={`nav-tab ${period === p ? 'active' : ''}`} onClick={() => setPeriod(p)}>{p}</button>
            ))}
          </div>
        </div>
      </div>

      {/* Signal accuracy — always public, shown first so non-connected visitors
          can immediately see proof of signal quality without needing to log in. */}
      {accuracy && (
        <div className="card" style={{ padding: 20, marginBottom: 20 }}>
          <div style={{ display: 'flex', alignItems: 'baseline', gap: 12, marginBottom: 14, flexWrap: 'wrap' }}>
            <div className="tiny">AI Signal Accuracy</div>
            <span style={{ fontSize: 12, color: 'var(--ink-4)' }}>{accuracy.total_directional_signals} directional signals measured</span>
            <span style={{ fontSize: 11, color: 'var(--up)', fontWeight: 600, marginLeft: 'auto' }}>Public · no login needed</span>
          </div>
          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(140px, 1fr))', gap: 8 }}>
            {/* Overall */}
            <div style={{ background: 'var(--surface-2)', borderRadius: 10, padding: '12px 14px' }}>
              <div style={{ fontSize: 11, fontWeight: 600, color: 'var(--ink-3)', marginBottom: 8, textTransform: 'uppercase', letterSpacing: '0.06em' }}>Overall</div>
              {(['m5','m15','m1h'] as const).map(w => {
                const d = accuracy.overall[w]
                const pct = d.accuracy_pct
                const color = pct >= 55 ? 'var(--up)' : pct >= 45 ? 'var(--ink-2)' : 'var(--down)'
                return (
                  <div key={w} className="row between" style={{ marginBottom: 3 }}>
                    <span style={{ fontSize: 11, color: 'var(--ink-3)' }}>{w.replace('m1','1').replace('m','')}</span>
                    <span style={{ fontSize: 13, fontWeight: 700, color, fontVariantNumeric: 'tabular-nums' }}>{pct != null ? `${pct.toFixed(0)}%` : '—'}</span>
                  </div>
                )
              })}
            </div>
            {Object.entries(accuracy.by_signal).map(([sig, data]) => {
              const label = sig === 'buy' ? '🟢 Buy' : sig === 'short' ? '🔴 Short' : '🟡 Sell'
              return (
                <div key={sig} style={{ background: 'var(--surface-2)', borderRadius: 10, padding: '12px 14px' }}>
                  <div style={{ fontSize: 11, fontWeight: 600, color: 'var(--ink-3)', marginBottom: 8, textTransform: 'uppercase', letterSpacing: '0.06em' }}>{label} <span style={{ fontWeight: 400 }}>({data.count})</span></div>
                  {(['m5','m15','m1h'] as const).map(w => {
                    const d = data[w]
                    if (d.checked < 2) return <div key={w} className="row between" style={{ marginBottom: 3 }}><span style={{ fontSize: 11, color: 'var(--ink-3)' }}>{w.replace('m1','1').replace('m','')}</span><span style={{ fontSize: 12, color: 'var(--ink-3)' }}>—</span></div>
                    const pct = d.accuracy_pct
                    const color = pct >= 55 ? 'var(--up)' : pct >= 45 ? 'var(--ink-2)' : 'var(--down)'
                    return (
                      <div key={w} className="row between" style={{ marginBottom: 3 }}>
                        <span style={{ fontSize: 11, color: 'var(--ink-3)' }}>{w.replace('m1','1').replace('m','')}</span>
                        <span style={{ fontSize: 13, fontWeight: 700, color, fontVariantNumeric: 'tabular-nums' }}>{pct.toFixed(0)}%</span>
                      </div>
                    )
                  })}
                </div>
              )
            })}
          </div>
        </div>
      )}

      {isPaperView && filteredTrades.length > 0 && (
        <div className="card" style={{
          padding: '10px 16px', marginBottom: 16, fontSize: 12, fontWeight: 600,
          background: 'var(--amber-soft)',
          borderColor: 'color-mix(in oklab, var(--amber) 30%, var(--line))',
          color: 'var(--amber-ink, var(--ink))',
        }}>
          📝 Showing SIMULATED (paper) performance — these are not real-money results.
          {hasBoth && ' Switch to 💰 Live above for actual P&L.'}
        </div>
      )}

      {privateLocked && (
        <div className="card" style={{ padding: 16, marginBottom: 20 }}>
          <div style={{ fontSize: 13, fontWeight: 600 }}>Your performance data is private.</div>
          <div style={{ fontSize: 12, color: 'var(--ink-3)', marginTop: 4, lineHeight: 1.6 }}>
            Sign once to unlock your P&amp;L and trade history on this device
            (valid a few minutes — no transaction, no gas).
            Signal-accuracy stats below are always public.
          </div>
          <button className="btn amber" style={{ fontSize: 13, padding: '8px 16px', marginTop: 12 }}
            disabled={unlocking} onClick={handleUnlock}>
            {unlocking ? 'Waiting for signature…' : 'Unlock performance'}
          </button>
          {unlockErr && (
            <div style={{ fontSize: 11, color: 'var(--down)', marginTop: 8 }}>● {unlockErr}</div>
          )}
        </div>
      )}

      <div className="card" style={{ padding: 28, marginBottom: 20 }}>
        <div className="row between" style={{ alignItems: 'flex-start', marginBottom: 20 }}>
          <div>
            <div className="tiny">{isZh ? '表现' : 'Performance'} · {period}</div>
            <div className="hero-value mono" style={{ marginTop: 6, fontSize: 40 }}>
              {filteredTrades.length ? fmtMoney(summaryPnl) : '—'}
            </div>
            <div className="row gap-s" style={{ marginTop: 8 }}>
              <span className={`chip ${winRate >= 50 ? 'up' : 'down'}`}>{winRate.toFixed(1)}% {isZh ? '胜率' : 'win rate'}</span>
              <span className="chip">{isZh ? `${filteredTrades.length} 笔交易` : `${filteredTrades.length} trades`}</span>
            </div>
          </div>
        </div>
      </div>

      <div className="metric-grid" style={{ marginBottom: 20 }}>
        {metrics.map(m => (
          <div key={m.k} className="card" style={{ padding: 20, overflow: 'visible' }}>
            <div className="tiny" style={{ marginBottom: 8, display: 'flex', alignItems: 'center' }}>
              {m.k}
              {m.tip && <InfoTip text={m.tip} placement="top" width={240} />}
            </div>
            <div className={`mono ${m.up ? 'delta up' : m.down ? 'delta down' : ''}`} style={{ fontSize: 24, fontWeight: 500, letterSpacing: '-0.01em' }}>{m.v}</div>
            <div style={{ fontSize: 12, color: 'var(--ink-3)', marginTop: 4 }}>{m.sub}</div>
          </div>
        ))}
      </div>

      {/* Signal accuracy is now shown at the top of the page (public, no login needed).
          Removed duplicate block here to avoid showing the same data twice. */}

      {!filteredTrades.length && (
        <div className="card" style={{ padding: 60, textAlign: 'center', color: 'var(--ink-3)' }}>
          <p style={{ fontSize: 14 }}>
            {!isConnected || !address
              ? (isZh ? '连接钱包以加载你的分析数据。' : 'Connect your wallet to load your analytics.')
              : privateLocked
              ? (isZh ? '签名解锁后可查看你的真实业绩和交易历史。' : 'Sign once above to unlock your personal P&L and trade history.')
              : trades.length
              ? (isZh ? `${period} 时间窗内还没有已平仓交易。` : `No trades closed in the ${period} window yet.`)
              : (isZh ? '还没有交易数据。机器人开始执行后，这里会自动出现统计。' : 'No trade data yet. The bot will populate analytics once it starts executing.')}
          </p>
        </div>
      )}
    </div>
  )
}
