/* ============================================================
   basket.fun — KOL Studio (create / edit / rebalance)
   ============================================================ */

const MAX_TOKEN_WEIGHT = 100;

function WeightSlider({ t, value, onChange, onRemove }) {
  return (
    <div style={{ display: 'flex', alignItems: 'center', gap: 14, padding: '12px 0', borderBottom: '1px solid var(--line)' }}>
      <TokenDot color={t.color} sym={t.sym} logoUrl={t.logo_url || t.logoUrl} logoSources={t.logo_sources || t.logoSources} size={34} />
      <div style={{ width: 96 }}>
        <div style={{ fontWeight: 700, fontSize: 14 }}>{t.sym}</div>
        <div style={{ fontSize: 11, color: 'var(--text-3)' }}>{t.name}</div>
      </div>
      <input type="range" min="0" max={MAX_TOKEN_WEIGHT} value={value} onChange={e => onChange(+e.target.value)}
        style={{ flex: 1, accentColor: t.color }} />
      <div style={{ width: 70, display: 'flex', alignItems: 'center', gap: 4, justifyContent: 'flex-end' }}>
        <input type="number" value={value} onChange={e => onChange(Math.max(0, Math.min(MAX_TOKEN_WEIGHT, +e.target.value || 0)))}
          style={{ width: 46, textAlign: 'right', border: '1px solid var(--line)', background: 'var(--bg-2)', color: 'var(--text)', borderRadius: 8, padding: '5px 6px', fontFamily: 'var(--font)', fontWeight: 700, fontSize: 14, outline: 'none' }} />
        <span style={{ fontSize: 13, color: 'var(--text-3)' }}>%</span>
      </div>
      <button onClick={onRemove} style={{ width: 28, height: 28, borderRadius: 8, border: '1px solid var(--line)', background: 'var(--surface-2)', cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}><Icon name="x" size={13} color="var(--text-3)" /></button>
    </div>
  );
}

function KolStudio({ auth = {}, dataState = {}, onConnectWallet, onConnectX, onDisconnect, onDataReload, onAuthChanged }) {
  const template = (window.DB.baskets && window.DB.baskets[0]) || {
    id: 'new',
    name: 'My Basket',
    tagline: '',
    thesis: '',
    kol: { x: '@you', handle: 'you' },
    aum: 0,
    copiers: 0,
    version: 0,
    tokens: [],
  };
  const [studioBasket, setStudioBasket] = useState(null);
  const [profile, setProfile] = useState(null);
  const [name, setName] = useState(template.name);
  const [description, setDescription] = useState(template.tagline || '');
  const [tokens, setTokens] = useState(template.tokens.map(t => ({ ...t })));
  const [thesis, setThesis] = useState(template.thesis || '');
  const [baseline, setBaseline] = useState('');
  const [cooldown, setCooldown] = useState(0);
  const [toast, setToast] = useState(null);
  const [error, setError] = useState('');
  const [working, setWorking] = useState('');
  const [addOpen, setAddOpen] = useState(false);
  const [tokenQuery, setTokenQuery] = useState('');
  const [tokenChain, setTokenChain] = useState('solana');
  const [tokenResults, setTokenResults] = useState([]);
  const [tokenSearchState, setTokenSearchState] = useState('');
  const [manualAddress, setManualAddress] = useState('');
  const [manualSymbol, setManualSymbol] = useState('');
  const [manualName, setManualName] = useState('');
  const [manualDecimals, setManualDecimals] = useState('');

  const tokenKey = (t) => t.id || t.token_id || t.sym || t.symbol || t.name;
  const makeSnapshot = (next) => JSON.stringify({
    name: next.name,
    description: next.description,
    thesis: next.thesis,
    tokens: (next.tokens || []).map(t => [tokenKey(t), Number(t.weight) || 0, t.thesis || '']),
  });
  const snapshot = () => makeSnapshot({ name, description, thesis, tokens });

  const hydrate = (basket, nextProfile) => {
    const source = basket || template;
    const nextTokens = (source.tokens || []).map(t => ({ ...t }));
    const nextName = source.name || 'My Basket';
    const nextDescription = source.tagline || source.description || '';
    const nextThesis = source.thesis || '';
    setStudioBasket(basket || null);
    if (nextProfile !== undefined) setProfile(nextProfile);
    setName(nextName);
    setDescription(nextDescription);
    setTokens(nextTokens);
    setThesis(nextThesis);
    setBaseline(makeSnapshot({ name: nextName, description: nextDescription, thesis: nextThesis, tokens: nextTokens }));
  };

  useEffect(() => {
    let cancelled = false;
    const load = async () => {
      setError('');
      if (!auth.connected || !window.BasketAPI) {
        hydrate(null, null);
        return;
      }
      setWorking('loading');
      try {
        const kol = await window.BasketAPI.myKolProfile().catch((e) => {
          if (e && (e.status === 401 || e.status === 403)) return null;
          throw e;
        });
        const basket = kol
          ? await window.BasketAPI.myKolBasket().catch((e) => {
            if (e && (e.status === 404 || e.status === 403)) return null;
            throw e;
          })
          : null;
        if (!cancelled) hydrate(basket, kol);
      } catch (e) {
        if (!cancelled) {
          setError(e.message || 'Could not load your KOL basket.');
          hydrate(null, null);
        }
      } finally {
        if (!cancelled) setWorking('');
      }
    };
    load();
    return () => { cancelled = true; };
  }, [auth.token, dataState.mode]);

  useEffect(() => {
    if (cooldown <= 0) return;
    const t = setInterval(() => setCooldown(c => Math.max(0, c - 1)), 1000);
    return () => clearInterval(t);
  }, [cooldown]);

  const total = tokens.reduce((s, t) => s + (Number(t.weight) || 0), 0);
  const balanced = total === 100;
  const dirty = snapshot() !== baseline;
  const apiReady = dataState.online !== false;
  const isKol = Boolean(profile && profile.id);
  const needsWallet = !auth.connected;
  const needsX = auth.connected && !isKol && working !== 'loading';
  const needsTokenIds = auth.connected && apiReady;
  const importedMissing = needsTokenIds ? tokens.filter(t => (Number(t.weight) || 0) > 0 && !(t.id || t.token_id)) : [];
  const nameOk = name.trim().length >= 2;
  const tokenCountOk = tokens.length >= 2 && tokens.length <= 10;
  const thesisOk = thesis.trim().length > 20;
  const draft = !studioBasket || studioBasket.status === 'draft';
  const active = studioBasket && studioBasket.status === 'active';
  const locked = studioBasket && studioBasket.status === 'locked';
  const validForApi = apiReady && isKol && nameOk && balanced && tokenCountOk && thesisOk && importedMissing.length === 0;
  const canPrimary = auth.connected && isKol
    ? validForApi && cooldown === 0 && !locked && (!studioBasket || dirty)
    : true;
  const handle = profile && profile.x_handle ? '@' + profile.x_handle : (auth.connected ? '@connect_x' : ((template.kol && template.kol.x) || '@you'));
  const currentVersion = studioBasket ? (studioBasket.version || 0) : (template.version || 0);
  const statusLabel = studioBasket ? studioBasket.status : (auth.connected ? 'new' : 'preview');
  const versionSub = studioBasket && studioBasket.versionStatus ? studioBasket.versionStatus : (studioBasket ? 'not published' : 'template');
  const revenue = ((studioBasket && studioBasket.aum) || template.aum || 0) * 0.005 * 0.6;
  const tokenAlreadyAdded = (u) => tokens.find(t => {
    const left = String(tokenKey(t) || '').toLowerCase();
    const right = String(tokenKey(u) || '').toLowerCase();
    const mintA = String(t.mint_address || '').toLowerCase();
    const mintB = String(u.mint_address || '').toLowerCase();
    return (left && right && left === right) || (mintA && mintB && mintA === mintB) || (t.sym && u.sym && t.sym === u.sym);
  });
  const universe = Object.values(window.DB.T || {})
    .filter(u => !tokenAlreadyAdded(u))
    .filter(u => !needsTokenIds || u.id || u.token_id);
  const filteredTokenResults = tokenResults.filter(u => !tokenAlreadyAdded(u));
  const tokenPickerItems = tokenQuery.trim().length >= 2 ? filteredTokenResults : universe;
  const xHandle = profile && profile.x_handle
    ? profile.x_handle
    : auth && auth.xProfile && auth.xProfile.handle
      ? auth.xProfile.handle
      : '';
  const walletLabel = auth && auth.wallet
    ? `${auth.wallet.label || 'Wallet'} ${auth.wallet.short || auth.wallet.address || ''}`.trim()
    : '';

  useEffect(() => {
    if (!addOpen || !window.BasketAPI || !apiReady) return;
    const query = tokenQuery.trim();
    if (query.length < 2) {
      setTokenResults([]);
      setTokenSearchState('');
      return;
    }
    let cancelled = false;
    setTokenSearchState('searching');
    const timer = setTimeout(async () => {
      try {
        const rows = await window.BasketAPI.searchTokens(query, tokenChain);
        if (!cancelled) {
          setTokenResults(rows || []);
          setTokenSearchState('done');
        }
      } catch (e) {
        if (!cancelled) {
          setTokenResults([]);
          setTokenSearchState(e.message || 'Token search failed');
        }
      }
    }, 260);
    return () => {
      cancelled = true;
      clearTimeout(timer);
    };
  }, [addOpen, tokenQuery, tokenChain, apiReady, tokens.length]);

  const fmtCd = (s) => `${String(Math.floor(s / 60)).padStart(2, '0')}:${String(s % 60).padStart(2, '0')}`;
  const showToast = (message) => {
    setToast(message);
    setTimeout(() => setToast(null), 5200);
  };
  const setW = (key, v) => setTokens(ts => ts.map(t => tokenKey(t) === key ? { ...t, weight: v } : t));
  const remove = (key) => setTokens(ts => ts.filter(t => tokenKey(t) !== key));
  const distributeWeights = (rows) => {
    if (!rows.length) return rows;
    const each = Math.floor(100 / rows.length);
    let rem = 100 - each * rows.length;
    return rows.map((t, i) => ({ ...t, weight: each + (i < rem ? 1 : 0) }));
  };
  const addToken = (u) => {
    setTokens(ts => distributeWeights([...ts, { ...u, weight: 0, thesis: u.thesis || '' }]));
    setTokenQuery('');
    setTokenResults([]);
    setAddOpen(false);
  };
  const autoBalance = () => {
    if (!tokens.length) return;
    setTokens(ts => distributeWeights(ts));
  };
  const importManualToken = async () => {
    if (!window.BasketAPI) return;
    if (!auth.connected) {
      if (onConnectWallet) await onConnectWallet();
      return;
    }
    const mint = (manualAddress || tokenQuery).trim();
    if (!mint) {
      setTokenSearchState('Paste a token address first.');
      return;
    }
    setWorking('importing-token');
    setTokenSearchState('importing');
    try {
      const token = await window.BasketAPI.importToken({
        chain: tokenChain,
        mint_address: mint,
        symbol: manualSymbol.trim() || undefined,
        name: manualName.trim() || undefined,
        decimals: manualDecimals === '' ? undefined : Number(manualDecimals),
      });
      addToken(token);
      setManualAddress('');
      setManualSymbol('');
      setManualName('');
      setManualDecimals('');
      showToast(`Added ${token.sym || token.symbol}.`);
    } catch (e) {
      setTokenSearchState(e.message || 'Could not import token.');
    } finally {
      setWorking('');
    }
  };

  const persistDraft = async () => {
    setError('');
    if (!auth.connected) {
      if (onConnectWallet) await onConnectWallet();
      return null;
    }
    if (!isKol) {
      if (onConnectX) await onConnectX();
      return null;
    }
    if (!validForApi) return null;
    setWorking(studioBasket ? 'saving' : 'creating');
    try {
      const next = await window.BasketAPI.saveKolBasket({
        basket: studioBasket,
        name,
        description,
        thesis,
        tokens,
      });
      hydrate(next, profile);
      if (onDataReload) await onDataReload();
      showToast(studioBasket ? 'Draft saved.' : 'Draft created.');
      return next;
    } catch (e) {
      setError(e.message || 'Could not save draft.');
      return null;
    } finally {
      setWorking('');
    }
  };

  const submit = async () => {
    if (!auth.connected) {
      if (onConnectWallet) await onConnectWallet();
      return;
    }
    if (!isKol) {
      if (onConnectX) await onConnectX();
      return;
    }
    if (!validForApi || locked || (studioBasket && !active && !dirty)) return;
    if (!active) {
      await persistDraft();
      return;
    }
    setError('');
    setWorking('rebalancing');
    try {
      const response = await window.BasketAPI.submitRebalance({
        reason: 'KOL Studio rebalance',
        thesis,
        tokens,
      });
      setStudioBasket(b => b ? { ...b, status: 'locked' } : b);
      setCooldown(3600);
      if (onDataReload) await onDataReload();
      showToast('Rebalance queued. Order ' + String(response.order_id || '').slice(0, 8) + '.');
    } catch (e) {
      setError(e.message || 'Could not submit rebalance.');
    } finally {
      setWorking('');
    }
  };

  const launch = async () => {
    if (!auth.connected) {
      if (onConnectWallet) await onConnectWallet();
      return;
    }
    if (!isKol) {
      if (onConnectX) await onConnectX();
      return;
    }
    if (!studioBasket || studioBasket.status !== 'draft' || !validForApi) return;
    setError('');
    setWorking('launching');
    try {
      if (dirty) {
        await window.BasketAPI.saveKolBasket({ basket: studioBasket, name, description, thesis, tokens });
      }
      const next = await window.BasketAPI.launchKolBasket();
      hydrate(next, profile);
      if (onDataReload) await onDataReload();
      showToast('Basket launched. It is now visible in the marketplace.');
    } catch (e) {
      setError(e.message || 'Could not launch basket.');
    } finally {
      setWorking('');
    }
  };

  const primaryLabel = !auth.connected
    ? 'Connect wallet'
    : !isKol
      ? 'Connect X to become KOL'
    : working === 'creating'
      ? 'Creating...'
      : working === 'saving'
        ? 'Saving...'
        : working === 'rebalancing'
          ? 'Publishing...'
          : locked
            ? 'Rebalance queued'
            : active
              ? (cooldown > 0 ? `Cooldown ${fmtCd(cooldown)}` : 'Publish rebalance')
              : studioBasket
                ? 'Save draft'
                : 'Create draft';
  const blockers = [
    !auth.connected && 'Connect a wallet first.',
    auth.connected && !isKol && 'Connect X to attach a KOL profile.',
    auth.connected && isKol && !apiReady && 'Backend is offline.',
    auth.connected && isKol && !nameOk && 'Basket name must be at least 2 characters.',
    auth.connected && isKol && tokens.length < 2 && 'Add at least 2 tokens.',
    auth.connected && isKol && tokens.length > 10 && 'Keep the basket at 10 tokens or fewer.',
    auth.connected && isKol && !balanced && `Weights must equal 100%. Current total is ${total}%.`,
    auth.connected && isKol && importedMissing.length > 0 && 'Use live token search/import so every token has a backend ID.',
    auth.connected && isKol && !thesisOk && 'Write a basket thesis of at least 20 characters.',
    auth.connected && isKol && locked && 'A rebalance order is already queued.',
    auth.connected && isKol && cooldown > 0 && `Cooldown is active for ${fmtCd(cooldown)}.`,
    auth.connected && isKol && studioBasket && !dirty && !active && 'Make a change before saving the draft.',
  ].filter(Boolean);

  return (
    <div className="page" style={{ padding: '32px 32px 80px', maxWidth: 1180, margin: '0 auto', animation: 'fadeIn .35s ease .06s forwards' }}>
      {toast && (
        <div style={{ position: 'fixed', bottom: 24, left: '50%', transform: 'translateX(-50%)', zIndex: 90, background: 'var(--surface)', border: '1px solid rgba(163,255,91,0.35)', borderRadius: 14, padding: '14px 18px', boxShadow: 'var(--shadow-lg)', display: 'flex', alignItems: 'center', gap: 12, maxWidth: 440, animation: 'fadeUp .3s ease .06s forwards' }}>
          <div style={{ width: 30, height: 30, borderRadius: 99, background: 'var(--accent)', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}><Icon name="check" size={16} color="var(--on-accent)" sw={3} /></div>
          <span style={{ fontSize: 13, color: 'var(--text-2)', lineHeight: 1.4 }}>{toast}</span>
        </div>
      )}

      <div style={{ display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', marginBottom: 26, flexWrap: 'wrap', gap: 16 }}>
        <div>
          <div style={{ display: 'inline-flex', alignItems: 'center', gap: 7, padding: '4px 11px', borderRadius: 999, background: 'var(--blue-wash)', border: '1px solid rgba(107,127,255,0.25)', marginBottom: 14 }}>
            <Icon name="basket" size={13} color="var(--blue)" /><span className="eyebrow" style={{ color: 'var(--blue)', letterSpacing: '0.14em' }}>KOL Studio · {handle}</span>
          </div>
          <h1 className="display" style={{ margin: 0, fontSize: 'clamp(28px, 3.2vw, 42px)', fontWeight: 900, lineHeight: 1.0 }}>{name}</h1>
          <p style={{ margin: '10px 0 0', color: 'var(--text-2)', fontSize: 15.5 }}>{studioBasket ? (studioBasket.status === 'draft' ? 'Draft basket' : studioBasket.status + ' basket') : 'New KOL basket draft'}</p>
        </div>
      </div>

      {error && (
        <div style={{ marginBottom: 18, background: 'rgba(255,107,107,0.1)', border: '1px solid rgba(255,107,107,0.28)', borderRadius: 14, padding: '12px 14px', color: 'var(--danger)', fontSize: 13.5, lineHeight: 1.45 }}>
          {error}
        </div>
      )}

      {needsX && (
        <div style={{ marginBottom: 18, background: 'rgba(107,127,255,0.1)', border: '1px solid rgba(107,127,255,0.28)', borderRadius: 14, padding: '12px 14px', color: 'var(--text-2)', fontSize: 13.5, lineHeight: 1.45 }}>
          Wallet-only accounts can copy, buy, and sell baskets. Link X to create and publish a KOL basket.
        </div>
      )}

      {/* revenue stat band */}
      <div className="g4" style={{ display: 'grid', gridTemplateColumns: 'repeat(4,1fr)', gap: 16, marginBottom: 24 }}>
        <Card pad={20}><Stat label="Basket status" value={statusLabel} /></Card>
        <Card pad={20}><Stat label="Tokens" value={tokens.length + '/10'} /></Card>
        <Card pad={20}><Stat label="Your revenue" value={fmtCompact(revenue)} accent sub="0.5% of buy/sell flow" /></Card>
        <Card pad={20}><Stat label="Current version" value={'v' + currentVersion} sub={versionSub} /></Card>
      </div>

      <div className="kol-grid" style={{ display: 'grid', gridTemplateColumns: '1fr 340px', gap: 24, alignItems: 'start' }}>
        {/* editor */}
        <div style={{ display: 'flex', flexDirection: 'column', gap: 24 }}>
          <Card pad={24}>
            <SectionLabel n="00" right={<span className="eyebrow" style={{ color: auth.connected ? 'var(--accent-ink)' : 'var(--warning)' }}>{auth.connected ? 'session' : 'connect'}</span>}>Basket details</SectionLabel>
            <div style={{ display: 'grid', gridTemplateColumns: '1fr', gap: 12 }}>
              <input value={name} onChange={e => setName(e.target.value)}
                style={{ width: '100%', border: '1px solid var(--line-2)', background: 'var(--bg-2)', color: 'var(--text)', borderRadius: 12, padding: '12px 14px', fontFamily: 'var(--font)', fontSize: 15, fontWeight: 800, outline: 'none' }} />
              <input value={description} onChange={e => setDescription(e.target.value)} placeholder="Short marketplace line"
                style={{ width: '100%', border: '1px solid var(--line-2)', background: 'var(--bg-2)', color: 'var(--text)', borderRadius: 12, padding: '11px 14px', fontFamily: 'var(--font)', fontSize: 13.5, outline: 'none' }} />
            </div>
          </Card>

          <Card pad={24}>
            <SectionLabel n="01" right={<div style={{ display: 'flex', gap: 8 }}>
              <Btn size="sm" variant="ghost" onClick={autoBalance}>Auto-balance</Btn>
              <Btn size="sm" variant="soft" icon="plus" onClick={() => setAddOpen(o => !o)} disabled={tokens.length >= 10}>Add token</Btn>
            </div>}>Weights</SectionLabel>
            <div className="eyebrow" style={{ marginBottom: 6, marginTop: -8 }}>{tokens.length}/10 tokens · weights must total 100%</div>

            {addOpen && (
              <div style={{ background: 'var(--bg-2)', border: '1px solid var(--line-2)', borderRadius: 14, padding: 14, marginBottom: 14, animation: 'fadeIn .2s ease .06s forwards' }}>
                <div style={{ display: 'flex', gap: 10, alignItems: 'center', marginBottom: 10, flexWrap: 'wrap' }}>
                  <div style={{ display: 'inline-flex', border: '1px solid var(--line)', borderRadius: 999, overflow: 'hidden', background: 'var(--surface)' }}>
                    {[
                      ['solana', 'Solana'],
                      ['base', 'Base'],
                    ].map(([id, label]) => (
                      <button key={id} onClick={() => setTokenChain(id)} style={{
                        border: 0,
                        borderRight: id === 'solana' ? '1px solid var(--line)' : 0,
                        background: tokenChain === id ? 'var(--accent)' : 'transparent',
                        color: tokenChain === id ? 'var(--on-accent)' : 'var(--text-2)',
                        padding: '7px 12px',
                        cursor: 'pointer',
                        fontFamily: 'var(--font)',
                        fontSize: 12,
                        fontWeight: 800,
                      }}>{label}</button>
                    ))}
                  </div>
                  <div style={{ flex: '1 1 260px', minWidth: 220, display: 'flex', alignItems: 'center', gap: 8, border: '1px solid var(--line)', background: 'var(--surface)', borderRadius: 999, padding: '0 12px' }}>
                    <Icon name="explore" size={15} color="var(--text-3)" />
                    <input value={tokenQuery} onChange={e => setTokenQuery(e.target.value)} placeholder="Search symbol, name, or token address"
                      style={{ flex: 1, minWidth: 0, height: 38, border: 0, outline: 'none', background: 'transparent', color: 'var(--text)', fontFamily: 'var(--font)', fontSize: 13 }} />
                  </div>
                </div>

                <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(190px, 1fr))', gap: 8, marginBottom: 12 }}>
                  {tokenPickerItems.map(u => (
                    <button key={`${u.chain || tokenChain}-${u.id || u.mint_address || u.sym}`} onClick={() => addToken(u)} style={{ minWidth: 0, display: 'flex', alignItems: 'center', gap: 9, padding: '9px 10px', borderRadius: 12, border: '1px solid var(--line)', background: 'var(--surface)', cursor: 'pointer', fontFamily: 'var(--font)', textAlign: 'left', color: 'var(--text)' }}>
                      <TokenDot color={u.color} sym={u.sym || u.symbol} logoUrl={u.logo_url || u.logoUrl} logoSources={u.logo_sources || u.logoSources} size={28} />
                      <div style={{ minWidth: 0, flex: 1 }}>
                        <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
                          <strong style={{ fontSize: 13, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{u.sym || u.symbol}</strong>
                          <ChainBadge chain={u.chain || tokenChain} size="sm" />
                        </div>
                        <div style={{ fontSize: 11.5, color: 'var(--text-3)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{u.name || u.mint_address}</div>
                      </div>
                      <Icon name="plus" size={14} color="var(--accent-ink)" />
                    </button>
                  ))}
                </div>

                {tokenSearchState === 'searching' && <div style={{ fontSize: 12, color: 'var(--text-3)', marginBottom: 10 }}>Searching tokens...</div>}
                {tokenQuery.trim().length >= 2 && tokenSearchState === 'done' && tokenPickerItems.length === 0 && (
                  <div style={{ fontSize: 12, color: 'var(--text-3)', marginBottom: 10 }}>No registry match. Import by address below.</div>
                )}
                {tokenQuery.trim().length < 2 && tokenPickerItems.length === 0 && (
                  <div style={{ fontSize: 12, color: 'var(--text-3)', marginBottom: 10 }}>Type at least 2 characters to search live tokens.</div>
                )}
                {tokenSearchState && !['searching', 'done', 'importing'].includes(tokenSearchState) && (
                  <div style={{ fontSize: 12, color: 'var(--warning)', marginBottom: 10 }}>{tokenSearchState}</div>
                )}

                <div style={{ borderTop: '1px solid var(--line)', paddingTop: 12 }}>
                  <div className="eyebrow" style={{ marginBottom: 8 }}>Manual import</div>
                  <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(120px, 1fr))', gap: 8 }}>
                    <input value={manualAddress} onChange={e => setManualAddress(e.target.value)} placeholder={tokenChain === 'base' ? 'Base token contract' : 'Solana mint address'}
                      style={{ minWidth: 0, border: '1px solid var(--line)', background: 'var(--surface)', color: 'var(--text)', borderRadius: 10, padding: '9px 10px', fontFamily: 'var(--mono)', fontSize: 12, outline: 'none' }} />
                    <input value={manualSymbol} onChange={e => setManualSymbol(e.target.value)} placeholder="Symbol"
                      style={{ minWidth: 0, border: '1px solid var(--line)', background: 'var(--surface)', color: 'var(--text)', borderRadius: 10, padding: '9px 10px', fontFamily: 'var(--font)', fontSize: 12, outline: 'none' }} />
                    <input value={manualDecimals} onChange={e => setManualDecimals(e.target.value.replace(/[^0-9]/g, '').slice(0, 2))} placeholder="Dec"
                      style={{ minWidth: 0, border: '1px solid var(--line)', background: 'var(--surface)', color: 'var(--text)', borderRadius: 10, padding: '9px 10px', fontFamily: 'var(--font)', fontSize: 12, outline: 'none' }} />
                  </div>
                  <div style={{ display: 'flex', gap: 8, marginTop: 8, alignItems: 'center' }}>
                    <input value={manualName} onChange={e => setManualName(e.target.value)} placeholder="Name optional"
                      style={{ flex: 1, minWidth: 0, border: '1px solid var(--line)', background: 'var(--surface)', color: 'var(--text)', borderRadius: 10, padding: '9px 10px', fontFamily: 'var(--font)', fontSize: 12, outline: 'none' }} />
                    <Btn size="sm" variant="ghost" icon="plus" disabled={working === 'importing-token'} onClick={importManualToken}>{working === 'importing-token' ? 'Importing...' : 'Import'}</Btn>
                  </div>
                  <div style={{ fontSize: 11.5, color: 'var(--text-3)', marginTop: 7 }}>
                    Solana can auto-fill metadata from Jupiter by mint. Base usually needs symbol and decimals.
                  </div>
                </div>
              </div>
            )}

            {tokens.map(t => <WeightSlider key={tokenKey(t)} t={t} value={t.weight} onChange={v => setW(tokenKey(t), v)} onRemove={() => remove(tokenKey(t))} />)}

            {/* total bar */}
            <div style={{ display: 'flex', alignItems: 'center', gap: 14, marginTop: 16 }}>
              <div style={{ flex: 1, height: 8, borderRadius: 99, background: 'var(--surface-2)', overflow: 'hidden', display: 'flex' }}>
                {tokens.map(t => <div key={t.sym} style={{ width: t.weight + '%', background: t.color }} />)}
              </div>
              <span className="tnum" style={{ fontSize: 14, fontWeight: 700, color: balanced ? 'var(--accent-ink)' : 'var(--warning)', minWidth: 92, textAlign: 'right' }}>
                {balanced ? '100% balanced' : total > 100 ? `${total - 100}% over` : `${100 - total}% left`}
              </span>
            </div>
          </Card>

          {/* thesis editor */}
          <Card pad={24}>
            <SectionLabel n="02" right={<span className="eyebrow" style={{ color: 'var(--danger)' }}>required</span>}>Basket thesis</SectionLabel>
            <textarea value={thesis} onChange={e => setThesis(e.target.value)} rows={5} placeholder="Explain the basket thesis, risk profile, and when copiers should expect rebalances."
              style={{ width: '100%', resize: 'vertical', border: '1px solid var(--line-2)', background: 'var(--bg-2)', color: 'var(--text)', borderRadius: 12, padding: '13px 15px', fontFamily: 'var(--font)', fontSize: 14, lineHeight: 1.5, outline: 'none' }} />
            <div className="eyebrow" style={{ marginTop: 8 }}>{thesis.length} chars · shown to every copier</div>
          </Card>
        </div>

        {/* publish panel */}
        <div style={{ display: 'flex', flexDirection: 'column', gap: 20, position: 'sticky', top: 92 }}>
          <Card pad={22} style={{ background: 'linear-gradient(165deg, var(--surface), var(--bg-2))' }}>
            <div style={{ display: 'flex', justifyContent: 'center', marginBottom: 16 }}>
              <WeightRing tokens={tokens.filter(t => t.weight > 0)} size={150} thickness={18} centerLabel={total + '%'} centerSub={balanced ? 'balanced' : 'allocated'} />
            </div>
            <h4 style={{ margin: '0 0 10px', fontSize: 15, fontWeight: 700 }}>{draft ? 'Draft controls' : 'Publish rebalance'}</h4>
            <div style={{ fontSize: 13, color: 'var(--text-2)', lineHeight: 1.5, marginBottom: 16 }}>
              {draft ? 'Draft changes stay hidden until launch.' : 'Pushes '}
              {!draft && <strong style={{ color: 'var(--text)' }}>v{currentVersion + 1}</strong>}
              {!draft && '. Every copier follows once fills settle.'}
            </div>

            <div style={{ border: '1px solid var(--line)', background: 'var(--bg-2)', borderRadius: 14, padding: 12, marginBottom: 16 }}>
              <div className="eyebrow" style={{ marginBottom: 10 }}>Signed session</div>
              <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
                <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
                  <span style={{ width: 28, height: 28, borderRadius: 99, background: auth.connected ? 'var(--accent)' : 'var(--surface-2)', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>
                    <Icon name="wallet" size={14} color={auth.connected ? 'var(--on-accent)' : 'var(--text-3)'} />
                  </span>
                  <div style={{ minWidth: 0, flex: 1 }}>
                    <div style={{ fontSize: 12, fontWeight: 850 }}>{auth.connected ? 'Wallet session active' : 'Wallet not connected'}</div>
                    <div style={{ fontSize: 11.5, color: 'var(--text-3)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
                      {walletLabel || 'Connect a wallet to create orders and KOL baskets.'}
                    </div>
                  </div>
                  <Btn size="sm" variant="ghost" icon="wallet" onClick={onConnectWallet}>{auth.connected ? 'Switch' : 'Connect'}</Btn>
                </div>
                <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
                  <span style={{ width: 28, height: 28, borderRadius: 99, background: isKol ? '#111' : 'var(--surface-2)', display: 'flex', alignItems: 'center', justifyContent: 'center', color: isKol ? '#fff' : 'var(--text-3)', fontSize: 14, fontWeight: 900, flexShrink: 0 }}>X</span>
                  <div style={{ minWidth: 0, flex: 1 }}>
                    <div style={{ fontSize: 12, fontWeight: 850 }}>{isKol ? 'X profile linked' : 'X not linked'}</div>
                    <div style={{ fontSize: 11.5, color: 'var(--text-3)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
                      {isKol ? (xHandle ? '@' + xHandle : 'Linked X profile') : auth.connected ? 'Link X to publish as a KOL.' : 'Connect wallet before linking X.'}
                    </div>
                  </div>
                  <Btn size="sm" variant="ghost" icon="x" disabled={!auth.connected} onClick={onConnectX}>{isKol ? 'Switch' : 'Link'}</Btn>
                </div>
                {auth.connected && (
                  <Btn full size="sm" variant="danger" icon="x" onClick={onDisconnect}>Disconnect session</Btn>
                )}
              </div>
            </div>

            {/* checklist */}
            <div style={{ display: 'flex', flexDirection: 'column', gap: 9, marginBottom: 16 }}>
              {[
                { ok: auth.connected, label: auth.connected ? 'Wallet connected' : 'Connect wallet' },
                { ok: isKol, label: isKol ? 'X profile linked' : 'Connect X profile' },
                { ok: apiReady, label: apiReady ? 'Backend reachable' : 'Backend offline' },
                { ok: balanced, label: 'Weights sum to 100%' },
                { ok: nameOk, label: 'Basket name set' },
                { ok: tokens.length >= 2 && tokens.length <= 10, label: '2-10 tokens' },
                { ok: tokens.length > 0 && importedMissing.length === 0, label: importedMissing.length ? 'Resolve backend token IDs' : 'Added tokens have backend IDs' },
                { ok: thesis.trim().length > 20, label: 'Thesis written' },
                { ok: cooldown === 0 && !locked, label: locked ? 'Order already queued' : cooldown === 0 ? 'Cooldown clear' : `Cooldown ${fmtCd(cooldown)}` },
              ].map((c, i) => (
                <div key={i} style={{ display: 'flex', alignItems: 'center', gap: 9, fontSize: 13 }}>
                  <span style={{ width: 18, height: 18, borderRadius: 99, flexShrink: 0, display: 'flex', alignItems: 'center', justifyContent: 'center', background: c.ok ? 'var(--accent)' : 'var(--surface-2)', border: '1px solid ' + (c.ok ? 'var(--accent)' : 'var(--line-2)') }}>
                    {c.ok ? <Icon name="check" size={11} color="var(--on-accent)" sw={3} /> : <Icon name="clock" size={11} color="var(--text-3)" />}
                  </span>
                  <span style={{ color: c.ok ? 'var(--text)' : 'var(--text-3)' }}>{c.label}</span>
                </div>
              ))}
            </div>

            <Btn full size="lg" icon={needsWallet ? 'wallet' : !isKol ? 'x' : (active ? 'swap' : 'check')} disabled={Boolean(working) || !canPrimary} onClick={submit}>
              {primaryLabel}
            </Btn>
            {blockers.length > 0 && (
              <div style={{ marginTop: 10, padding: '10px 12px', borderRadius: 12, background: 'var(--surface-2)', border: '1px solid var(--line)', color: 'var(--text-2)', fontSize: 12.5, lineHeight: 1.4 }}>
                {blockers[0]}
              </div>
            )}
            {studioBasket && studioBasket.status === 'draft' && (
              <Btn full size="md" variant="blue" icon="bolt" disabled={Boolean(working) || !validForApi} onClick={launch} style={{ marginTop: 10 }}>
                {working === 'launching' ? 'Launching...' : 'Launch basket'}
              </Btn>
            )}
            <div style={{ fontSize: 11.5, color: 'var(--text-3)', textAlign: 'center', marginTop: 10, display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 6 }}>
              <Icon name="clock" size={12} color="var(--text-3)" /> Max 1 rebalance per hour
            </div>
          </Card>
        </div>
      </div>
    </div>
  );
}

Object.assign(window, { KolStudio });
