/* app-shield.jsx — /app surface
 *
 * Wireframe (see screenshot 2026-06-08):
 *   ┌──────────────────────┬──────────────────────────┐
 *   │ [Shield] [Unshield]  │  Supported │ Private DeFi │
 *   │  Token   [select  ▾] │  tokens    │              │
 *   │  Amount  [input    ] │  list      │  Vesu top 5  │
 *   │                      │            │  Endur STRK  │
 *   │  [ CONNECT WALLET  ] │            │  BTC staking │
 *   └──────────────────────┴──────────────────────────┘
 *
 * Data sources:
 *   - Supported tokens → local dashboard API /agg/tvl
 *     (every token with at least one deposit, AVNU logoUri + symbol + name)
 *   - Private DeFi → live fetches:
 *       * Vesu: https://api.vesu.xyz/markets (CORS *)
 *       * Endur STRK: https://app.endur.fi/api/stats (CORS *)
 *       * Endur BTC: endpoint not yet confirmed — row shows TBD until wired
 */

const { useEffect, useState } = React;

const API_BASE = 'http://localhost:8787'
const VESU_MARKETS_URL = 'https://api.vesu.xyz/markets'
const ENDUR_STRK_URL = 'https://app.endur.fi/api/stats'

/* ────────────────────────────────────────────────────────────────
 * Top-level layout
 * ──────────────────────────────────────────────────────────────── */

function ShieldApp() {
  return (
    <main style={{ minHeight: '100vh', padding: '110px var(--gut) 60px' }}>
      <div className="shield-grid">
        <ShieldForm />
        <InfoPanel />
      </div>
      <style>{styles}</style>
    </main>
  )
}

/* ────────────────────────────────────────────────────────────────
 * Left — Shield / Unshield form
 * ──────────────────────────────────────────────────────────────── */

function ShieldForm() {
  const [tab, setTab] = useState('shield') // 'shield' | 'unshield'
  const { tokens } = useSupportedTokens()
  const [tokenAddr, setTokenAddr] = useState('')
  const [amount, setAmount] = useState('')

  // pick the first token by default once the list loads
  useEffect(() => {
    if (!tokenAddr && tokens.length > 0) setTokenAddr(tokens[0].address)
  }, [tokens, tokenAddr])

  return (
    <section className="shield-card">
      <div className="shield-tabs" role="tablist">
        <button
          role="tab"
          aria-selected={tab === 'shield'}
          className={`shield-tab ${tab === 'shield' ? 'is-active' : ''}`}
          onClick={() => setTab('shield')}
        >Shield</button>
        <button
          role="tab"
          aria-selected={tab === 'unshield'}
          className={`shield-tab ${tab === 'unshield' ? 'is-active' : ''}`}
          onClick={() => setTab('unshield')}
        >Unshield</button>
      </div>

      <div className="shield-body">
        <label className="field-label" htmlFor="shield-token">Token</label>
        <div className="field-wrap">
          <select
            id="shield-token"
            className="field-input"
            value={tokenAddr}
            onChange={(e) => setTokenAddr(e.target.value)}
          >
            {tokens.length === 0 && <option value="">Loading…</option>}
            {tokens.map((t) => (
              <option key={t.address} value={t.address}>
                {t.symbol} — {t.name}
              </option>
            ))}
          </select>
          <span className="field-caret" aria-hidden="true">▾</span>
        </div>

        <label className="field-label" htmlFor="shield-amount">Amount</label>
        <input
          id="shield-amount"
          className="field-input"
          type="text"
          inputMode="decimal"
          placeholder="0.00"
          value={amount}
          onChange={(e) => setAmount(e.target.value)}
        />

        {/* Wallet integration stripped from this branch — the button
            stays as a static placeholder so the form layout is
            unchanged. Re-wire on the next branch that owns wallet UX. */}
        <button
          type="button"
          className="shield-connect"
          disabled
        >
          Connect Wallet
        </button>
      </div>
    </section>
  )
}

/* ────────────────────────────────────────────────────────────────
 * Right — Supported tokens + Private DeFi
 * ──────────────────────────────────────────────────────────────── */

function InfoPanel() {
  return (
    <section className="info-card">
      <div className="info-col info-col--left">
        <h2 className="info-h">Supported tokens</h2>
        <SupportedTokensList />
      </div>
      <div className="info-col">
        <h2 className="info-h">Private DeFi</h2>
        <PrivateDefiList />
      </div>
    </section>
  )
}

function SupportedTokensList() {
  const { tokens, loading, error } = useSupportedTokens()
  if (loading && tokens.length === 0) return <p className="info-muted">Loading…</p>
  if (error) return <p className="info-muted">Couldn’t load supported tokens.</p>
  if (tokens.length === 0) return <p className="info-muted">No tokens shielded yet.</p>
  return (
    <ul className="info-list">
      {tokens.map((t) => (
        <li key={t.address} className="info-row">
          <span className="info-row__left">
            <TokenIcon src={t.logoUri} symbol={t.symbol} />
            <span className="info-row__symbol">{t.symbol}</span>
            <span className="info-row__name">{t.name}</span>
          </span>
        </li>
      ))}
    </ul>
  )
}

function PrivateDefiList() {
  const { yields, loading, error } = usePrivateDefiYields()
  if (loading && yields.length === 0) return <p className="info-muted">Loading…</p>
  if (error && yields.length === 0) return <p className="info-muted">Couldn’t load yields.</p>
  return (
    <ul className="info-list">
      {yields.map((y) => (
        <li key={y.id} className="info-row">
          <span className="info-row__left">
            <TokenIcon src={y.logoUri} symbol={y.symbol} />
            <span className="info-row__symbol">{y.symbol}</span>
            <span className="info-row__on">on {y.venue}</span>
            {y.note && <span className="info-row__note">{y.note}</span>}
          </span>
          <span className="info-row__yield">{y.apyLabel}</span>
        </li>
      ))}
    </ul>
  )
}

function TokenIcon({ src, symbol }) {
  if (src) {
    return (
      <img
        className="info-row__icon"
        src={src}
        alt={`${symbol} logo`}
        loading="lazy"
        onError={(e) => { e.currentTarget.style.display = 'none' }}
      />
    )
  }
  // fallback monogram
  return (
    <span className="info-row__icon info-row__icon--mono" aria-hidden="true">
      {symbol?.slice(0, 1) ?? '?'}
    </span>
  )
}

/* ────────────────────────────────────────────────────────────────
 * Data hooks
 * ──────────────────────────────────────────────────────────────── */

/** Tokens currently in the privacy pool — from local dashboard API. */
function useSupportedTokens() {
  const [state, setState] = useState({ tokens: [], loading: true, error: null })
  useEffect(() => {
    let cancelled = false
    fetch(`${API_BASE}/agg/tvl`)
      .then((r) => { if (!r.ok) throw new Error(`${r.status}`); return r.json() })
      .then((d) => {
        if (cancelled) return
        // Show tokens we've ever seen a deposit for. /agg/tvl already orders
        // by USD value desc, so big-volume tokens float to the top.
        const tokens = (d.perToken || [])
          .filter((t) => (t.depositCount ?? 0) > 0)
          .map((t) => ({
            address: t.address,
            symbol: t.symbol,
            name: nameForSymbol(t.symbol),
            logoUri: t.logoUri,
          }))
        setState({ tokens, loading: false, error: null })
      })
      .catch((e) => { if (!cancelled) setState((s) => ({ ...s, loading: false, error: e })) })
    return () => { cancelled = true }
  }, [])
  return state
}

/** Pretty name fallback when AVNU's name field isn't on the row. */
function nameForSymbol(symbol) {
  const map = {
    STRK: 'Starknet', ETH: 'Ether', USDC: 'USD Coin', USDT: 'Tether',
    WBTC: 'Wrapped Bitcoin', strkBTC: 'Starknet BTC', xstrkBTC: 'Endur xBTC',
    xSTRK: 'Endur xSTRK', vSTRK: 'Vesu STRK', vUSDC: 'Vesu USDC',
    vUSDT: 'Vesu USDT', vETH: 'Vesu ETH', xWBTC: 'Endur xWBTC',
    EKUBO: 'Ekubo', DAI: 'Dai', LBTC: 'Lombard BTC',
  }
  return map[symbol] ?? symbol
}

/** Top 5 Vesu yields + Endur STRK staking + Endur BTC staking row. */
function usePrivateDefiYields() {
  const [state, setState] = useState({ yields: [], loading: true, error: null })

  useEffect(() => {
    let cancelled = false

    async function load() {
      try {
        const [vesuRes, endurStrkRes] = await Promise.allSettled([
          fetch(VESU_MARKETS_URL).then((r) => r.json()),
          fetch(ENDUR_STRK_URL).then((r) => r.json()),
        ])

        const out = []

        // Vesu: top 5 by supplyApy across non-deprecated markets.
        if (vesuRes.status === 'fulfilled') {
          const items = (vesuRes.value?.data ?? [])
            .filter((m) => !m?.pool?.isDeprecated)
            .map((m) => {
              const apy = decimalFromValueObj(m?.stats?.supplyApy)
              return apy != null
                ? {
                    id: `vesu-${m.pool.id}-${m.address}`,
                    symbol: m.symbol,
                    venue: 'Vesu',
                    note: m?.pool?.name,
                    apy,
                    apyLabel: formatPct(apy),
                    logoUri: vesuLogo(m.symbol),
                  }
                : null
            })
            .filter(Boolean)
            .sort((a, b) => b.apy - a.apy)
            .slice(0, 5)
          out.push(...items)
        }

        // Endur STRK staking.
        if (endurStrkRes.status === 'fulfilled' && endurStrkRes.value?.apy != null) {
          out.push({
            id: 'endur-strk',
            symbol: 'STRK',
            venue: 'Endur',
            note: 'STRK staking',
            apy: endurStrkRes.value.apy,
            apyLabel: endurStrkRes.value.apyInPercentage ?? formatPct(endurStrkRes.value.apy),
            logoUri: 'https://assets.coingecko.com/coins/images/26433/small/starknet.png',
          })
        }

        // Endur BTC staking — public endpoint not confirmed yet. Placeholder
        // so the row renders; APY label resolves once we know the URL.
        out.push({
          id: 'endur-btc',
          symbol: 'strkBTC',
          venue: 'Endur',
          note: 'BTC staking',
          apy: null,
          apyLabel: '—',
          logoUri: 'https://raw.githubusercontent.com/avnu-labs/tokens/refs/heads/main/images/strkBTC.svg',
        })

        if (!cancelled) setState({ yields: out, loading: false, error: null })
      } catch (e) {
        if (!cancelled) setState((s) => ({ ...s, loading: false, error: e }))
      }
    }

    load()
    return () => { cancelled = true }
  }, [])

  return state
}

function decimalFromValueObj(v) {
  if (!v || typeof v !== 'object') return null
  try {
    const value = BigInt(v.value)
    const decimals = Number(v.decimals ?? 18)
    // convert through Number — fine for sub-1.0 yield magnitudes
    return Number(value) / Math.pow(10, decimals)
  } catch {
    return null
  }
}

function formatPct(d) {
  return `${(d * 100).toFixed(2)}%`
}

/** Vesu's market rows don't carry a logo URI, but every collateral symbol
 *  lines up with AVNU's tokens repo so we can synthesise one. */
function vesuLogo(symbol) {
  const known = {
    STRK: 'https://assets.coingecko.com/coins/images/26433/small/starknet.png',
    USDC: 'https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48/logo.png',
    'USDC.e': 'https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48/logo.png',
    USDT: 'https://assets.coingecko.com/coins/images/325/small/Tether.png',
    ETH: 'https://imagedelivery.net/0xPAQaDtnQhBs8IzYRIlNg/e07829b7-0382-4e03-7ecd-a478c5aa9f00/logo',
    WBTC: 'https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599/logo.png',
    tBTC: 'https://raw.githubusercontent.com/avnu-labs/tokens/refs/heads/main/images/tBTC.svg',
    LBTC: 'https://assets.coingecko.com/coins/images/39969/standard/LBTC_Logo.png',
    strkBTC: 'https://raw.githubusercontent.com/avnu-labs/tokens/refs/heads/main/images/strkBTC.svg',
    xstrkBTC: 'https://raw.githubusercontent.com/avnu-labs/tokens/refs/heads/main/images/xstrkBTC.svg',
  }
  return known[symbol] ?? null
}

/* ────────────────────────────────────────────────────────────────
 * Styles
 * ──────────────────────────────────────────────────────────────── */

const styles = `
.shield-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr);
  gap: 24px;
  max-width: 1240px;
  margin: 0 auto;
}
@media (max-width: 980px) {
  .shield-grid { grid-template-columns: 1fr; }
}

/* ── shared card chrome ── */
.shield-card,
.info-card {
  background: rgba(20,20,20,0.55);
  border: 1px solid var(--line);
  border-radius: 6px;
  box-shadow: 0 0 0 1px rgba(0,0,0,0.4) inset;
}

/* ── shield form ── */
.shield-tabs {
  display: grid;
  grid-template-columns: 1fr 1fr;
  border-bottom: 1px solid var(--line);
}
.shield-tab {
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--dim);
  background: transparent;
  border: 0;
  padding: 18px 22px;
  cursor: pointer;
  transition: color .18s ease, background .18s ease;
  border-bottom: 2px solid transparent;
}
.shield-tab + .shield-tab {
  border-left: 1px solid var(--line);
}
.shield-tab:hover { color: var(--text); }
.shield-tab.is-active {
  color: var(--text);
  background: rgba(0,0,0,0.25);
  border-bottom-color: var(--orange);
}

.shield-body { padding: 26px 26px 30px; }
.field-label {
  display: block;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--dim);
  margin: 14px 0 8px;
}
.field-label:first-child { margin-top: 0; }
.field-wrap { position: relative; }
.field-input {
  width: 100%;
  font-family: var(--mono);
  font-size: 14px;
  color: var(--text);
  background: rgba(0,0,0,0.35);
  border: 1px solid var(--line);
  border-radius: 4px;
  padding: 14px 14px;
  appearance: none;
  outline: none;
  transition: border-color .18s ease, box-shadow .18s ease;
}
.field-input:focus {
  border-color: var(--orange);
  box-shadow: 0 0 0 1px var(--orange) inset;
}
select.field-input { padding-right: 36px; }
.field-caret {
  position: absolute; right: 14px; top: 50%;
  transform: translateY(-50%);
  font-size: 14px; color: var(--dim);
  pointer-events: none;
}
.shield-connect {
  margin-top: 26px;
  width: 100%;
  height: 52px;
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--text);
  background: transparent;
  border: 1px solid var(--line);
  border-radius: 4px;
  cursor: pointer;
  transition: border-color .18s ease, color .18s ease, background .18s ease, box-shadow .18s ease;
}
.shield-connect:hover:not(:disabled) {
  border-color: var(--orange);
  color: var(--orange);
  box-shadow: 0 0 16px rgba(197,52,0,0.18);
}
.shield-connect:disabled { opacity: 0.6; cursor: wait; }

/* ── info panel ── */
.info-card {
  display: grid;
  grid-template-columns: 1fr 1px 1fr;
  gap: 0;
  padding: 0;
}
.info-col {
  padding: 22px 22px 26px;
  min-width: 0;
}
.info-col--left {
  border-right: 1px solid var(--line);
}
@media (max-width: 720px) {
  .info-card { grid-template-columns: 1fr; }
  .info-col--left { border-right: 0; border-bottom: 1px solid var(--line); }
}
.info-h {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--dim);
  margin: 0 0 14px;
  font-weight: 500;
}
.info-list {
  list-style: none;
  margin: 0; padding: 0;
  display: flex; flex-direction: column;
  gap: 2px;
}
.info-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 10px 6px;
  border-radius: 4px;
  transition: background .15s ease;
}
.info-row:hover { background: rgba(255,255,255,0.025); }
.info-row__left {
  display: flex; align-items: center;
  gap: 10px;
  min-width: 0;
}
.info-row__icon {
  width: 22px; height: 22px;
  border-radius: 50%;
  background: var(--bg-2);
  object-fit: cover;
  flex: 0 0 auto;
}
.info-row__icon--mono {
  display: inline-flex; align-items: center; justify-content: center;
  font-family: var(--mono); font-size: 10px;
  color: var(--dim);
  border: 1px solid var(--line);
}
.info-row__symbol {
  font-family: var(--mono);
  font-size: 13px;
  color: var(--text);
  letter-spacing: 0.04em;
}
.info-row__name {
  font-family: var(--mono);
  font-size: 11px;
  color: var(--dim);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.info-row__on {
  font-family: var(--mono);
  font-size: 11px;
  color: var(--dim);
  letter-spacing: 0.06em;
}
.info-row__note {
  font-family: var(--mono);
  font-size: 10px;
  color: var(--dim);
  opacity: 0.7;
  margin-left: 4px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.info-row__yield {
  font-family: var(--mono);
  font-size: 13px;
  color: var(--orange);
  font-variant-numeric: tabular-nums;
  flex: 0 0 auto;
}
.info-muted {
  font-family: var(--mono);
  font-size: 12px;
  color: var(--dim);
  margin: 4px 0 0;
}
`

// No exports — loaded via <script type="text/babel"> so ShieldApp is a
// window global, referenced by app.jsx's pathname switch.
