/* ============================================================
   basket.fun — Copy / Buy flow + Order status (state machine)
   ============================================================ */

function AmountField({ value, setValue, min, max, balance, balanceLabel = 'Balance' }) {
  const tooLow = value && +value < min;
  const tooHigh = +value > max;
  const insufficient = value && +value > balance;
  return (
    <div>
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 8 }}>
        <label style={{ fontSize: 13, fontWeight: 600, color: 'var(--text-2)' }}>Amount to invest</label>
        <span style={{ fontSize: 12, color: 'var(--text-3)' }}>{balanceLabel}: <span className="tnum" style={{ color: 'var(--text-2)' }}>{fmtUsd(balance)}</span></span>
      </div>
      <div style={{
        display: 'flex', alignItems: 'center', gap: 10, padding: '14px 16px', borderRadius: 14,
        background: 'var(--bg-2)', border: '1px solid ' + (tooLow || tooHigh || insufficient ? 'rgba(255,107,107,0.5)' : 'var(--line-2)'),
      }}>
        <span style={{ fontSize: 26, fontWeight: 700, color: value ? 'var(--text)' : 'var(--text-3)' }}>$</span>
        <input type="number" value={value} onChange={e => setValue(e.target.value)} placeholder="0"
          style={{ flex: 1, border: 'none', background: 'transparent', color: 'var(--text)', fontFamily: 'var(--font)', fontSize: 26, fontWeight: 700, outline: 'none', width: '100%' }} />
        <div style={{ display: 'flex', alignItems: 'center', gap: 7, padding: '6px 10px', borderRadius: 99, background: 'var(--surface-2)', border: '1px solid var(--line)' }}>
          <div style={{ width: 20, height: 20, borderRadius: 99, background: 'linear-gradient(135deg,#2775CA,#2775ca)', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 10, fontWeight: 800, color: '#fff' }}>$</div>
          <span style={{ fontSize: 14, fontWeight: 700 }}>USDC</span>
        </div>
      </div>
      <div style={{ display: 'flex', gap: 8, marginTop: 10 }}>
        {[1, 10, 100, 500].map(q => (
          <button key={q} onClick={() => setValue(String(q))} style={{ flex: 1, padding: '8px 0', borderRadius: 9, border: '1px solid var(--line)', background: +value === q ? 'var(--surface-2)' : 'var(--surface)', color: 'var(--text-2)', cursor: 'pointer', fontFamily: 'var(--font)', fontSize: 13, fontWeight: 600 }}>${q.toLocaleString()}</button>
        ))}
        <button onClick={() => setValue(String(max))} style={{ flex: 1, padding: '8px 0', borderRadius: 9, border: '1px solid var(--line)', background: 'var(--surface)', color: 'var(--accent-ink)', cursor: 'pointer', fontFamily: 'var(--font)', fontSize: 13, fontWeight: 700 }}>MAX</button>
      </div>
      {tooLow && <div style={{ fontSize: 12, color: 'var(--danger)', marginTop: 8 }}>Minimum is {fmtUsd(min, 0)}.</div>}
      {tooHigh && <div style={{ fontSize: 12, color: 'var(--danger)', marginTop: 8 }}>Maximum per copy is {fmtUsd(max, 0)}.</div>}
      {insufficient && !tooHigh && <div style={{ fontSize: 12, color: 'var(--danger)', marginTop: 8 }}>Available {balanceLabel.toLowerCase()} is {fmtUsd(balance)}.</div>}
    </div>
  );
}

function Row({ label, value, sub, strong, accent, badge }) {
  return (
    <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '9px 0' }}>
      <span style={{ fontSize: 13.5, color: strong ? 'var(--text)' : 'var(--text-2)', fontWeight: strong ? 700 : 500, display: 'inline-flex', alignItems: 'center', gap: 8 }}>{label}{badge}</span>
      <span className="tnum" style={{ fontSize: strong ? 16 : 13.5, fontWeight: strong ? 700 : 600, color: accent ? 'var(--accent-ink)' : 'var(--text)' }}>{value}{sub && <span style={{ fontSize: 11, color: 'var(--text-3)', fontWeight: 500 }}> {sub}</span>}</span>
    </div>
  );
}

/* ---------------- Execution / Order status ---------------- */
function ExecStep({ step, state }) {
  // state: 'done' | 'active' | 'pending'
  const color = state === 'done' ? 'var(--accent)' : state === 'active' ? 'var(--blue)' : 'var(--text-3)';
  return (
    <div style={{ display: 'flex', gap: 14, alignItems: 'flex-start', opacity: state === 'pending' ? 0.5 : 1, transition: 'opacity .3s' }}>
      <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', alignSelf: 'stretch' }}>
        <div style={{
          width: 30, height: 30, borderRadius: 99, flexShrink: 0, display: 'flex', alignItems: 'center', justifyContent: 'center',
          background: state === 'done' ? 'var(--accent)' : state === 'active' ? 'var(--blue-wash)' : 'var(--surface-2)',
          border: '1px solid ' + (state === 'pending' ? 'var(--line-2)' : color),
        }}>
          {state === 'done'
            ? <Icon name="check" size={16} color="var(--on-accent)" sw={3} />
            : state === 'active'
              ? <span style={{ width: 9, height: 9, borderRadius: 99, background: 'var(--blue)', animation: 'pulse 1s infinite' }} />
              : <span style={{ width: 7, height: 7, borderRadius: 99, background: 'var(--text-3)' }} />}
        </div>
        {!step.last && <div style={{ width: 2, flex: 1, minHeight: 16, background: state === 'done' ? 'var(--accent)' : 'var(--line)', marginTop: 4 }} />}
      </div>
      <div style={{ paddingBottom: 18, flex: 1 }}>
        <div style={{ fontSize: 14, fontWeight: 700, color: state === 'pending' ? 'var(--text-2)' : 'var(--text)' }}>{step.title}</div>
        <div style={{ fontSize: 12.5, color: 'var(--text-3)', marginTop: 2 }}>{step.desc}</div>
        {state === 'active' && step.note && (
          <div style={{ fontSize: 12, color: 'var(--blue)', marginTop: 6, display: 'inline-flex', alignItems: 'center', gap: 6 }}>
            <span style={{ width: 6, height: 6, borderRadius: 99, background: 'var(--blue)', animation: 'pulse 1s infinite' }} />{step.note}
          </div>
        )}
      </div>
    </div>
  );
}

function orderStepCopy(stepType) {
  const map = {
    buy_created: ['Order created', 'Backend accepted the buy request'],
    deposit_seen: ['Waiting for deposit', 'Send USDC to the order deposit address'],
    fee_taken: ['Fee reserved', 'KOL/platform fee accounted in USDC'],
    execution_plan_created: ['Quote locked', 'Jupiter and 0x routes prepared'],
    cctp_solana_to_base_burn: ['CCTP burn', 'Moving the Base sleeve from Solana'],
    cctp_attestation_received: ['CCTP attestation', 'Waiting for Circle Iris attestation'],
    cctp_base_minted: ['Base USDC minted', 'USDC received on Base'],
    base_gas_reserved: ['Base gas reserved', 'Funding gas for Base execution'],
    solana_swaps_running: ['Swapping on Solana', 'USDC to underlying assets'],
    solana_swaps_done: ['Solana swaps done', 'Settled Solana fills recorded'],
    base_swaps_running: ['Swapping on Base', '0x routed Base execution'],
    base_swaps_done: ['Base swaps done', 'Settled Base fills recorded'],
    vault_sweep_done: ['Sweeping to vault', 'Moving assets into basket vaults'],
    units_minted: ['Units minted', 'Crediting basket units'],
    buy_settled: ['Copy settled', 'Final units reflect settled fills'],
  };
  return map[stepType] || [stepType.replaceAll('_', ' '), 'Backend execution step'];
}

function shortHash(value) {
  const s = String(value || '');
  if (!s) return '--';
  return s.length > 18 ? s.slice(0, 8) + '...' + s.slice(-6) : s;
}

function copyText(value) {
  const text = String(value || '');
  if (!text) return Promise.resolve(false);
  if (navigator.clipboard && navigator.clipboard.writeText) {
    return navigator.clipboard.writeText(text).then(() => true).catch(() => false);
  }
  try {
    const input = document.createElement('textarea');
    input.value = text;
    input.setAttribute('readonly', '');
    input.style.position = 'fixed';
    input.style.left = '-9999px';
    document.body.appendChild(input);
    input.select();
    const ok = document.execCommand('copy');
    document.body.removeChild(input);
    return Promise.resolve(ok);
  } catch (e) {
    return Promise.resolve(false);
  }
}

function explorerUrl(chain, value, kind = 'tx') {
  const clean = String(value || '').trim();
  if (!clean) return '';
  if (chain === 'base') return 'https://basescan.org/' + (kind === 'address' ? 'address/' : 'tx/') + clean;
  return 'https://solscan.io/' + (kind === 'address' ? 'account/' : 'tx/') + clean;
}

function TinyAction({ icon, title, onClick, href }) {
  const common = {
    title,
    'aria-label': title,
    style: {
      width: 30,
      height: 30,
      borderRadius: 9,
      border: '1px solid var(--line)',
      background: 'var(--surface)',
      color: 'var(--text-3)',
      cursor: 'pointer',
      display: 'inline-flex',
      alignItems: 'center',
      justifyContent: 'center',
      flexShrink: 0,
    },
  };
  if (href) {
    return <a {...common} href={href} target="_blank" rel="noreferrer"><Icon name={icon} size={13} color="currentColor" /></a>;
  }
  return <button {...common} onClick={onClick}><Icon name={icon} size={13} color="currentColor" /></button>;
}

function DepositAddressBox({ address, chain = 'solana' }) {
  const [copied, setCopied] = useState(false);
  const open = explorerUrl(chain === 'base' ? 'base' : 'solana', address, 'address');
  const onCopy = async () => {
    const ok = await copyText(address);
    if (ok) {
      setCopied(true);
      setTimeout(() => setCopied(false), 1500);
    }
  };
  return (
    <div style={{ background: 'var(--bg-2)', border: '1px solid var(--line)', borderRadius: 12, padding: '12px 13px', marginBottom: 16 }}>
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 10, marginBottom: 6 }}>
        <div className="eyebrow">Deposit address</div>
        <div style={{ display: 'inline-flex', alignItems: 'center', gap: 7 }}>
          <span style={{ fontSize: 11.5, color: copied ? 'var(--accent-ink)' : 'var(--text-3)' }}>{copied ? 'Copied' : 'USDC only'}</span>
          <TinyAction icon="copy" title="Copy deposit address" onClick={onCopy} />
          <TinyAction icon="ext" title="Open deposit address in explorer" href={open} />
        </div>
      </div>
      <div className="tnum" style={{ fontSize: 12, lineHeight: 1.45, wordBreak: 'break-all', color: 'var(--text)' }}>{address}</div>
      <div style={{ fontSize: 12, color: 'var(--text-3)', marginTop: 8 }}>Send Solana USDC to this order wallet. The worker starts after the deposit is seen.</div>
    </div>
  );
}

function OrderChainActivity({ transactions = [], fills = [] }) {
  const hasTx = transactions && transactions.length;
  const hasFills = fills && fills.length;
  if (!hasTx && !hasFills) {
    return (
      <div style={{ marginTop: 14, padding: '10px 12px', borderRadius: 12, border: '1px solid var(--line)', background: 'var(--bg-2)', color: 'var(--text-3)', fontSize: 12.5, lineHeight: 1.4 }}>
        On-chain transactions and settled fills will appear here as soon as the worker records them.
      </div>
    );
  }
  return (
    <div style={{ marginTop: 14, display: 'grid', gap: 10 }}>
      {hasTx && (
        <div style={{ border: '1px solid var(--line)', background: 'var(--bg-2)', borderRadius: 12, padding: '10px 12px' }}>
          <div className="eyebrow" style={{ marginBottom: 8 }}>Transactions</div>
          {transactions.slice(-4).map(tx => {
            const hash = tx.signature || tx.tx_hash;
            const chain = tx.chain || tx.chain_type || 'solana';
            const label = tx.label ? tx.label.replaceAll('_', ' ') : (chain === 'base' ? 'Base tx' : 'Solana tx');
            return (
              <div key={tx.id || hash} style={{ display: 'flex', alignItems: 'center', gap: 8, padding: '7px 0', borderTop: '1px solid var(--line)' }}>
                <Icon name="bolt" size={13} color={tx.status === 'confirmed' ? 'var(--accent-ink)' : 'var(--blue)'} />
                <div style={{ flex: 1, minWidth: 0 }}>
                  <div style={{ display: 'flex', alignItems: 'center', gap: 7 }}>
                    <span style={{ fontSize: 11, color: 'var(--text-3)', textTransform: 'uppercase', fontWeight: 750 }}>{chain}</span>
                    <span style={{ fontSize: 11.5, color: 'var(--text-2)', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{label}</span>
                  </div>
                  <div className="tnum" style={{ fontSize: 12.5, color: 'var(--text)' }}>{shortHash(hash)}</div>
                </div>
                <span style={{ fontSize: 11.5, color: 'var(--text-3)' }}>{tx.confirmation_status || tx.status}</span>
                {hash && <TinyAction icon="copy" title="Copy transaction hash" onClick={() => copyText(hash)} />}
                {hash && <TinyAction icon="ext" title="Open transaction in explorer" href={explorerUrl(chain, hash, 'tx')} />}
              </div>
            );
          })}
        </div>
      )}
      {hasFills && (
        <div style={{ border: '1px solid var(--line)', background: 'var(--bg-2)', borderRadius: 12, padding: '10px 12px' }}>
          <div className="eyebrow" style={{ marginBottom: 8 }}>Settled fills</div>
          {fills.slice(-5).map(fill => (
            <div key={fill.id} style={{ display: 'flex', alignItems: 'center', gap: 8, padding: '7px 0', borderTop: '1px solid var(--line)' }}>
              <Icon name={fill.side === 'buy' ? 'plus' : 'swap2'} size={13} color="var(--accent-ink)" />
              <span style={{ flex: 1, minWidth: 0, fontSize: 12.5, color: 'var(--text-2)' }}>{fill.side} fill</span>
              <span className="tnum" style={{ fontSize: 12.5, fontWeight: 650 }}>{fill.amount_in_usdc || fill.amount_out_usdc ? fmtUsd(Number(fill.amount_in_usdc || fill.amount_out_usdc)) : shortHash(fill.tx_hash)}</span>
            </div>
          ))}
        </div>
      )}
    </div>
  );
}

function OrderExecuting({ b, amount, order, onDone }) {
  const liveOrderId = order && order.order_id;
  const [remoteOrder, setRemoteOrder] = useState(order || null);
  const [remoteSteps, setRemoteSteps] = useState([]);
  const [transactions, setTransactions] = useState([]);
  const [fills, setFills] = useState([]);
  const [remoteError, setRemoteError] = useState(null);

  useEffect(() => {
    if (!liveOrderId || !window.BasketAPI) return;
    let stop = false;
    const poll = async () => {
      try {
        const [nextOrder, nextSteps, nextTransactions, nextFills] = await Promise.all([
          window.BasketAPI.order(liveOrderId),
          window.BasketAPI.orderSteps(liveOrderId),
          window.BasketAPI.orderTransactions(liveOrderId).catch(() => ({ items: [] })),
          window.BasketAPI.orderFills(liveOrderId).catch(() => ({ items: [] })),
        ]);
        if (stop) return;
        setRemoteOrder(nextOrder);
        setRemoteSteps(nextSteps || []);
        setTransactions((nextTransactions && nextTransactions.items) || []);
        setFills((nextFills && nextFills.items) || []);
        setRemoteError(null);
        if (nextOrder && nextOrder.status === 'settled') {
          setTimeout(onDone, 700);
        }
      } catch (e) {
        if (!stop) setRemoteError(e.message || 'Could not read order status');
      }
    };
    poll();
    const id = setInterval(poll, 3000);
    return () => { stop = true; clearInterval(id); };
  }, [liveOrderId]);

  if (liveOrderId) {
    const shownSteps = remoteSteps.length ? remoteSteps : [
      { step_type: 'buy_created', status: 'done' },
      { step_type: 'deposit_seen', status: 'pending' },
    ];
    const doneCount = shownSteps.filter(s => s.status === 'done').length;
    const activeIndex = Math.max(0, shownSteps.findIndex(s => !['done'].includes(s.status)));
    const pct = Math.min(100, Math.round((doneCount / Math.max(1, shownSteps.length)) * 100));
    const status = (remoteOrder && remoteOrder.status) || order.status;
    const deposit = order.deposit_address || (remoteOrder && remoteOrder.metadata && remoteOrder.metadata.deposit_address);
    return (
      <div style={{ animation: 'fadeIn .3s ease .06s forwards' }}>
        <div style={{ textAlign: 'center', marginBottom: 20 }}>
          <div style={{ width: 56, height: 56, borderRadius: 99, margin: '0 auto 14px', background: 'var(--blue-wash)', border: '1px solid rgba(107,127,255,0.3)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
            <Icon name="swap2" size={26} color="var(--blue)" />
          </div>
          <h3 style={{ margin: 0, fontSize: 20, fontWeight: 700 }}>Order submitted</h3>
          <p style={{ margin: '6px 0 0', fontSize: 13.5, color: 'var(--text-2)' }}>{b.name} · {fmtUsd(+amount)} · <span className="tnum">{status}</span></p>
        </div>

        {deposit && (
          <DepositAddressBox address={deposit} chain="solana" />
        )}

        <div style={{ height: 6, borderRadius: 99, background: 'var(--surface-2)', overflow: 'hidden', marginBottom: 24 }}>
          <div style={{ width: pct + '%', height: '100%', background: 'linear-gradient(90deg, var(--blue), var(--accent))', borderRadius: 99, transition: 'width .6s ease' }} />
        </div>

        <div>
          {shownSteps.map((s, i) => {
            const [title, desc] = orderStepCopy(s.step_type);
            const state = s.status === 'done' ? 'done' : i === activeIndex ? 'active' : 'pending';
            return (
              <ExecStep key={s.id || s.step_type} step={{
                title,
                desc: s.last_error || desc,
                note: s.next_run_at ? 'Scheduled retry' : (state === 'active' ? status : ''),
                last: i === shownSteps.length - 1,
              }} state={state} />
            );
          })}
        </div>

        <OrderChainActivity transactions={transactions} fills={fills} />

        {remoteError && (
          <div style={{ display: 'flex', gap: 8, alignItems: 'flex-start', background: 'rgba(255,107,107,0.1)', border: '1px solid rgba(255,107,107,0.28)', borderRadius: 12, padding: '11px 13px', marginTop: 8 }}>
            <Icon name="info" size={15} color="var(--danger)" style={{ marginTop: 1, flexShrink: 0 }} />
            <span style={{ fontSize: 12.5, color: 'var(--text-2)', lineHeight: 1.45 }}>{remoteError}</span>
          </div>
        )}
      </div>
    );
  }

  const twoChain = b.chainSplit.base > 0;
  const steps = useMemo(() => {
    const s = [
      { title: 'Quote locked', desc: 'Routing via Jupiter' + (twoChain ? ' + 0x' : ''), note: 'Best route found across venues' },
      { title: 'Swapping on Solana', desc: `${b.tokens.filter(t=>t.chain==='sol').length} legs · USDC → underlying`, note: 'Submitting orders to Jupiter' },
    ];
    if (twoChain) {
      s.push({ title: 'Bridging via CCTP', desc: 'Moving USDC sleeve to Base', note: 'Waiting for attestation (~90s)' });
      s.push({ title: 'Swapping on Base', desc: `${b.tokens.filter(t=>t.chain==='base').length} legs · 0x routing`, note: 'Submitting orders to 0x' });
    }
    s.push({ title: 'Settling to vault', desc: 'Crediting basket units', note: 'Reconciling settled fills' });
    s[s.length - 1].last = true;
    return s;
  }, [b.id]);
  const [active, setActive] = useState(0);

  useEffect(() => {
    if (active >= steps.length) { const t = setTimeout(onDone, 700); return () => clearTimeout(t); }
    const dur = active === 0 ? 900 : active === (twoChain ? 2 : 0) ? 1700 : 1300;
    const t = setTimeout(() => setActive(a => a + 1), dur);
    return () => clearTimeout(t);
  }, [active]);

  const pct = Math.min(100, Math.round((active / steps.length) * 100));
  return (
    <div style={{ animation: 'fadeIn .3s ease .06s forwards' }}>
      <div style={{ textAlign: 'center', marginBottom: 24 }}>
        <div style={{ width: 56, height: 56, borderRadius: 99, margin: '0 auto 14px', background: 'var(--blue-wash)', border: '1px solid rgba(107,127,255,0.3)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
          <Icon name="swap2" size={26} color="var(--blue)" />
        </div>
        <h3 style={{ margin: 0, fontSize: 20, fontWeight: 700 }}>Executing your copy</h3>
        <p style={{ margin: '6px 0 0', fontSize: 13.5, color: 'var(--text-2)' }}>Buying {fmtUsd(+amount)} of {b.name} · {b.tokens.length} legs</p>
      </div>
      <div style={{ height: 6, borderRadius: 99, background: 'var(--surface-2)', overflow: 'hidden', marginBottom: 24 }}>
        <div style={{ width: pct + '%', height: '100%', background: 'linear-gradient(90deg, var(--blue), var(--accent))', borderRadius: 99, transition: 'width .6s ease' }} />
      </div>
      <div>
        {steps.map((s, i) => <ExecStep key={i} step={s} state={i < active ? 'done' : i === active ? 'active' : 'pending'} />)}
      </div>
      <div style={{ display: 'flex', gap: 8, alignItems: 'flex-start', background: 'var(--blue-wash)', border: '1px solid rgba(107,127,255,0.22)', borderRadius: 12, padding: '11px 13px', marginTop: 8 }}>
        <Icon name="info" size={15} color="var(--blue)" style={{ marginTop: 1, flexShrink: 0 }} />
        <span style={{ fontSize: 12.5, color: 'var(--text-2)', lineHeight: 1.45 }}>Quotes shown are <strong style={{ color: 'var(--text)' }}>estimates</strong>. Your final units are set by the <strong style={{ color: 'var(--text)' }}>settled on-chain fills</strong> — we'll show the exact result next.</span>
      </div>
    </div>
  );
}

function OrderDone({ b, amount, onView, onClose }) {
  const fee = +amount * b.buyFee / 100;
  const net = +amount - fee;
  const slip = net * 0.0016; // realized vs estimate
  const units = (net - slip) / 1.0171;
  return (
    <div style={{ animation: 'scaleIn .35s ease .06s forwards', textAlign: 'center' }}>
      <div style={{ width: 64, height: 64, borderRadius: 99, margin: '0 auto 16px', background: 'var(--accent)', display: 'flex', alignItems: 'center', justifyContent: 'center', boxShadow: '0 0 30px var(--accent-glow)' }}>
        <Icon name="check" size={32} color="var(--on-accent)" sw={3} />
      </div>
      <h3 style={{ margin: 0, fontSize: 22, fontWeight: 700 }}>Copy settled</h3>
      <p style={{ margin: '6px 0 22px', fontSize: 14, color: 'var(--text-2)' }}>You're now following <strong style={{ color: 'var(--text)' }}>{b.name}</strong> v{b.version}.</p>
      <div style={{ background: 'var(--bg-2)', border: '1px solid var(--line)', borderRadius: 14, padding: '6px 18px', textAlign: 'left', marginBottom: 10 }}>
        <Row label="Basket units received" value={units.toFixed(2)} strong accent badge={<span style={{ fontSize: 10, color: 'var(--accent-ink)' }}>SETTLED</span>} />
        <div style={{ height: 1, background: 'var(--line)' }} />
        <Row label="Net invested" value={fmtUsd(net)} />
        <Row label="Realized slippage" value={'−' + fmtUsd(slip)} sub="vs estimate" />
        <Row label="KOL fee" value={fmtUsd(fee)} />
      </div>
      <div style={{ display: 'flex', gap: 10, marginTop: 18 }}>
        <Btn variant="ghost" full onClick={onClose}>Close</Btn>
        <Btn full icon="wallet" onClick={onView}>View position</Btn>
      </div>
    </div>
  );
}

/* ---------------- Copy modal (orchestrator) ---------------- */
function CopyModal({ basketId, onClose, onViewPosition, auth, dataState, onConnectX, onAuthChanged }) {
  const { baskets } = window.DB;
  const b = baskets.find(x => x.id === basketId) || baskets[0];
  const [stage, setStage] = useState('form'); // form | review | executing | done
  const [amount, setAmount] = useState('500');
  const [quote, setQuote] = useState(null);
  const [quoteState, setQuoteState] = useState({ loading: false, error: null });
  const [order, setOrder] = useState(null);
  const [orderError, setOrderError] = useState(null);
  const [submitting, setSubmitting] = useState(false);
  const live = b.source === 'api' && window.BasketAPI;
  const authWallet = auth && auth.wallet;
  const hasSolanaWallet = Boolean(
    (dataState && dataState.hasSolanaWallet) ||
    (authWallet && authWallet.chain === 'solana')
  );
  const balance = live
    ? (dataState && dataState.walletSolanaUsdcBalance != null ? Number(dataState.walletSolanaUsdcBalance) || 0 : (hasSolanaWallet ? Number(dataState.walletUsdcBalance || 0) || 0 : 0))
    : 12840;
  const min = 1, max = 5000;
  const amt = +amount || 0;
  const needsSolanaWallet = live && !hasSolanaWallet;
  const valid = amt >= min && amt <= max && amt <= balance && !needsSolanaWallet;
  const fee = quote ? +quote.fee_usdc : amt * b.buyFee / 100;
  const net = quote ? +quote.net_amount_usdc : amt - fee;
  const estSlip = net * (b.chainSplit.base > 0 ? 0.004 : 0.0022);
  const twoChain = b.chainSplit.base > 0;

  useEffect(() => {
    if (!live || !valid) {
      setQuote(null);
      setQuoteState({ loading: false, error: null });
      return;
    }
    let stop = false;
    setQuoteState({ loading: true, error: null });
    const id = setTimeout(async () => {
      try {
        const next = await window.BasketAPI.buyQuote(b, amt);
        if (!stop) {
          setQuote(next);
          setQuoteState({ loading: false, error: null });
        }
      } catch (e) {
        if (!stop) {
          setQuote(null);
          setQuoteState({ loading: false, error: e.message || 'Quote failed' });
        }
      }
    }, 250);
    return () => { stop = true; clearTimeout(id); };
  }, [live, b.id, amount, valid]);

  const confirmCopy = async () => {
    setOrderError(null);
    if (!live) {
      setStage('executing');
      return;
    }
    if (!auth || !auth.connected) {
      setOrderError('Connect a wallet first. The backend needs a signed wallet session before it can create a buy order.');
      return;
    }
    if (!hasSolanaWallet) {
      setOrderError('Link a Solana wallet first. Buy deposits and future sell payouts settle in Solana USDC.');
      return;
    }
    setSubmitting(true);
    try {
      const created = await window.BasketAPI.createBuyOrder(b, amt);
      setOrder(created);
      setStage('executing');
      onAuthChanged && onAuthChanged();
    } catch (e) {
      setOrderError(e.message || 'Could not create order');
    } finally {
      setSubmitting(false);
    }
  };

  return (
    <div onClick={onClose} style={{ position: 'fixed', inset: 0, zIndex: 80, background: 'rgba(5,6,11,0.72)', backdropFilter: 'blur(6px)', display: 'flex', alignItems: 'center', justifyContent: 'center', padding: 24, animation: 'fadeIn .2s ease .06s forwards' }}>
      <div onClick={e => e.stopPropagation()} style={{ width: '100%', maxWidth: 460, background: 'var(--surface)', border: '1px solid var(--line-2)', borderRadius: 'var(--r-xl)', boxShadow: 'var(--shadow-lg)', maxHeight: '92vh', overflowY: 'auto', animation: 'scaleIn .25s ease .06s forwards' }}>
        {/* header */}
        <div style={{ display: 'flex', alignItems: 'center', gap: 12, padding: '20px 22px', borderBottom: '1px solid var(--line)', position: 'sticky', top: 0, background: 'var(--surface)', zIndex: 1 }}>
          {(stage === 'form' || stage === 'review') && <>
            <KolAvatar kol={b.kol} size={36} />
            <div style={{ flex: 1 }}>
              <div style={{ fontWeight: 700, fontSize: 15 }}>{stage === 'review' ? 'Review copy' : 'Copy basket'}</div>
              <div style={{ fontSize: 12, color: 'var(--text-3)' }}>{b.name} · by {b.kol.x}</div>
            </div>
          </>}
          {(stage === 'executing' || stage === 'done') && <div style={{ flex: 1, fontWeight: 700, fontSize: 15 }}>Order status</div>}
          <button onClick={onClose} style={{ width: 32, height: 32, borderRadius: 9, border: '1px solid var(--line)', background: 'var(--surface-2)', cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
            <Icon name="x" size={16} color="var(--text-2)" />
          </button>
        </div>

        <div style={{ padding: 22 }}>
          {stage === 'form' && (
            <div style={{ display: 'flex', flexDirection: 'column', gap: 18 }}>
              <AmountField value={amount} setValue={setAmount} min={min} max={max} balance={balance} balanceLabel={live ? 'Solana USDC' : 'Balance'} />

              <div style={{
                display: 'flex', alignItems: 'center', gap: 9, padding: '10px 12px', borderRadius: 12,
                background: live ? 'var(--blue-wash)' : 'var(--surface-2)',
                border: '1px solid ' + (quoteState.error ? 'rgba(255,107,107,0.28)' : live ? 'rgba(107,127,255,0.25)' : 'var(--line)'),
              }}>
                <Icon name={quoteState.error ? 'info' : live ? 'bolt' : 'spark'} size={15} color={quoteState.error ? 'var(--danger)' : live ? 'var(--blue)' : 'var(--text-3)'} />
                <span style={{ fontSize: 12.5, color: 'var(--text-2)', lineHeight: 1.4 }}>
                  {quoteState.loading ? 'Fetching live backend quote...' :
                    quoteState.error ? `Backend quote unavailable: ${quoteState.error}` :
                    quote ? 'Live quote loaded from basket-fund.' :
                    'Demo estimate. Connect a live backend basket to create an on-chain order.'}
                </span>
              </div>

              {/* execution preview */}
              <div>
                <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 8 }}>
                  <span style={{ fontSize: 13, fontWeight: 600, color: 'var(--text-2)' }}>Execution preview</span>
                  <EstimateBadge tip="Per-token amounts are estimated from current quotes and will differ slightly from settled fills." />
                </div>
                <div style={{ background: 'var(--bg-2)', border: '1px solid var(--line)', borderRadius: 12, padding: '6px 14px' }}>
                  {b.tokens.map((t, i) => (
                    <div key={t.sym} style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '8px 0', borderBottom: i < b.tokens.length - 1 ? '1px solid var(--line)' : 'none' }}>
                      <TokenDot color={t.color} sym={t.sym} logoUrl={t.logo_url || t.logoUrl} logoSources={t.logo_sources || t.logoSources} size={24} />
                      <span style={{ fontSize: 13, fontWeight: 600, flex: 1 }}>{t.sym} <span style={{ color: 'var(--text-3)', fontWeight: 500 }}>· {t.weight}%</span></span>
                      <ChainBadge chain={t.chain} size="sm" />
                      <span className="tnum" style={{ fontSize: 13, fontWeight: 600, minWidth: 64, textAlign: 'right' }}>{fmtUsd(net * t.weight / 100)}</span>
                    </div>
                  ))}
                </div>
              </div>

              {/* fee breakdown */}
              <div style={{ background: 'var(--bg-2)', border: '1px solid var(--line)', borderRadius: 12, padding: '6px 14px' }}>
                <Row label="KOL fee" value={fmtUsd(fee)} sub={`(${b.buyFee}%)`} />
                <Row label="Est. slippage" value={'−' + fmtUsd(estSlip)} badge={<EstimateBadge>Est</EstimateBadge>} />
                <Row label="Network / execution" value="≈ $0.40" badge={<EstimateBadge>Est</EstimateBadge>} />
                <div style={{ height: 1, background: 'var(--line)' }} />
                <Row label="Net invested" value={fmtUsd(Math.max(0, net - estSlip))} strong accent />
              </div>

              {/* warnings */}
              {twoChain && (
                <div style={{ display: 'flex', gap: 9, background: 'rgba(255,198,91,0.08)', border: '1px solid rgba(255,198,91,0.25)', borderRadius: 12, padding: '11px 13px' }}>
                  <Icon name="swap2" size={16} color="var(--warning)" style={{ marginTop: 1, flexShrink: 0 }} />
                  <span style={{ fontSize: 12.5, color: 'var(--text-2)', lineHeight: 1.45 }}>This basket is <strong style={{ color: 'var(--text)' }}>two-chain</strong> ({b.chainSplit.base}% on Base). The Base legs bridge via CCTP and may take ~90s longer to settle.</span>
                </div>
              )}

              {needsSolanaWallet && (
                <div style={{ display: 'flex', gap: 10, alignItems: 'center', background: 'rgba(255,198,91,0.08)', border: '1px solid rgba(255,198,91,0.25)', borderRadius: 12, padding: '11px 13px' }}>
                  <Icon name="wallet" size={16} color="var(--warning)" />
                  <span style={{ flex: 1, fontSize: 12.5, color: 'var(--text-2)', lineHeight: 1.4 }}>Link a Solana wallet before copying. Deposits and sell payouts settle in Solana USDC.</span>
                  <Btn size="sm" variant="ghost" onClick={onConnectX}>Link</Btn>
                </div>
              )}

              <Btn full size="lg" disabled={!valid} onClick={() => setStage('review')}>Review copy</Btn>
            </div>
          )}

          {stage === 'review' && (
            <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
              <div style={{ textAlign: 'center', padding: '8px 0' }}>
                <div style={{ fontSize: 12, color: 'var(--text-3)' }}>You're investing</div>
                <div className="tnum" style={{ fontSize: 40, fontWeight: 700, letterSpacing: '-0.03em' }}>{fmtUsd(amt)}</div>
                <div style={{ fontSize: 13, color: 'var(--text-2)' }}>into <strong style={{ color: 'var(--text)' }}>{b.name}</strong> · v{b.version}</div>
              </div>
              <div style={{ background: 'var(--bg-2)', border: '1px solid var(--line)', borderRadius: 12, padding: '6px 14px' }}>
                <Row label="Net invested" value={fmtUsd(Math.max(0, net - estSlip))} strong />
                <Row label="KOL fee" value={fmtUsd(fee)} sub={`(${b.buyFee}%)`} />
                <Row label="Est. units received" value={(Math.max(0, net - estSlip) / 1.0171).toFixed(2)} badge={<EstimateBadge>Est</EstimateBadge>} />
                <Row label="Auto-follow rebalances" value="On" accent />
              </div>
              <div style={{ display: 'flex', gap: 8, alignItems: 'flex-start', fontSize: 12, color: 'var(--text-3)', padding: '0 2px' }}>
                <Icon name="shield" size={14} color="var(--text-3)" style={{ marginTop: 1, flexShrink: 0 }} />
                Funds buy real underlying assets held in custodial vaults. Final units reflect settled fills, not the estimates above.
              </div>
              {live && (!auth || !auth.connected) && (
                <div style={{ display: 'flex', gap: 10, alignItems: 'center', background: 'var(--blue-wash)', border: '1px solid rgba(107,127,255,0.25)', borderRadius: 12, padding: '11px 13px' }}>
                  <Icon name="user" size={16} color="var(--blue)" />
                <span style={{ flex: 1, fontSize: 12.5, color: 'var(--text-2)', lineHeight: 1.4 }}>A signed wallet session is required before creating a real order.</span>
                  <Btn size="sm" variant="blue" onClick={onConnectX}>Connect wallet</Btn>
                </div>
              )}
              {live && auth && auth.connected && !hasSolanaWallet && (
                <div style={{ display: 'flex', gap: 10, alignItems: 'center', background: 'rgba(255,198,91,0.08)', border: '1px solid rgba(255,198,91,0.25)', borderRadius: 12, padding: '11px 13px' }}>
                  <Icon name="wallet" size={16} color="var(--warning)" />
                  <span style={{ flex: 1, fontSize: 12.5, color: 'var(--text-2)', lineHeight: 1.4 }}>Link a Solana wallet before creating the order. Base wallets can stay linked for balances, but settlement uses Solana USDC.</span>
                  <Btn size="sm" variant="ghost" onClick={onConnectX}>Link</Btn>
                </div>
              )}
              {orderError && (
                <div style={{ display: 'flex', gap: 9, background: 'rgba(255,107,107,0.1)', border: '1px solid rgba(255,107,107,0.28)', borderRadius: 12, padding: '11px 13px' }}>
                  <Icon name="info" size={15} color="var(--danger)" style={{ marginTop: 1, flexShrink: 0 }} />
                  <span style={{ fontSize: 12.5, color: 'var(--text-2)', lineHeight: 1.45 }}>{orderError}</span>
                </div>
              )}
              <div style={{ display: 'flex', gap: 10 }}>
                <Btn variant="ghost" full onClick={() => setStage('form')}>Back</Btn>
                <Btn full icon="bolt" disabled={submitting || (live && (!auth || !auth.connected))} onClick={confirmCopy}>{submitting ? 'Creating order...' : 'Confirm & copy'}</Btn>
              </div>
            </div>
          )}

          {stage === 'executing' && <OrderExecuting b={b} amount={amount} order={order} onDone={() => setStage('done')} />}
          {stage === 'done' && <OrderDone b={b} amount={amount} onClose={onClose} onView={onViewPosition} />}
        </div>
      </div>
    </div>
  );
}

Object.assign(window, { CopyModal, OrderChainActivity });
