// Dapp Marketplace — full-bleed overlay opened from the icon rail's "+" button.
// Catalog of apps that extend the Personal Dapp (UBP). Apps fall into categories:
// research, publishing, finance, infrastructure, identity, governance.

const __MKT_CATALOG = [
  // Featured / installed
  { id: 'labbook', name: 'Open Labbook', tagline: 'Git for science · live notebooks', cat: 'research',
    issuer: 'UB Core', icon: 'book', tis: 94.2, installs: '128k', price: 'Included',
    installed: true, featured: true,
    desc: 'Versioned, branchable lab notebooks with on-chain commit history. Multi-author, reproducible, every cell hashed.',
    perms: ['Read/write notebooks', 'Sign commits with UBID', 'Push to chain'],
    screens: 4 },
  { id: 'publication', name: 'Publication', tagline: 'Submit · review · royalties', cat: 'publishing',
    issuer: 'UB Core', icon: 'doc', tis: 92.8, installs: '94k', price: 'Included',
    installed: true, featured: true,
    desc: 'End-to-end paper pipeline. SBT-gated peer review, automated royalty splits, OJN integration.',
    perms: ['Read drafts', 'Submit to journals', 'Distribute royalties'],
    screens: 6 },
  { id: 'institution', name: 'Institution / Grant DAO', tagline: 'Funding · payroll · governance', cat: 'governance',
    issuer: 'UB Core', icon: 'bank', tis: 89.1, installs: '12k', price: 'Included',
    installed: true, featured: true,
    desc: 'Run a lab, department, or grant DAO on-chain. Milestone-gated payouts, transparent overhead, member SBTs.',
    perms: ['Hold institutional treasury', 'Issue member SBTs', 'Sign on milestones'],
    screens: 5 },
  { id: 'compute', name: 'Compute Marketplace', tagline: 'Spot GPU · ZK proofs', cat: 'infrastructure',
    issuer: 'UB Core', icon: 'cpu', tis: 91.4, installs: '67k', price: 'Pay-as-you-go',
    installed: true,
    desc: 'Bid for academic compute on a live order book. NVIDIA H100 / A100, ZK-verifiable runs.',
    perms: ['Submit jobs', 'Spend UBR from wallet', 'Receive output to storage'],
    screens: 3 },
  { id: 'storage', name: 'Storage / DePIN', tagline: 'IPFS · proof-of-storage', cat: 'infrastructure',
    issuer: 'UB Core', icon: 'storage', tis: 88.7, installs: '54k', price: 'Pay-as-you-go',
    installed: true,
    desc: 'Pin datasets across 142 nodes. Receipts stored on-chain. Host capacity to earn UBR.',
    perms: ['Pin/unpin objects', 'Verify receipts', 'Pledge capacity'],
    screens: 3 },
  { id: 'launchpad', name: 'Patent Launchpad', tagline: 'Tokenize IP · raise · royalties', cat: 'finance',
    issuer: 'UB Core', icon: 'rocket', tis: 86.3, installs: '21k', price: '0.4% of raise',
    installed: true,
    desc: 'Tokenize a patent and offer fractional ownership. Linear vesting, on-chain royalty waterfalls.',
    perms: ['Issue patent tokens', 'Hold treasury in escrow', 'Distribute royalties'],
    screens: 4 },

  // Available — not installed
  { id: 'reviewer', name: 'Reviewer Hub', tagline: 'Anonymous SBT-gated reviews', cat: 'publishing',
    issuer: 'OJN', icon: 'check', tis: 90.6, installs: '38k', price: 'Free',
    desc: 'Pseudonymous peer review with verified credentials. Earn TIS for accepted reviews.',
    perms: ['Sign reviews with SBT', 'Read embargoed drafts'],
    screens: 3 },
  { id: 'preprint', name: 'arXiv Mirror', tagline: 'Sync preprints · two-way', cat: 'research',
    issuer: 'arXiv Foundation', icon: 'doc', tis: 87.0, installs: '102k', price: 'Free',
    desc: 'Two-way sync between arXiv/bioRxiv and your TRID. Auto-mirror new preprints, push UB-Chain hashes back to arXiv.',
    perms: ['Read your arXiv drafts', 'Push DOI receipts'],
    screens: 2 },
  { id: 'dao-vote', name: 'DAO Voting', tagline: 'Quadratic · conviction · futarchy', cat: 'governance',
    issuer: 'UB Labs', icon: 'shield', tis: 84.5, installs: '17k', price: 'Free',
    desc: 'Pluggable governance: quadratic, conviction, or futarchy. SBT-weighted ballots.',
    perms: ['Cast votes', 'Read DAO proposals'],
    screens: 3 },
  { id: 'ai-twin', name: 'Research AI Twin', tagline: 'Personal model · cited from your work', cat: 'research',
    issuer: 'Constellation Labs', icon: 'flask', tis: 78.2, installs: '8.4k', price: '120 UBR/mo',
    desc: 'Fine-tune a private model on your published work, drafts and reviews. Every output is cited.',
    perms: ['Read all your papers', 'Read your drafts', 'Spend compute budget'],
    screens: 4 },
  { id: 'bounties', name: 'Research Bounties', tagline: 'Open problems · paid', cat: 'finance',
    issuer: 'UB Core', icon: 'plus', tis: 82.9, installs: '14k', price: 'Free',
    desc: 'Post or claim research bounties. Reproducibility, replication studies, code translations.',
    perms: ['Post bounties', 'Hold escrow', 'Claim payouts'],
    screens: 3 },
  { id: 'sloan', name: 'Sloan Foundation', tagline: 'Apply · report · disburse', cat: 'finance',
    issuer: 'Sloan Foundation', icon: 'bank', tis: 91.0, installs: '2.1k', price: 'Free',
    verified: true,
    desc: 'Direct integration with Sloan grant programs. Apply, submit milestones, receive disbursements.',
    perms: ['Read grant docs', 'Submit reports', 'Receive UBR/USDC'],
    screens: 3 },
  { id: 'orcid', name: 'ORCID Bridge', tagline: 'Federate identity', cat: 'identity',
    issuer: 'ORCID', icon: 'user', tis: 95.4, installs: '187k', price: 'Free',
    verified: true,
    desc: 'Bidirectional sync between your TRID and ORCID. One canonical identity across web2 and web3.',
    perms: ['Read ORCID profile', 'Update affiliations', 'Sign with ORCID'],
    screens: 2 },
  { id: 'figma', name: 'Figure Studio', tagline: 'Reproducible figures · LaTeX export', cat: 'research',
    issuer: 'Plotly', icon: 'doc', tis: 79.4, installs: '23k', price: '40 UBR/mo',
    desc: 'Build publication-quality figures from your notebook outputs. One-click LaTeX/SVG export.',
    perms: ['Read notebook outputs', 'Write to drafts'],
    screens: 3 },
  { id: 'replication', name: 'Replication Vault', tagline: 'Reproducibility tokens · rewards', cat: 'research',
    issuer: 'UB Core', icon: 'shield', tis: 83.7, installs: '11k', price: 'Free',
    desc: 'Stake on whether a result will replicate. Earn when correct. Funds reproducibility studies.',
    perms: ['Stake UBR', 'Read replication results'],
    screens: 3 },
  { id: 'ipfs-pin', name: 'Long-Term Archive', tagline: 'Cold storage · 100yr SLA', cat: 'infrastructure',
    issuer: 'Filecoin Foundation', icon: 'storage', tis: 89.9, installs: '6.7k', price: '12 UBR/TB·yr',
    verified: true,
    desc: 'Cold-archive your raw data with a 100-year SLA. Tape + IPFS dual replication.',
    perms: ['Read storage', 'Manage archive policies'],
    screens: 2 },
  { id: 'editor', name: 'Editor Workbench', tagline: 'Journal editor toolkit', cat: 'publishing',
    issuer: 'OJN', icon: 'doc', tis: 87.6, installs: '4.2k', price: 'Free',
    desc: 'For journal editors: assignment, conflicts, review aggregation, decision letters.',
    perms: ['Read submissions', 'Assign reviewers', 'Issue decisions'],
    screens: 5 },
  { id: 'ubid-keys', name: 'Hardware Keys', tagline: 'YubiKey · Ledger', cat: 'identity',
    issuer: 'Yubico', icon: 'shield', tis: 96.2, installs: '44k', price: 'Free',
    verified: true,
    desc: 'Sign UBID transactions with a hardware key. Recovery via social custodians.',
    perms: ['Sign with hardware key'],
    screens: 2 },
];

const __MKT_CATS = [
  { id: 'all', label: 'All apps', count: 18 },
  { id: 'featured', label: 'Featured', count: 6 },
  { id: 'installed', label: 'Installed', count: 6 },
  { id: 'research', label: 'Research tools', count: 5 },
  { id: 'publishing', label: 'Publishing', count: 3 },
  { id: 'finance', label: 'Finance & funding', count: 3 },
  { id: 'infrastructure', label: 'Infrastructure', count: 3 },
  { id: 'governance', label: 'Governance', count: 2 },
  { id: 'identity', label: 'Identity & keys', count: 2 },
];

function MktCatRow({ row, active, onPick }) {
  return (
    <button onClick={() => onPick(row.id)}
      style={{
        appearance: 'none', border: 0, background: active ? UB.ink : 'transparent',
        color: active ? UB.paper : UB.ink2,
        display: 'flex', alignItems: 'center', justifyContent: 'space-between',
        width: '100%', padding: '7px 14px', cursor: 'pointer',
        fontSize: 12, textAlign: 'left'
      }}>
      <span>{row.label}</span>
      <span style={{ fontFamily: UB.mono, fontSize: 9, color: active ? 'rgba(243,239,225,.5)' : UB.ink3 }}>{row.count}</span>
    </button>
  );
}

function MktAppCard({ app, selected, onPick }) {
  const tone = app.installed ? UB.ok : UB.accent;
  return (
    <button onClick={() => onPick(app.id)}
      style={{
        appearance: 'none', textAlign: 'left',
        border: `1px solid ${selected ? UB.ink : UB.rule2}`,
        background: '#fff',
        padding: 14, cursor: 'pointer', position: 'relative',
        display: 'flex', flexDirection: 'column', gap: 10, minHeight: 160,
        outline: selected ? `1px solid ${UB.ink}` : 'none',
      }}>
      <Corners />
      <div style={{ display: 'flex', alignItems: 'flex-start', gap: 10 }}>
        <div style={{
          width: 36, height: 36, background: UB.ink, color: UB.paper,
          display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0
        }}>{Icon[app.icon] || Icon.cube}</div>
        <div style={{ minWidth: 0, flex: 1 }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 6, marginBottom: 1 }}>
            <span style={{ fontWeight: 600, fontSize: 13 }}>{app.name}</span>
            {app.verified && <span title="Verified issuer" style={{ color: UB.ok, display: 'inline-flex' }}>{Icon.check}</span>}
          </div>
          <div style={{ fontSize: 11, color: UB.ink3, fontFamily: UB.mono, letterSpacing: '0.02em' }}>
            {app.tagline}
          </div>
        </div>
        {app.installed
          ? <Tag tone="ok">INSTALLED</Tag>
          : app.featured ? <Tag tone="accent">FEATURED</Tag> : null}
      </div>
      <div style={{ fontSize: 11, color: UB.ink2, lineHeight: 1.45, flex: 1, textWrap: 'pretty' }}>
        {app.desc}
      </div>
      <div style={{ display: 'flex', alignItems: 'center', gap: 10, fontFamily: UB.mono, fontSize: 9, color: UB.ink3, letterSpacing: '0.06em', textTransform: 'uppercase', borderTop: `1px solid ${UB.rule2}`, paddingTop: 8 }}>
        <span>TIS <span style={{ color: UB.ink, fontWeight: 600 }}>{app.tis}</span></span>
        <span>·</span>
        <span>{app.installs}</span>
        <span style={{ flex: 1 }} />
        <span style={{ color: app.price === 'Free' || app.price === 'Included' ? UB.ok : UB.ink }}>{app.price}</span>
      </div>
    </button>
  );
}

function MktDetail({ app, onClose, onInstall }) {
  if (!app) return null;
  return (
    <div style={{
      width: 320, flexShrink: 0,
      borderLeft: `1px solid ${UB.rule2}`, background: UB.paperDeep,
      display: 'flex', flexDirection: 'column', overflow: 'auto'
    }}>
      {/* hero */}
      <div style={{ padding: 18, borderBottom: `1px solid ${UB.rule2}`, position: 'relative' }}>
        <Corners />
        <div style={{ display: 'flex', alignItems: 'flex-start', gap: 12, marginBottom: 12 }}>
          <div style={{
            width: 52, height: 52, background: UB.ink, color: UB.paper,
            display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0
          }}>{Icon[app.icon] || Icon.cube}</div>
          <div style={{ minWidth: 0, flex: 1 }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
              <span style={{ fontWeight: 600, fontSize: 16, fontFamily: UB.serif }}>{app.name}</span>
              {app.verified && <span title="Verified" style={{ color: UB.ok, display: 'inline-flex' }}>{Icon.check}</span>}
            </div>
            <div style={{ fontSize: 11, color: UB.ink3, fontFamily: UB.mono, marginBottom: 6 }}>
              by {app.issuer}
            </div>
            <div style={{ display: 'flex', gap: 4, flexWrap: 'wrap' }}>
              <Tag>{app.cat.toUpperCase()}</Tag>
              {app.installed && <Tag tone="ok">INSTALLED</Tag>}
            </div>
          </div>
        </div>
        <div style={{ fontSize: 12, color: UB.ink2, lineHeight: 1.45, marginBottom: 12, textWrap: 'pretty' }}>
          {app.desc}
        </div>
        <div style={{ display: 'flex', gap: 8 }}>
          {app.installed
            ? <>
                <Btn small style={{ flex: 1 }}>Open</Btn>
                <Btn small icon={Icon.cog}>Settings</Btn>
              </>
            : <>
                <Btn small primary style={{ flex: 1 }} onClick={() => onInstall && onInstall(app)}>
                  {app.price === 'Free' || app.price === 'Included' ? 'Install' : `Install · ${app.price}`}
                </Btn>
                <Btn small icon={Icon.doc}>Docs</Btn>
              </>}
        </div>
      </div>

      {/* stats */}
      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', borderBottom: `1px solid ${UB.rule2}` }}>
        {[['TIS', app.tis], ['Installs', app.installs], ['Screens', app.screens]].map(([k, v], i) => (
          <div key={k} style={{ padding: '10px 12px', borderRight: i < 2 ? `1px solid ${UB.rule2}` : 'none' }}>
            <div style={{ fontFamily: UB.mono, fontSize: 8, color: UB.ink3, letterSpacing: '0.14em', textTransform: 'uppercase', marginBottom: 2 }}>{k}</div>
            <div style={{ fontFamily: UB.serif, fontSize: 18 }}>{v}</div>
          </div>
        ))}
      </div>

      {/* screenshots placeholder */}
      <div style={{ padding: 14, borderBottom: `1px solid ${UB.rule2}` }}>
        <div style={{ fontFamily: UB.mono, fontSize: 9, color: UB.ink3, letterSpacing: '0.14em', textTransform: 'uppercase', marginBottom: 8 }}>Screens · {app.screens}</div>
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 6 }}>
          {Array.from({ length: Math.min(4, app.screens) }).map((_, i) => (
            <div key={i} style={{
              aspectRatio: '4/3', background: UB.paper, border: `1px solid ${UB.rule2}`,
              position: 'relative', overflow: 'hidden'
            }}>
              <StripePlaceholder />
              <div style={{ position: 'absolute', bottom: 4, left: 6, fontFamily: UB.mono, fontSize: 8, color: UB.ink3, letterSpacing: '0.1em' }}>
                {String(i + 1).padStart(2, '0')}
              </div>
            </div>
          ))}
        </div>
      </div>

      {/* permissions */}
      <div style={{ padding: 14, borderBottom: `1px solid ${UB.rule2}` }}>
        <div style={{ fontFamily: UB.mono, fontSize: 9, color: UB.ink3, letterSpacing: '0.14em', textTransform: 'uppercase', marginBottom: 8 }}>Permissions requested</div>
        {app.perms.map((p, i) => (
          <div key={i} style={{ display: 'flex', alignItems: 'flex-start', gap: 6, fontSize: 11, color: UB.ink2, marginBottom: 4 }}>
            <span style={{ color: UB.ink3, marginTop: 2, display: 'inline-flex' }}>{Icon.check}</span>
            <span>{p}</span>
          </div>
        ))}
      </div>

      {/* manifest */}
      <div style={{ padding: 14 }}>
        <div style={{ fontFamily: UB.mono, fontSize: 9, color: UB.ink3, letterSpacing: '0.14em', textTransform: 'uppercase', marginBottom: 8 }}>Manifest</div>
        <div style={{ fontFamily: UB.mono, fontSize: 10, color: UB.ink2, lineHeight: 1.6 }}>
          <div>id · <span style={{ color: UB.ink }}>app.unblock.{app.id}</span></div>
          <div>v · 0.4.{Math.floor(app.tis / 10)}</div>
          <div>chain · UB-Chain · audited</div>
          <div>license · Apache-2.0</div>
        </div>
      </div>
    </div>
  );
}

function DappMarketplace({ onClose }) {
  const [cat, setCat] = React.useState('featured');
  const [sel, setSel] = React.useState('labbook');
  const [q, setQ] = React.useState('');

  const filtered = __MKT_CATALOG.filter(a => {
    if (cat === 'all') return true;
    if (cat === 'featured') return a.featured;
    if (cat === 'installed') return a.installed;
    return a.cat === cat;
  }).filter(a =>
    !q || a.name.toLowerCase().includes(q.toLowerCase()) ||
    a.tagline.toLowerCase().includes(q.toLowerCase()) ||
    a.desc.toLowerCase().includes(q.toLowerCase())
  );

  const selectedApp = __MKT_CATALOG.find(a => a.id === sel) || filtered[0];

  return (
    <div style={{
      position: 'absolute', inset: 0, zIndex: 50,
      background: 'rgba(20,20,21,0.55)',
      display: 'flex', alignItems: 'stretch', justifyContent: 'stretch',
      animation: 'mktFade 160ms ease-out'
    }} onClick={(e) => { if (e.target === e.currentTarget) onClose(); }}>
      <style>{`@keyframes mktFade { from { opacity: 0 } to { opacity: 1 } }`}</style>
      <div style={{
        flex: 1, margin: 16,
        background: UB.paper, border: `1px solid ${UB.ink}`,
        display: 'flex', flexDirection: 'column', minHeight: 0,
        boxShadow: '0 30px 60px rgba(0,0,0,0.35)',
        position: 'relative'
      }}>
        <Corners />

        {/* header */}
        <div style={{ display: 'flex', alignItems: 'center', gap: 14, padding: '12px 18px', borderBottom: `1px solid ${UB.rule2}` }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
            <span style={{ display: 'inline-flex', color: UB.ink }}>{Icon.store}</span>
            <span style={{ fontFamily: UB.serif, fontSize: 18 }}>Dapp Marketplace</span>
            <span style={{ fontFamily: UB.mono, fontSize: 9, color: UB.ink3, letterSpacing: '0.14em', borderLeft: `1px solid ${UB.rule2}`, paddingLeft: 10 }}>
              UB-CHAIN · 247 APPS · ALL AUDITED
            </span>
          </div>
          <div style={{ flex: 1 }} />
          <div style={{ display: 'flex', alignItems: 'center', gap: 6, height: 30, padding: '0 10px', border: `1px solid ${UB.rule2}`, background: '#fff', minWidth: 280 }}>
            <span style={{ color: UB.ink4, display: 'inline-flex' }}>{Icon.search}</span>
            <input value={q} onChange={e => setQ(e.target.value)}
              placeholder="Search apps · category · issuer"
              style={{
                appearance: 'none', border: 0, outline: 0, background: 'transparent',
                fontFamily: UB.mono, fontSize: 11, color: UB.ink, flex: 1, minWidth: 0
              }} />
          </div>
          <Btn small onClick={onClose}>Close</Btn>
        </div>

        {/* body */}
        <div style={{ flex: 1, display: 'flex', minHeight: 0 }}>
          {/* category rail */}
          <div style={{ width: 200, flexShrink: 0, borderRight: `1px solid ${UB.rule2}`, background: UB.paperDeep, padding: '12px 0', overflow: 'auto' }}>
            <div style={{ fontFamily: UB.mono, fontSize: 9, color: UB.ink3, letterSpacing: '0.14em', textTransform: 'uppercase', padding: '4px 14px 8px' }}>
              Browse
            </div>
            {__MKT_CATS.slice(0, 3).map(c =>
              <MktCatRow key={c.id} row={c} active={cat === c.id} onPick={setCat} />
            )}
            <div style={{ fontFamily: UB.mono, fontSize: 9, color: UB.ink3, letterSpacing: '0.14em', textTransform: 'uppercase', padding: '14px 14px 8px' }}>
              Categories
            </div>
            {__MKT_CATS.slice(3).map(c =>
              <MktCatRow key={c.id} row={c} active={cat === c.id} onPick={setCat} />
            )}

            <div style={{ borderTop: `1px solid ${UB.rule2}`, marginTop: 14, padding: '14px' }}>
              <div style={{ fontFamily: UB.mono, fontSize: 9, color: UB.ink3, letterSpacing: '0.14em', textTransform: 'uppercase', marginBottom: 6 }}>Publish your own</div>
              <div style={{ fontSize: 11, color: UB.ink2, lineHeight: 1.45, marginBottom: 8 }}>
                Build a dapp that extends UBP. Submit a manifest, pass audit, list here.
              </div>
              <Btn small icon={Icon.plus}>Developer portal</Btn>
            </div>
          </div>

          {/* app grid */}
          <div style={{ flex: 1, minWidth: 0, padding: 18, overflow: 'auto', background: '#FAFAF6' }}>
            <div style={{ display: 'flex', alignItems: 'baseline', gap: 8, marginBottom: 14 }}>
              <span style={{ fontFamily: UB.serif, fontSize: 22 }}>
                {(__MKT_CATS.find(c => c.id === cat) || {}).label}
              </span>
              <span style={{ fontFamily: UB.mono, fontSize: 10, color: UB.ink3, letterSpacing: '0.12em' }}>
                {filtered.length} APPS
              </span>
              <span style={{ flex: 1 }} />
              <span style={{ fontFamily: UB.mono, fontSize: 10, color: UB.ink3 }}>
                Sort: <span style={{ color: UB.ink }}>TIS ↓</span>
              </span>
            </div>
            <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(260px, 1fr))', gap: 12 }}>
              {filtered.map(a =>
                <MktAppCard key={a.id} app={a} selected={a.id === sel} onPick={setSel} />
              )}
            </div>
            {filtered.length === 0 &&
              <div style={{ padding: 40, textAlign: 'center', color: UB.ink3 }}>
                No apps match. Try a different category.
              </div>}
          </div>

          {/* detail */}
          <MktDetail app={selectedApp} onClose={onClose} />
        </div>

        {/* footer */}
        <div style={{ padding: '8px 18px', borderTop: `1px solid ${UB.rule2}`, fontFamily: UB.mono, fontSize: 9, color: UB.ink3, letterSpacing: '0.12em', display: 'flex', gap: 14 }}>
          <span>ALL DAPPS AUDITED · BUG BOUNTY 50K UBR</span>
          <span>·</span>
          <span>NO TRACKING · EVERY PERMISSION ON-CHAIN</span>
          <span style={{ flex: 1 }} />
          <span>v0.4.2-rc1</span>
        </div>
      </div>
    </div>
  );
}

window.DappMarketplace = DappMarketplace;
