/* global React, ReactDOM */
const { useState, useEffect } = React;

// =============================================================
// Continuum MCP — dedicated landing page
// Design system + tokens shared with ../continuum/styles.css
// =============================================================

function Eyebrow({ num, children }) {
  return (
    <div className="section-eyebrow">
      <span className="num">{num}</span>
      <span>{children}</span>
    </div>
  );
}

// ---------- Nav ----------

function NavBar({ scrolled, activeId }) {
  const links = [
    ['what',   'What it is'],
    ['tools',  'Tools'],
    ['wire',   'Wire it up'],
    ['hood',   'Under the hood'],
    ['clients','Clients'],
  ];
  return (
    <nav className={`nav ${scrolled ? 'scrolled' : ''}`}>
      <div className="wrap nav-inner">
        <a href="../continuum/" className="nav-brand">
          <div className="mark"></div>
          Continuum <span style={{ color: 'var(--tx-2)', fontWeight: 500 }}>· MCP</span>
        </a>
        <div className="nav-links">
          {links.map(([id, label]) => (
            <a key={id} href={`#${id}`} className={activeId === id ? 'active' : ''}>{label}</a>
          ))}
        </div>
        <a href="https://pypi.org/project/continuum-mcp/" target="_blank" rel="noopener" className="nav-cta mono">pip · v2.0.3 →</a>
      </div>
    </nav>
  );
}

// ---------- Hero ----------

function Hero() {
  return (
    <section className="hero">
      <div className="hero-grid-bg" />
      <div className="hero-glow" />
      <div className="wrap hero-inner">
        <div className="hero-eyebrow">
          <span className="dot"></span>
          Model Context Protocol server · continuum-mcp v2.0.3
        </div>
        <h1 className="h-display">Continuum MCP</h1>
        <p className="hero-sub">
          A <strong>Model Context Protocol</strong> server that hands any MCP client — Claude Code, Claude Desktop, Cursor —
          persistent memory as four tools: <code className="mono">remember</code>, <code className="mono">recall</code>,{' '}
          <code className="mono">current</code> and <code className="mono">timeline</code>. Backed by Postgres + pgvector,
          local <span className="mono">bge-m3</span> embeddings, hybrid lexical + dense retrieval, and bi-temporal queries.
          No agentic loop on the hot path — memory is just tool calls.
        </p>
        <div className="portfolio-tagline mono">
          <span>⬡</span> One <code>pip install</code>, one <code>claude mcp add</code>, and your agent remembers.
        </div>
        <div className="stack-row">
          {['MCP', 'stdio', 'Streamable-HTTP', 'Postgres', 'pgvector', 'HNSW', 'BM25', 'RRF', 'bge-m3'].map((t) => (
            <span className="skill-tag" key={t}>{t}</span>
          ))}
        </div>
        <div className="hero-actions">
          <a href="https://pypi.org/project/continuum-mcp/" target="_blank" rel="noopener" className="btn btn-primary">Get it on PyPI →</a>
          <a href="https://github.com/Genkryptos/Continuum" target="_blank" rel="noopener" className="btn btn-ghost mono" style={{ fontSize: 13 }}>View on GitHub</a>
          <a href="../continuum/" className="btn btn-ghost mono" style={{ fontSize: 13 }}>← Continuum engine</a>
        </div>

        <div className="hero-stats">
          <div className="hero-stat">
            <div className="v"><span className="ac">4</span></div>
            <div className="k">Tools · remember / recall / current / timeline</div>
          </div>
          <div className="hero-stat">
            <div className="v">2</div>
            <div className="k">Transports · stdio + HTTP</div>
          </div>
          <div className="hero-stat">
            <div className="v"><span className="ac">0</span></div>
            <div className="k">API keys for memory itself</div>
          </div>
          <div className="hero-stat">
            <div className="v">100<span className="dim" style={{ fontSize: 18 }}>%</span></div>
            <div className="k">Local embeddings · bge-m3</div>
          </div>
        </div>
      </div>
    </section>
  );
}

// ---------- What it is ----------

function WhatSection() {
  return (
    <section id="what" className="section">
      <div className="wrap-tight">
        <Eyebrow num="01">What it is</Eyebrow>
        <div className="lead-2col" style={{ marginTop: 20 }}>
          <div>
            <h2 className="h-2" style={{ marginBottom: 16 }}>Memory that speaks the protocol your agent already speaks.</h2>
            <p className="lede" style={{ maxWidth: 'none' }}>
              MCP is the open standard clients like Claude use to reach external tools. Continuum MCP is a server on that
              standard: point it at a Postgres + pgvector database, register it once, and your agent gains a durable memory
              it reads and writes through ordinary tool calls.
            </p>
            <p className="note-line">
              The retrieval engine is the full Continuum stack — hybrid lexical + dense search, live-row invalidation, and
              bi-temporal "as of" queries — exposed here as a thin, four-tool surface.
            </p>
          </div>
          <div className="card card-pad">
            <div className="mono" style={{ fontSize: 11, color: 'var(--tx-2)', letterSpacing: '0.1em', textTransform: 'uppercase', marginBottom: 14 }}>
              the shape of it
            </div>
            <div className="mono" style={{ fontSize: 13, lineHeight: 2, color: 'var(--tx-1)' }}>
              <div><span style={{ color: 'var(--stm)' }}>MCP client</span> <span style={{ color: 'var(--tx-3)' }}>(Claude / Cursor)</span></div>
              <div style={{ color: 'var(--tx-3)' }}>&nbsp;&nbsp;│ &nbsp;tool call</div>
              <div style={{ color: 'var(--tx-3)' }}>&nbsp;&nbsp;▼</div>
              <div><span style={{ color: 'var(--accent)' }}>continuum-mcp</span> <span style={{ color: 'var(--tx-3)' }}>· stdio / http</span></div>
              <div style={{ color: 'var(--tx-3)' }}>&nbsp;&nbsp;│ &nbsp;hybrid retrieval</div>
              <div style={{ color: 'var(--tx-3)' }}>&nbsp;&nbsp;▼</div>
              <div><span style={{ color: 'var(--mtm)' }}>Postgres</span> + <span style={{ color: 'var(--mtm)' }}>pgvector</span> <span style={{ color: 'var(--tx-3)' }}>+ bge-m3</span></div>
            </div>
          </div>
        </div>
      </div>
    </section>
  );
}

// ---------- The four tools ----------

const TOOLS = [
  {
    name: 'remember',
    args: ['text', 'occurred_at?', 'attribute?'],
    badge: 'write',
    desc: 'Store a durable fact. Continuum extracts and indexes it, and — with supersession enabled — retires any older fact it contradicts.',
    ex: [['u', '→ remember("The weekly ops sync moved to Thursdays 3pm")'], ['r', '← stored']],
  },
  {
    name: 'recall',
    args: ['query', 'k?'],
    badge: 'read',
    desc: 'Retrieve the most relevant memories for a query — hybrid lexical + dense search, so it matches on meaning, not just words.',
    ex: [['u', '→ recall("when is the ops meeting")'], ['r', '← "...ops sync moved to Thursdays 3pm"']],
  },
  {
    name: 'current',
    args: ['subject', 'attribute?', 'as_of?'],
    badge: 'read',
    desc: 'The value that holds right now after supersession — or, with as_of, the value that held at any past instant.',
    ex: [['u', '→ current("residence")'], ['r', '← "Lisbon"  (Porto retired 2026-03)']],
  },
  {
    name: 'timeline',
    args: ['entity', 'since?', 'until?'],
    badge: 'read',
    desc: 'The ordered history of an entity — every value it held and when, reconstructed from the bi-temporal record.',
    ex: [['u', '→ timeline("residence")'], ['r', '← Porto → Lisbon, with dates']],
  },
];

function ToolCard({ t }) {
  return (
    <div className="tool-card">
      <div className="tc-h">
        <div className="tc-name">
          {t.name}<span className="paren">(</span>
          {t.args.map((a, i) => (
            <React.Fragment key={a}>
              <span className="arg">{a}</span>{i < t.args.length - 1 ? <span className="paren">, </span> : null}
            </React.Fragment>
          ))}
          <span className="paren">)</span>
        </div>
        <span className="tc-badge">{t.badge}</span>
      </div>
      <div className="tc-b">
        <p className="tc-desc">{t.desc}</p>
        <div className="tc-ex">
          {t.ex.map(([cls, line], i) => (
            <div key={i} className={cls}>{line}</div>
          ))}
        </div>
      </div>
    </div>
  );
}

function ToolsSection() {
  return (
    <section id="tools" className="section">
      <div className="wrap-tight">
        <Eyebrow num="02">The four tools</Eyebrow>
        <h2 className="h-2" style={{ margin: '18px 0 10px' }}>Four verbs. That's the whole API.</h2>
        <p className="lede" style={{ marginBottom: 30 }}>
          One tool writes, three read. Arguments marked <span className="mono">?</span> are optional — the common path is a
          single string in, relevant memory out.
        </p>
        <div className="tool-grid">
          {TOOLS.map((t) => <ToolCard key={t.name} t={t} />)}
        </div>
      </div>
    </section>
  );
}

// ---------- Wire it up ----------

const STEPS = {
  stdio: [
    ['install', 'pip install "continuum-mcp[mcp,postgres,embed]"'],
    ['migrate', 'python -m continuum.db.migrate --dsn "$CONTINUUM_DB_DSN"        # Postgres + pgvector, one time'],
    ['wire',    'claude mcp add continuum -e CONTINUUM_DB_DSN="$CONTINUUM_DB_DSN" -- continuum-mcp'],
    ['verify',  'claude mcp list        # continuum ✓ — remember · recall · current · timeline'],
  ],
  http: [
    ['install', 'pip install "continuum-mcp[mcp,postgres,embed]"'],
    ['migrate', 'python -m continuum.db.migrate --dsn "$CONTINUUM_DB_DSN"        # Postgres + pgvector, one time'],
    ['serve',   'CONTINUUM_DB_DSN="$CONTINUUM_DB_DSN" continuum-mcp --http --port 8000        # endpoint: /mcp'],
    ['wire',    'claude mcp add -t http continuum http://127.0.0.1:8000/mcp'],
  ],
};

function WireSection() {
  const [transport, setTransport] = useState('stdio');
  const [copied, setCopied] = useState('');
  const copy = (key, text) => {
    navigator.clipboard?.writeText(text.replace(/\s+#.*$/, ''));
    setCopied(key); setTimeout(() => setCopied(''), 1400);
  };
  const steps = STEPS[transport];
  return (
    <section id="wire" className="section">
      <div className="wrap-tight">
        <Eyebrow num="03">Wire it up</Eyebrow>
        <h2 className="h-2" style={{ margin: '18px 0 10px' }}>From install to a remembering agent.</h2>
        <p className="lede" style={{ marginBottom: 22 }}>
          <strong>stdio</strong> is the simplest — the client launches the server on demand. Prefer a long-running
          service? Serve it over <strong>HTTP</strong> and connect by URL. Same four tools either way.
        </p>

        <div className="transport-tabs">
          <button className={transport === 'stdio' ? 'on' : ''} onClick={() => setTransport('stdio')}>stdio</button>
          <button className={transport === 'http' ? 'on' : ''} onClick={() => setTransport('http')}>HTTP</button>
        </div>

        <div className="ending-shell">
          {steps.map(([key, cmd]) => (
            <div key={key} className="ending-cmd">
              <span className="prompt mono">$</span>
              <code className="mono">{cmd}</code>
              <button className="ending-copy mono" onClick={() => copy(key, cmd)}>
                {copied === key ? '✓ copied' : 'copy'}
              </button>
            </div>
          ))}
        </div>

        <p className="note-line">
          <code>$CONTINUUM_DB_DSN</code> is your Postgres URL, e.g.{' '}
          <code>postgresql://user@localhost:5432/continuum</code>. Embeddings run locally on bge-m3 — set{' '}
          <code>CONTINUUM_MCP_EMBEDDINGS=0</code> for a sparse, zero-download start.
        </p>
      </div>
    </section>
  );
}

// ---------- Under the hood ----------

const HOOD = [
  ['◆', 'Postgres + pgvector', 'The durable store. HNSW index over halfvec embeddings, tuned ef_search — the same engine validated across the recall curves.'],
  ['⧉', 'Hybrid retrieval', 'Dense bge-m3 vectors and BM25 lexical search, fused with Reciprocal Rank Fusion. Matches on meaning and on exact tokens.'],
  ['⏱', 'Bi-temporal', 'Every fact carries valid-time and transaction-time. current and timeline reconstruct what held, and when.'],
  ['⊘', 'Live-row invalidation', 'Superseded facts are retired in place, not deleted — so recall stays clean while history stays intact.'],
  ['⌂', 'Local by default', 'bge-m3 runs on your machine; memory needs no external API. Sparse mode skips the model download entirely.'],
  ['✦', 'Optional supersession', 'Opt-in LLM decider (gpt-4o-mini via OpenRouter) resolves contradictions. Off by default; refuses to run without a key.'],
];

function HoodSection() {
  return (
    <section id="hood" className="section">
      <div className="wrap-tight">
        <Eyebrow num="04">Under the hood</Eyebrow>
        <h2 className="h-2" style={{ margin: '18px 0 24px' }}>A thin tool surface over a real memory engine.</h2>
        <div className="hood-grid">
          {HOOD.map(([ico, t, d]) => (
            <div className="hood-item" key={t}>
              <div className="hi-ico mono">{ico}</div>
              <div className="hi-t">{t}</div>
              <div className="hi-d">{d}</div>
            </div>
          ))}
        </div>
      </div>
    </section>
  );
}

// ---------- Clients ----------

function ClientsSection() {
  const cfg = `{
  "mcpServers": {
    "continuum": {
      "command": "continuum-mcp",
      "env": {
        "CONTINUUM_DB_DSN": "postgresql://user@localhost:5432/continuum"
      }
    }
  }
}`;
  const [copied, setCopied] = useState(false);
  return (
    <section id="clients" className="section">
      <div className="wrap-tight">
        <Eyebrow num="05">Clients</Eyebrow>
        <h2 className="h-2" style={{ margin: '18px 0 10px' }}>Any MCP client connects.</h2>
        <p className="lede" style={{ marginBottom: 24 }}>
          Claude Code registers it with one command; Claude Desktop and Cursor take a small JSON block in their config.
        </p>
        <div className="client-row">
          {['Claude Code', 'Claude Desktop', 'Cursor'].map((c) => (
            <div className="client-pill" key={c}><span className="cp-dot" />{c}</div>
          ))}
        </div>
        <div className="code-block">
          <div className="code-tab">
            <span className="path">claude_desktop_config.json</span>
            <button className="ending-copy mono" style={{ padding: '2px 8px' }}
              onClick={() => { navigator.clipboard?.writeText(cfg); setCopied(true); setTimeout(() => setCopied(false), 1400); }}>
              {copied ? '✓ copied' : 'copy'}
            </button>
          </div>
          <pre style={{ color: 'var(--tx-1)' }}>{cfg}</pre>
        </div>
        <p className="note-line">
          Restart the client and the four tools appear. For a shared HTTP deployment, register the URL instead:{' '}
          <code>claude mcp add -t http continuum http://your-host:8000/mcp</code>.
        </p>
      </div>
    </section>
  );
}

// ---------- CTA / footer ----------

function CTASection() {
  const [copied, setCopied] = useState(false);
  const cmd = 'pip install "continuum-mcp[mcp,postgres,embed]"';
  return (
    <section id="start" className="section ending-section">
      <div className="wrap-tight" style={{ textAlign: 'center' }}>
        <Eyebrow num="06">Start</Eyebrow>
        <h2 className="h-1 serif" style={{ margin: '18px 0 14px' }}>
          Give your agent a memory.
        </h2>
        <p className="lede" style={{ margin: '0 auto 28px', maxWidth: 560 }}>
          One package, four tools, your own Postgres. Open source, MIT licensed.
        </p>
        <div className="ending-shell" style={{ maxWidth: 640, margin: '0 auto 28px' }}>
          <div className="ending-cmd">
            <span className="prompt mono">$</span>
            <code className="mono">{cmd}</code>
            <button className="ending-copy mono" onClick={() => { navigator.clipboard?.writeText(cmd); setCopied(true); setTimeout(() => setCopied(false), 1400); }}>
              {copied ? '✓ copied' : 'copy'}
            </button>
          </div>
        </div>
        <div className="ending-actions" style={{ justifyContent: 'center' }}>
          <a href="https://pypi.org/project/continuum-mcp/" target="_blank" rel="noopener" className="btn btn-primary">PyPI →</a>
          <a href="https://github.com/Genkryptos/Continuum" target="_blank" rel="noopener" className="btn btn-ghost mono" style={{ fontSize: 13 }}>GitHub</a>
          <a href="../continuum/" className="btn btn-ghost mono" style={{ fontSize: 13 }}>The engine behind it →</a>
        </div>
      </div>
    </section>
  );
}

function Footer() {
  return (
    <footer className="footer">
      <div className="wrap">
        <div className="footer-grid">
          <div>
            <a href="../continuum/" className="nav-brand" style={{ fontSize: 16 }}>
              <div className="mark"></div>
              Continuum · MCP
            </a>
            <p style={{ marginTop: 14, fontSize: 13, color: 'var(--tx-2)', maxWidth: 320, lineHeight: 1.6 }}>
              A Model Context Protocol server exposing Continuum's memory as remember, recall, current and timeline.
            </p>
            <div className="mono" style={{ marginTop: 18, fontSize: 11, color: 'var(--tx-3)' }}>
              MIT · Python 3.11+ · continuum-mcp v2.0.3
            </div>
          </div>
          <div>
            <h4>Install</h4>
            <ul>
              <li><a href="https://pypi.org/project/continuum-mcp/" target="_blank" rel="noopener">PyPI</a></li>
              <li><a href="#wire">Wire it up</a></li>
              <li><a href="#clients">Client config</a></li>
              <li><a href="#tools">Tool reference</a></li>
            </ul>
          </div>
          <div>
            <h4>Continuum</h4>
            <ul>
              <li><a href="../continuum/">The engine</a></li>
              <li><a href="../continuum/#benchmarks">Benchmarks</a></li>
              <li><a href="../continuum/#pipeline">Architecture</a></li>
              <li><a href="#hood">Under the hood</a></li>
            </ul>
          </div>
          <div>
            <h4>Code</h4>
            <ul>
              <li><a href="https://github.com/Genkryptos/Continuum" target="_blank" rel="noopener">GitHub</a></li>
              <li><a href="https://github.com/Genkryptos/Continuum/issues" target="_blank" rel="noopener">Issues</a></li>
              <li><a href="https://github.com/Genkryptos/Continuum/blob/main/LICENSE" target="_blank" rel="noopener">License</a></li>
            </ul>
          </div>
        </div>
        <div className="signoff">
          <span>© 2026 Continuum · open source</span>
          <span>$ claude mcp add continuum &nbsp;<span style={{ color: 'var(--accent)' }}>↗</span></span>
        </div>
      </div>
    </footer>
  );
}

// ---------- App ----------

function App() {
  const [scrolled, setScrolled] = useState(false);
  const [activeId, setActiveId] = useState('');
  useEffect(() => {
    const onScroll = () => setScrolled(window.scrollY > 8);
    window.addEventListener('scroll', onScroll, { passive: true });
    return () => window.removeEventListener('scroll', onScroll);
  }, []);
  useEffect(() => {
    const ids = ['what', 'tools', 'wire', 'hood', 'clients'];
    const sections = ids.map((id) => document.getElementById(id)).filter(Boolean);
    if (!sections.length) return;
    const io = new IntersectionObserver(
      (entries) => { for (const e of entries) if (e.isIntersecting) setActiveId(e.target.id); },
      { rootMargin: '-40% 0px -55% 0px', threshold: 0 },
    );
    sections.forEach((s) => io.observe(s));
    return () => io.disconnect();
  }, []);
  return (
    <React.Fragment>
      <NavBar scrolled={scrolled} activeId={activeId} />
      <main>
        <Hero />
        <WhatSection />
        <ToolsSection />
        <WireSection />
        <HoodSection />
        <ClientsSection />
        <CTASection />
      </main>
      <Footer />
    </React.Fragment>
  );
}

ReactDOM.createRoot(document.getElementById('root')).render(<App />);
