// Sections.jsx — landing-page sections, themed via CSS vars on the wrapping div.

function Nav({ active }) {
  // On sub-pages, in-page anchors must point back at index.html;
  // on the landing itself, keep them as bare hashes to avoid full reloads.
  const onLanding = !active;
  const root = onLanding ? '' : 'index.html';
  return (
    <div className="nav">
      <div className="wrap nav-inner">
        <a href="index.html" className="brand">
          <div className="brand-mark">S</div>
          <div className="brand-name">sourceweaver</div>
        </a>
        <div className="nav-links">
          <a href={`${root}#how`}>How it works</a>
          <a href={`${root}#pipelines`}>Pipelines</a>
          <a href={`${root}#self`}>Self-built</a>
          <a href={`${root}#audience`}>Who it’s for</a>
          <a href="cli.html" className={active === 'cli' ? 'active' : ''}>CLI</a>
          <a href="compare.html" className={active === 'compare' ? 'active' : ''}>Compare</a>
        </div>
        <div className="nav-spacer" />
      </div>
    </div>
  );
}

function AppShellFrame() {
  const ref = React.useRef(null);
  const [height, setHeight] = React.useState(620);
  React.useEffect(() => {
    function onMsg(e) {
      const d = e.data;
      if (d && d.type === '__sw_app_height' && typeof d.height === 'number') {
        setHeight(d.height);
      }
    }
    window.addEventListener('message', onMsg);
    return () => window.removeEventListener('message', onMsg);
  }, []);
  // Push the current theme into the iframe as soon as it loads.
  function onLoad() {
    try {
      const theme = document.documentElement.dataset.theme || 'terminal';
      ref.current.contentWindow.postMessage({ type: '__sw_set_theme', theme }, '*');
    } catch {}
  }
  const theme = (typeof document !== 'undefined' && document.documentElement.dataset.theme) || 'terminal';
  return (
    <iframe
      ref={ref}
      data-sw-app="true"
      src={`app.html?theme=${theme}&embed=1&tab=workspace&subtab=activity`}
      title="SourceWeaver app preview"
      onLoad={onLoad}
      style={{
        width: '100%',
        height: height + 'px',
        border: 0,
        background: 'transparent',
        display: 'block',
      }}
      scrolling="no"
    />
  );
}

function Hero() {
  return (
    <section className="hero hero-stacked">
      <div className="wrap">
        <div className="hero-text">
          <div className="hero-stamp">
            <span className="hero-stamp-dot" />
            <span>v0.3 · self-hosted alpha</span>
          </div>
          <h1>
            An AI pipeline that <span className="accent">ships features</span> while you sleep.
          </h1>
          <p className="hero-sub">
            Define a feature. Approve it. The pipeline researches, plans, executes, reviews — and opens the PR. Self-hosted. Self-building. Yours.
          </p>
          <div className="hero-actions">
            <a className="btn btn-primary" href="#how">See how it works</a>
          </div>
        </div>
        <HeroShellMaybe />
      </div>
    </section>
  );
}

// Skip rendering the embedded app mock on phones. It loads a separate
// page-sized iframe of the product UI, which is heavy and gets cramped
// below ~720px wide; the marketing copy carries the page on its own.
function HeroShellMaybe() {
  const [show, setShow] = React.useState(() =>
    typeof window === 'undefined' ? true : !window.matchMedia('(max-width: 720px)').matches
  );
  React.useEffect(() => {
    const mq = window.matchMedia('(max-width: 720px)');
    const onChange = () => setShow(!mq.matches);
    mq.addEventListener('change', onChange);
    return () => mq.removeEventListener('change', onChange);
  }, []);
  if (!show) return null;
  return (
    <div className="hero-shell">
      <AppShellFrame />
    </div>
  );
}

function Strip() {
  return (
    <div className="strip">
      <div className="wrap strip-inner">
        <span>Stack</span>
        <span>Claude Code</span>
        <span>OpenCode</span>
        <span>MCP</span>
        <span>PostgreSQL</span>
        <span>.NET</span>
        <span>Docker</span>
      </div>
    </div>
  );
}

function HowItWorks() {
  return (
    <section className="section" id="how">
      <div className="wrap">
        <div className="section-head">
          <div>
            <div className="section-eyebrow">How it works</div>
            <h2>Scope it. Break it down. Ship it.</h2>
          </div>
          <p className="section-blurb">
            You write the Feature. SourceWeaver asks the questions a senior engineer would ask, generates the child tickets, and runs each one through a real pipeline — research, plan, execute, review, PR. Every stage is YAML you own.
          </p>
        </div>
        <div className="flow">
          <div className="flow-card">
            <div className="flow-step">01 · Scope</div>
            <h3>Write a Feature. SourceWeaver clarifies it.</h3>
            <p>Drop a Feature into the workspace with a title and acceptance criteria. SourceWeaver clarifies the gaps with you, then generates the Tasks and Bugs to cover the work.</p>
            <div className="flow-card-foot">clarify → tickets → ready to run</div>
          </div>
          <div className="flow-card">
            <div className="flow-step">02 · Build</div>
            <h3>Each ticket runs the pipeline.</h3>
            <p>Tasks: research → plan → expand → execute → review → PR. Bugs swap research for diagnose and add a regression-test validate step. Plans are split into independent units that execute in parallel. You watch it stream live.</p>
            <div className="flow-card-foot">workers claim → stream → open PR</div>
          </div>
          <div className="flow-card">
            <div className="flow-step">03 · Land</div>
            <h3>Merge queue with self-healing.</h3>
            <p>PRs queue up: rebase, gate on CI, fast-forward. Conflicts trigger an AI rebase and force-push-with-lease. Overwatch sweeps for stuck stages, dead workers, and broken queues every minute. Once the last child PR merges, SourceWeaver opens the feature PR.</p>
            <div className="flow-card-foot">queue → conflict-resolve → overwatch → merged</div>
          </div>
        </div>
      </div>
    </section>
  );
}

function WorkspaceSection() {
  return (
    <section className="section" id="workspace">
      <div className="wrap">
        <div className="section-head">
          <div>
            <div className="section-eyebrow">The workspace</div>
            <h2>Features. Tasks. Bugs. The same primitives, but they actually do work.</h2>
          </div>
          <p className="section-blurb">
            Every item is a node in a pipeline graph. Three-panel layout: document tree on the left, a real markdown editor with EDIT / SPLIT / PREVIEW in the middle, context-aware chat on the right. Flip to the board to watch tickets move through stages. The same pane the agent reads when it picks up the work.
          </p>
        </div>
        <TaskEditView />
      </div>
    </section>
  );
}

function MergeQueueSection() {
  return (
    <section className="section" id="mergequeue">
      <div className="wrap">
        <div className="section-head">
          <div>
            <div className="section-eyebrow">
              Merge queue
              <span className="optional-badge">optional</span>
            </div>
            <h2>A serialized merge queue that heals itself.</h2>
          </div>
          <p className="section-blurb">
            Optional. Off by default — review and merge PRs yourself, or flip on the queue and let it serialize them. Every queued PR is rebased onto its base, gated on CI, then fast-forwarded. When a rebase hits conflicts or CI goes red, recovery workflows fire automatically — diagnose, fix, retry.          </p>
        </div>
        <MergeQueue />
      </div>
    </section>
  );
}

function PipelinesSection() {
  return (
    <section className="section" id="pipelines">
      <div className="wrap">
        <div className="section-head">
          <div>
            <div className="section-eyebrow">Pipelines</div>
            <h2>Workflow-driven, not chat-driven.</h2>
          </div>
          <p className="section-blurb">
            Workflows are YAML. Stages run on AI or on the API, with timeouts and retries declared inline. Below is a summarized view of the workflow that runs against an approved Task. Hover any stage.
          </p>
        </div>
        <YamlBlock />
      </div>
    </section>
  );
}

function SelfBuilt() {
  return (
    <section className="self" id="self">
      <div className="wrap">
        <div className="section-head">
          <div>
            <div className="section-eyebrow">Proof</div>
            <h2>This product builds itself. The site’s backend included.</h2>
          </div>
          <p className="section-blurb">
            We don’t demo on a toy repo. SourceWeaver’s own backlog runs through SourceWeaver. If it can’t ship its own features, you’d be the first to know.
          </p>
        </div>
        <div className="self-grid">
          <div>
            <div className="self-pr">
              <div className="self-pr-head">most recent self-built PR</div>
              <div className="self-pr-title">#716 · Settings forms silently swallow failed PUT/POST responses</div>
              <div className="self-pr-quote">Opened by sourceweaver-bot. 2 files, +129 / −1. CI green. Merged 37 minutes after approval.</div>
            </div>
          </div>
          <div>
            <p style={{ fontSize: 17, lineHeight: 1.55, textWrap: 'pretty' }}>
              Every feature in the changelog has a link to the PR that built it. Every PR has a link to the work item that scoped it. Every work item has a stream of the agent that wrote the code. No black boxes. Lead time measured from the first child task PR opened to the feature PR landing on main — 6.6 child PRs per feature on average.
            </p>
            <div className="self-stat-row">
              <div>
                <div className="self-stat-num">21</div>
                <div className="self-stat-label">features shipped end-to-end</div>
              </div>
              <div>
                <div className="self-stat-num">627</div>
                <div className="self-stat-label">self-built PRs merged</div>
              </div>
              <div>
                <div className="self-stat-num">2.1d</div>
                <div className="self-stat-label">median feature lead time</div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </section>
  );
}

function AudienceSplit() {
  return (
    <section className="section" id="audience">
      <div className="wrap">
        <div className="section-head">
          <div>
            <div className="section-eyebrow">Who it’s for</div>
            <h2>Solo builders shipping alone. Teams that can’t touch the cloud.</h2>
          </div>
          <p className="section-blurb">
            The same binary runs on a Hetzner box and inside an air-gapped VPC. Two audiences, one product. Pick the column that sounds like you.
          </p>
        </div>
        <div className="split">
          <div className="split-col">
            <h3>Solo devs and indie hackers</h3>
            <p className="split-vignette">
              You’re shipping three side projects alone. You watched friends’ teams add five engineers and quadruple velocity, and you’re tired of pasting context into a chat window for the tenth time today.
            </p>
            <div className="split-group">Your day with it</div>
            <ul>
              <li>Dispatch a backlog before bed; review PRs over coffee.</li>
              <li>Schedule recurring workflows — nightly bug sweeps, weekly dependency bumps.</li>
            </ul>
            <div className="split-group">Your setup</div>
            <ul>
              <li>One <code>docker-compose up</code>. Bring your AI key from anywhere.</li>
              <li>Fork the YAML. It’s your workflow — edit any stage, prompt, or gate.</li>
            </ul>
            <div className="split-group">Your guardrails</div>
            <ul>
              <li>Approval gates and stage timeouts between every step — no runaway loops.</li>
              <li>Cost ceilings per pipeline. Kill any run from the UI.</li>
            </ul>
            <p className="split-outcome">
              <strong>By end of week one:</strong> a backlog that runs itself overnight, and pull requests waiting for review when you sit down in the morning.
            </p>
          </div>
          <div className="split-col">
            <h3>Teams with sovereignty requirements</h3>
            <p className="split-vignette">
              You’re an engineering lead at a regulated shop — defense, fintech, healthcare, gov — where SaaS AI tools fail the security review and your developers are asking what you’re going to do about it.
            </p>
            <div className="split-group">Your perimeter</div>
            <ul>
              <li>Fully self-hosted. No phone-home telemetry.</li>
              <li>Air-gap install supported. Same binary online or off.</li>
              <li>MCP tools you control — agents see only what you expose.</li>
            </ul>
            <div className="split-group">Your access controls</div>
            <ul>
              <li>Per-repo, per-pipeline RBAC. SSO via your IdP.</li>
              <li>Audit log of every agent action and approval gate.</li>
            </ul>
            <div className="split-group">Your integrations</div>
            <ul>
              <li>Bring your AI provider — Anthropic, OpenAI, or a self-hosted endpoint.</li>
              <li>Public MCP server — drive SourceWeaver from claude.ai chat, Claude Code, or any MCP client.</li>
            </ul>
            <p className="split-outcome">
              <strong>By end of week one:</strong> a working pipeline inside your VPC, approved by security, with one team running a real feature end-to-end.
            </p>
          </div>
        </div>
      </div>
    </section>
  );
}

function DiffGrid() {
  const cells = [
    ['01', 'Self-hosted, self-contained', 'Your code, your infra, your data. Nothing leaves the box. No vendor lock-in.'],
    ['02', 'Self-building', 'SourceWeaver develops itself. Public proof, every release.'],
    ['03', 'Workflow over chat', 'Declarative YAML pipelines. Versioned. Diffable. Reviewable.'],
    ['04', 'Human-in-the-loop', 'Approval gates between every stage. Manual, automatic, or conditional.'],
    ['05', 'Real engineering integration', 'Git branches. Real PRs. CI. Auto-deploy. Not a chat log.'],
    ['06', 'Live streams, not status pages', 'Watch the agent read, plan, and write. SignalR over a real socket.'],
    ['07', 'CI-aware retry loop', 'When execute fails, SourceWeaver triages — fix the bug, replan, or flag a flake — and tries again. Up to five attempts before it raises a blocker for you.'],
    ['08', 'Dynamic parallel stages', 'One feature, many plans. Each plan fans out into its own execution on its own branch. Independent work runs in parallel; the merge queue sorts it out.'],
  ];
  return (
    <section className="section" id="diff">
      <div className="wrap">
        <div className="section-head">
          <div>
            <div className="section-eyebrow">Differentiators</div>
            <h2>What you actually get — and what you don’t.</h2>
          </div>
          <p className="section-blurb">
            Not another assistant. Not another chat. SourceWeaver is closer to a CI system that happens to write code than a copilot that happens to ship.
          </p>
        </div>
        <div className="diffgrid">
          {cells.map(([n, h, p]) => (
            <div key={n} className="diff-cell">
              <div className="diff-icon">{n}</div>
              <h4>{h}</h4>
              <p>{p}</p>
            </div>
          ))}
        </div>
      </div>
    </section>
  );
}

function InterestCTA() {
  const [email, setEmail] = React.useState('');
  const [note, setNote] = React.useState('');
  const [state, setState] = React.useState('idle'); // idle | sending | ok | err
  const [errMsg, setErrMsg] = React.useState('');

  async function onSubmit(e) {
    e.preventDefault();
    setState('sending');
    setErrMsg('');
    try {
      const res = await fetch('/api/interest', {
        method: 'POST',
        headers: { 'content-type': 'application/json' },
        body: JSON.stringify({ email, note }),
      });
      if (!res.ok) {
        const data = await res.json().catch(() => ({}));
        throw new Error(data.error || `http_${res.status}`);
      }
      setState('ok');
    } catch (err) {
      setState('err');
      setErrMsg(err.message || 'unknown');
    }
  }

  return (
    <section className="cta" id="interest">
      <div className="wrap">
        <div className="section-eyebrow" style={{ marginBottom: 14 }}>Closed alpha</div>
        <h2>Register interest.</h2>
        <p className="cta-sub">SourceWeaver isn’t open yet. Drop your email and we’ll reach out when we open up access.</p>
        {state === 'ok' ? (
          <div className="interest-ok">
            <span className="accent">✓</span> You’re on the list. We’ll be in touch.
          </div>
        ) : (
          <form className="interest-form" onSubmit={onSubmit}>
            <input
              type="email"
              required
              placeholder="you@company.com"
              value={email}
              onChange={(e) => setEmail(e.target.value)}
              disabled={state === 'sending'}
              autoComplete="email"
            />
            <textarea
              rows={3}
              placeholder="What would you use it for? (optional)"
              value={note}
              onChange={(e) => setNote(e.target.value)}
              disabled={state === 'sending'}
              maxLength={1000}
            />
            <button type="submit" className="btn btn-primary" disabled={state === 'sending' || !email}>
              {state === 'sending' ? 'Sending…' : 'Register interest'}
            </button>
            {state === 'err' && (
              <div className="interest-err">Couldn’t submit ({errMsg}). Try again in a moment.</div>
            )}
          </form>
        )}
      </div>
    </section>
  );
}

function Footer() {
  return (
    <footer className="foot">
      <div className="wrap">
        <div className="foot-grid">
          <div className="foot-brand">
            <div className="brand">
              <div className="brand-mark">S</div>
              <div className="brand-name">SourceWeaver</div>
            </div>
            <div className="foot-tag">An AI pipeline that ships features while you sleep. Self-hosted. Self-building.</div>
          </div>
          <div className="foot-col">
            <h5>Product</h5>
            <a href="#how">How it works</a>
            <a href="#pipelines">Pipelines</a>
            <a href="#self">Self-built</a>
          </div>
        </div>
        <div className="foot-bottom">
          <span>© 2026 SourceWeaver</span>
          <span>built by SourceWeaver</span>
        </div>
      </div>
    </footer>
  );
}

function Landing() {
  return (
    <div className="shell">
      <Nav />
      <Hero />
      <Strip />
      <HowItWorks />
      <WorkspaceSection />
      <PipelinesSection />
      <MergeQueueSection />
      <SelfBuilt />
      <AudienceSplit />
      <DiffGrid />
      <InterestCTA />
      <Footer />
    </div>
  );
}

Object.assign(window, { Landing });
