// wallet.jsx — Phantom + Solflare wallet detection, connect, disconnect, balance
// Real provider detection via window.solana / window.solflare.
// We don't make on-chain payments — bets are mock against a local balance —
// but connection / sign / address / explorer-link are all real.

const { useState: useStateW, useEffect: useEffectW, useCallback: useCallbackW, useRef: useRefW } = React;

function detectWallets() {
  const list = [];
  if (typeof window === 'undefined') return list;
  if (window.solana?.isPhantom) list.push({ id:'phantom', name:'Phantom', provider: window.solana });
  if (window.solflare?.isSolflare) list.push({ id:'solflare', name:'Solflare', provider: window.solflare });
  // Some wallets register under window.phantom?.solana
  if (!list.find(w=>w.id==='phantom') && window.phantom?.solana?.isPhantom) {
    list.push({ id:'phantom', name:'Phantom', provider: window.phantom.solana });
  }
  return list;
}

function shortAddr(a) {
  if (!a) return '';
  return a.slice(0,4) + '…' + a.slice(-4);
}

function useWallet() {
  const [available, setAvailable] = useStateW(detectWallets());
  const [connecting, setConnecting] = useStateW(false);
  const [walletId, setWalletId] = useStateW(null);   // 'phantom' | 'solflare' | null
  const [address, setAddress] = useStateW(null);
  const [error, setError] = useStateW(null);
  // Mock playable balance — in a real app you'd fetch SPL/SOL via RPC; for the prototype
  // we keep a synthetic bag that bets actually move.
  const [realBalance, setRealBalance] = useStateW({ SOL: 12.847, USDC: 250.50, USDT: 180.00 });
  // Separate "play for fun" bag — wallet-free, resets to default on every page load.
  const [funBalance, setFunBalance] = useStateW({ SOL: 10, USDC: 100, USDT: 100 });
  const [funMode, setFunMode] = useStateW(() => {
    // Default ON for first-time visitors so games are immediately playable
    // without a wallet. User can flip to real bag any time.
    try {
      const v = localStorage.getItem('run!funMode');
      if (v === '0') return false;
      return true;
    } catch { return true; }
  });
  useEffectW(() => { try { localStorage.setItem('run!funMode', funMode?'1':'0'); } catch {} }, [funMode]);
  const balance = funMode ? funBalance : realBalance;
  const [activeCoin, setActiveCoin] = useStateW('SOL');
  const [username, setUsername] = useStateW(() => {
    try { return localStorage.getItem('run!username') || 'anon_degen'; } catch { return 'anon_degen'; }
  });
  // History resets on every page load — stats start fresh.
  const [history, setHistory] = useStateW([]);

  const setUsernamePersist = useCallbackW((name) => {
    const clean = (name||'').trim().slice(0,18) || 'anon_degen';
    setUsername(clean);
    try { localStorage.setItem('run!username', clean); } catch {}
  }, []);

  const logPlay = useCallbackW((entry) => {
    // entry: { game, side?, bet, payout, win, coin, hash?, nonce? }
    setHistory(h => [{ ...entry, t: Date.now() }, ...h].slice(0, 200));
  }, []);

  const clearHistory = useCallbackW(() => setHistory([]), []);

  // Re-scan when window finishes loading wallet extensions
  useEffectW(() => {
    const tick = () => setAvailable(detectWallets());
    tick();
    const id = setInterval(tick, 1500);
    // stop polling after 6s — should have enumerated by then
    setTimeout(()=>clearInterval(id), 6000);
    return () => clearInterval(id);
  }, []);

  const connect = useCallbackW(async (id) => {
    setConnecting(true); setError(null);
    try {
      const w = detectWallets().find(x=>x.id===id);
      if (!w) {
        // Wallet not installed — open install page
        const url = id==='phantom' ? 'https://phantom.app/' : 'https://solflare.com/';
        window.open(url, '_blank', 'noopener');
        setError(`${id} not installed — opened install page.`);
        setConnecting(false);
        return;
      }
      const resp = await w.provider.connect();
      const pk = resp?.publicKey?.toString?.() || w.provider.publicKey?.toString?.();
      setWalletId(id);
      setAddress(pk);
      // Try to remember
      try { localStorage.setItem('run!wallet', id); } catch {}
    } catch (e) {
      setError(e?.message || 'Connection rejected.');
    } finally {
      setConnecting(false);
    }
  }, []);

  const disconnect = useCallbackW(async () => {
    try {
      const w = detectWallets().find(x=>x.id===walletId);
      await w?.provider?.disconnect?.();
    } catch {}
    setWalletId(null); setAddress(null);
    try { localStorage.removeItem('run!wallet'); } catch {}
  }, [walletId]);

  // Auto-reconnect on load if previously connected
  useEffectW(() => {
    let cancelled = false;
    const id = (() => { try { return localStorage.getItem('run!wallet'); } catch { return null; } })();
    if (!id) return;
    // Wait briefly for extensions to inject
    const t = setTimeout(async () => {
      const w = detectWallets().find(x=>x.id===id);
      if (!w) return;
      try {
        const resp = await w.provider.connect({ onlyIfTrusted: true });
        if (cancelled) return;
        const pk = resp?.publicKey?.toString?.() || w.provider.publicKey?.toString?.();
        if (pk) { setWalletId(id); setAddress(pk); }
      } catch {}
    }, 600);
    return () => { cancelled = true; clearTimeout(t); };
  }, []);

  // Sign a message — useful for proving ownership (we expose this on the fairness page)
  const signMessage = useCallbackW(async (msg) => {
    const w = detectWallets().find(x=>x.id===walletId);
    if (!w) throw new Error('Not connected');
    const enc = new TextEncoder().encode(msg);
    const out = await w.provider.signMessage(enc, 'utf8');
    // Phantom returns { signature: Uint8Array, publicKey }, Solflare similar
    const sig = out?.signature || out;
    return Array.from(new Uint8Array(sig)).map(b=>b.toString(16).padStart(2,'0')).join('');
  }, [walletId]);

  // Bet helpers — debit / credit whichever bag is active (real or fun).
  // debit returns true if the bag had enough, false otherwise (audit HIGH-6).
  // Callers MUST honour the return value — when false, the bag is unchanged.
  //
  // Optional `roundId` (any non-empty string) makes the operation idempotent
  // (audit MED-12): a debit or credit with the same id is silently ignored,
  // even if a same-tick double-click somehow gets past every other guard.
  // The seen-id set is capped at 200 entries (FIFO eviction) — bounded memory.
  const seenOpsRef = useRefW({ order: [], set: new Set() });
  const SEEN_OPS_CAP = 200;
  function markSeen(id) {
    if (!id) return false; // un-keyed op: always proceed
    const s = seenOpsRef.current;
    if (s.set.has(id)) return true;
    s.set.add(id); s.order.push(id);
    if (s.order.length > SEEN_OPS_CAP) {
      const evicted = s.order.shift();
      s.set.delete(evicted);
    }
    return false;
  }

  const debit = useCallbackW((coin, amt, roundId) => {
    if (markSeen(roundId)) return true; // dedup: pretend it succeeded
    const bag = (funMode ? funBalance : realBalance)[coin] || 0;
    if (bag + 1e-9 < amt) return false;
    const setter = funMode ? setFunBalance : setRealBalance;
    setter(b => {
      if (b[coin] + 1e-9 < amt) return b;
      return { ...b, [coin]: +(b[coin] - amt).toFixed(6) };
    });
    return true;
  }, [funMode, funBalance, realBalance]);
  const credit = useCallbackW((coin, amt, roundId) => {
    if (markSeen(roundId)) return; // dedup
    const setter = funMode ? setFunBalance : setRealBalance;
    setter(b => ({ ...b, [coin]: +(b[coin] + amt).toFixed(6) }));
  }, [funMode]);

  const toggleFunMode = useCallbackW(() => setFunMode(v => !v), []);
  const resetFun = useCallbackW(() => setFunBalance({ SOL: 10, USDC: 100, USDT: 100 }), []);

  return {
    available, connecting, walletId, address, error, connect, disconnect, signMessage,
    balance, realBalance, funBalance, activeCoin, setActiveCoin, debit, credit,
    funMode, toggleFunMode, resetFun,
    username, setUsername: setUsernamePersist,
    history, logPlay, clearHistory,
    connected: !!address,
    canPlay: !!address || funMode,
  };
}

// ─── Connect modal ───────────────────────────────────────────────
function WalletModal({ wallet, onClose }) {
  const M = window.MEMEColors;
  return (
    <div style={{position:'fixed', inset:0, background:'rgba(0,0,0,0.85)', zIndex:1000, display:'flex', alignItems:'center', justifyContent:'center'}}>
      <div style={{background:M.bg, border:`3px solid ${M.green}`, padding:'22px 26px', maxWidth:420, width:'92%', boxShadow:`8px 8px 0 ${M.hot}`, position:'relative'}}>
        <div style={{position:'absolute', top:-14, left:14, background:M.bg, padding:'0 8px', color:M.green, fontSize:16}}>┤ connect.exe ├</div>
        <button onClick={onClose} style={{position:'absolute', top:-14, right:14, background:M.bg, color:M.hot, border:`1px solid ${M.hot}`, fontFamily:'inherit', fontSize:16, width:24, height:24, cursor:'pointer'}}>×</button>
        <div style={{fontSize:24, color:M.yellow, marginBottom:6, lineHeight:1}}>$ pick wallet</div>
        <div style={{fontSize:16, color:M.ink2, marginBottom:18, lineHeight:1.4}}>connecting your wallet lets you sign messages, verify proofs, and prove the bag is yours.</div>

        {[
          { id:'phantom', name:'Phantom', tag:'most popular sol wallet', logo:<PhantomLogo/> },
          { id:'solflare', name:'Solflare', tag:'lightweight + hardware support', logo:<SolflareLogo/> },
        ].map(w => {
          const installed = wallet.available.find(a=>a.id===w.id);
          return (
            <button key={w.id} onClick={()=>{ wallet.connect(w.id); }} disabled={wallet.connecting} style={{
              width:'100%', display:'flex', alignItems:'center', gap:14, padding:'12px 14px', marginBottom:10,
              background:M.panel, border:`2px solid ${installed?M.green:M.ink2}`, color:M.ink, fontFamily:'inherit',
              cursor:wallet.connecting?'wait':'pointer', textAlign:'left', boxShadow:installed?`4px 4px 0 ${M.green}`:`4px 4px 0 ${M.ink2}`,
            }}>
              {w.logo}
              <div style={{flex:1}}>
                <div style={{fontSize:22, color:installed?M.green:M.ink, fontWeight:700, lineHeight:1}}>{w.name}</div>
                <div style={{fontSize:14, color:M.ink2, marginTop:2}}>{w.tag}</div>
              </div>
              <div style={{fontSize:14, color:installed?M.green:M.yellow}}>{installed ? '[connect]' : '[install]'}</div>
            </button>
          );
        })}

        {wallet.error && <div style={{marginTop:10, color:M.red, fontSize:14, padding:'8px 12px', border:`1px dashed ${M.red}`}}>{'>'} ERROR: {wallet.error}</div>}
        <div style={{marginTop:12, fontSize:14, color:M.ink2}}>by connecting you agree to lose money to a smart contract you cannot read. cool? cool.</div>
      </div>
    </div>
  );
}

function PhantomLogo() {
  return (
    <svg width="40" height="40" viewBox="0 0 40 40" fill="none">
      <rect width="40" height="40" rx="6" fill="#ab9ff2"/>
      <path d="M30 20.5c0 5.8-5.5 12-12 12-3 0-5.5-1.2-6-1.2-.4 0 .5-2.4 1.4-3.6 1-1.4 1.6-2 3.4-2.6 1.5-.5 2.6-.4 3.4 0 1.2.6 2 1.6 2.4 1.6.5 0-.4-1-.4-2 0-3.4 2.4-6 5.4-6 1.4 0 2.4.6 2.4 1.8z" fill="#fff"/>
      <circle cx="22" cy="18" r="1.2" fill="#1a1240"/>
      <circle cx="27" cy="18" r="1.2" fill="#1a1240"/>
    </svg>
  );
}
function SolflareLogo() {
  return (
    <svg width="40" height="40" viewBox="0 0 40 40" fill="none">
      <rect width="40" height="40" rx="6" fill="#fc8e3b"/>
      <path d="M20 7l3 6 7 1-5 5 1 7-6-3-6 3 1-7-5-5 7-1z" fill="#fff"/>
    </svg>
  );
}

Object.assign(window, { useWallet, detectWallets, shortAddr, WalletModal });
