// ─────── BUFFERS: the actual content for each "file" ───────

function SectionHead({ idx, title, subt }) {
  return (
    <div className="h-section">
      <span className="idx">§ {idx}</span>
      <span className="title">{title}</span>
      {subt && <span className="subt">{subt}</span>}
    </div>
  );
}

/* ───── projects.md ───── */
function ProjectsBuffer({
  deps,
  focusIdx,
  setFocusIdx,
  expanded,
  setExpanded,
  searchQuery,
  activeSearchProjectIdx,
}) {
  const { data, utils } = deps;
  return (
    <>
      <div className="hero">
        <pre className="hero-ascii">{`
██╗      ██████╗ ██╗   ██╗███████╗    ███████╗ █████╗ ██╗  ██╗ █████╗      ██╗
██║     ██╔═══██╗██║   ██║██╔════╝    ██╔════╝██╔══██╗██║  ██║██╔══██╗     ██║
██║     ██║   ██║██║   ██║█████╗      ███████╗███████║███████║███████║     ██║
██║     ██║   ██║╚██╗ ██╔╝██╔══╝      ╚════██║██╔══██║██╔══██║██╔══██║██   ██║
███████╗╚██████╔╝ ╚████╔╝ ███████╗ ██╗███████║██║  ██║██║  ██║██║  ██║╚█████╔╝
╚══════╝ ╚═════╝   ╚═══╝  ╚══════╝ ╚═╝╚══════╝╚═╝  ╚═╝╚═╝  ╚═╝╚═╝  ╚═╝ ╚════╝
        `}</pre>
        <h1 className="hero-name">
          ML infrastructure engineer who cares more about <em>fast loops</em> than the model on top.
        </h1>
        <p className="hero-sub">
          Currently doing an M.Sc. at <code>Edinburgh</code>. Previously cut late hospital
          checkouts from ~95% to ~30%, sped up Verilog generation by 24×, and shipped a Lambda
          routing layer handling ~10k daily mobile users. The bullets below are load-bearing.
        </p>
        <div className="hero-help">
          <span className="pulse" />
          <span>
            new here? press <kbd>?</kbd> for the keymap — or click any project
          </span>
        </div>
      </div>

      <SectionHead
        idx="01"
        title="Selected projects"
        subt={`${data.projects.length} entries — j/k to browse, Enter to expand`}
      />

      <div className="proj-grid">
        {data.projects.map((p, i) => {
          const isFocus = i === focusIdx;
          const isOpen = expanded === p.id;
          const q = searchQuery && searchQuery.trim();
          const isSearchHit =
            !!q && (p.name + p.blurb + p.stack.join(' ')).toLowerCase().includes(q.toLowerCase());
          const isSearchActive = i === activeSearchProjectIdx;
          return (
            <div
              key={p.id}
              className={
                'proj' +
                (isFocus ? ' focus' : '') +
                (isSearchHit ? ' search-hit' : '') +
                (isSearchActive ? ' search-active' : '')
              }
              onClick={() => {
                setFocusIdx(i);
                setExpanded(isOpen ? null : p.id);
              }}
              data-proj-idx={i}
              data-focus={isFocus ? 'true' : undefined}
            >
              <div className="proj-idx">[{String(i + 1).padStart(2, '0')}]</div>
              <div className="proj-body">
                <h3>{utils.renderSearchText(p.name, searchQuery, isSearchActive)}</h3>
                <div className="desc">{utils.renderSearchText(p.blurb, searchQuery, isSearchActive)}</div>
                <div className="tags">
                  {p.stack.map((s) => (
                    <span key={s} className="tag">
                      {utils.renderSearchText(s, searchQuery, isSearchActive)}
                    </span>
                  ))}
                </div>
                {isOpen && (
                  <div className="proj-detail">
                    <div className="highlights">
                      {p.highlights.map((h, j) => (
                        <div key={j} className="hl">
                          <span className="bullet">▸</span>
                          <span>{utils.renderInline(h)}</span>
                        </div>
                      ))}
                    </div>
                    <div className="links">
                      {(p.links && p.links.length ? p.links : [{ label: 'source', url: p.link }]).map((l, k) => (
                        <a key={k} href={l.url} target="_blank" rel="noreferrer">
                          → {l.label}
                        </a>
                      ))}
                      <span style={{ color: 'var(--fg-muted)' }}>· {p.year}</span>
                    </div>
                  </div>
                )}
              </div>
              <div className="proj-meta">
                <div>{p.year}</div>
                <div className="arrow">{isOpen ? '▾' : '▸'}</div>
              </div>
            </div>
          );
        })}
      </div>

      <SectionHead idx="02" title="Numbers that sound made up" subt="they're not" />
      <div className="metrics">
        {data.metrics.map((m, i) => (
          <div key={i} className="metric">
            <div className="tag">{m.tag}</div>
            <div className="big">
              {m.big}
              <span className="unit">{m.unit}</span>
            </div>
            <div className="label">{m.label}</div>
          </div>
        ))}
      </div>
    </>
  );
}

/* ───── experience.md ───── */
function ExperienceBuffer({ deps, focusIdx, setFocusIdx }) {
  const { data, utils } = deps;
  return (
    <>
      <div className="hero" style={{ padding: '28px 0 20px' }}>
        <h1 className="hero-name" style={{ fontSize: 52 }}>
          Three years. Two countries. <em>Several</em> production incidents I'd rather not relive.
        </h1>
        <p className="hero-sub">
          A reverse-chronological accounting of paid work, with the highlights my manager would
          grudgingly confirm.
        </p>
      </div>

      <SectionHead
        idx="01"
        title="Work"
        subt={`${data.experience.length} entries — j/k to browse, most recent first`}
      />
      <div className="exp-list">
        {data.experience.map((e, i) => {
          const isFocus = i === focusIdx;
          return (
            <div
              key={`${e.role}-${e.org}-${e.dates}`}
              className={'exp' + (isFocus ? ' focus' : '')}
              role="button"
              tabIndex={0}
              onClick={() => setFocusIdx && setFocusIdx(i)}
              onKeyDown={(ev) => {
                if (ev.key === 'Enter' || ev.key === ' ') {
                  ev.preventDefault();
                  setFocusIdx && setFocusIdx(i);
                }
              }}
              data-exp-idx={i}
              data-focus={isFocus ? 'true' : undefined}
            >
              <div className="when">
                <div className="dates">{e.dates}</div>
                <div className="loc">{e.loc}</div>
              </div>
              <div className="role">
                <h4>{e.role}</h4>
                <div className="org">@ {e.org}</div>
                <ul className="bullets">
                  {e.bullets.map((b, j) => (
                    <li key={j}>{utils.renderInline(b)}</li>
                  ))}
                </ul>
              </div>
            </div>
          );
        })}
      </div>

      <SectionHead idx="02" title="Education" />
      <div className="exp-list">
        {data.education.map((e, i) => (
          <div key={`${e.school}-${e.dates}`} className="exp">
            <div className="when">
              <div className="dates">{e.dates}</div>
            </div>
            <div className="role">
              <h4>{e.school}</h4>
              <div className="org">{e.degree}</div>
              {e.extra && (
                <ul className="bullets">
                  <li>{e.extra}</li>
                </ul>
              )}
            </div>
          </div>
        ))}
      </div>
    </>
  );
}

/* ───── about.md ───── */
function AboutBuffer({ deps }) {
  const { data } = deps;
  return (
    <>
      <SectionHead idx="00" title="~/about" subt=":help me" />
      <div className="about-grid">
        <div className="about-prose">
          <p>
            I build <em>the infrastructure that ML runs on</em>, the systems that stay up so the
            models can ship. Most of my best work looks like "we removed a thing": a queue, a
            vendor, a class of bug, four minutes of compile time. I care more about the loop being
            fast and the failure modes being legible than about the model on top.
          </p>
          <p>
            Right now I'm at <em>the University of Edinburgh</em> doing an M.Sc., spending
            suspicious amounts of time exactly where I want to be: distributed systems,
            reinforcement learning, and the plumbing underneath ML. Lately that means an{' '}
            <em>RLVR fine-tuning pipeline</em> (GRPO, sandboxed parallel reward execution, held-out
            eval) and a <em>tile-based GPU kernel DSL in Zig</em>: Triton's programming model,
            Zig's comptime, no separate compiler.
          </p>
          <p>
            Before that: <em>Max Healthcare</em> (Redis, FastAPI, AWS, the serverless trifecta) and
            <em> Infineon</em> (Rust, Verilog, silicon tooling that compiled faster than the silicon
            team could believe).
          </p>
          <p>
            I like small, fast things. Monospace fonts. Cold coffee. <em>Neovim</em>, obviously.
            You're in it.
          </p>
        </div>

        <div className="about-sidebar">
          <div className="sidebar-block">
            <h5>:set identity</h5>
            <div className="row">
              <span className="k">name</span>
              <span className="v">{data.name}</span>
            </div>
            <div className="row">
              <span className="k">role</span>
              <span className="v">M.Sc. CS · SWE</span>
            </div>
            <div className="row">
              <span className="k">based</span>
              <span className="v">{data.location}</span>
            </div>
            <div className="row">
              <span className="k">status</span>
              <span className="v" style={{ color: 'var(--green)' }}>
                ● open to roles starting Sep 2026
              </span>
            </div>
          </div>

          <div className="sidebar-block">
            <h5>:set skills</h5>
            <div className="skill-grid">
              {data.skills.map((s, i) => (
                <React.Fragment key={i}>
                  <div className="k">{s.k}</div>
                  <div className="v">
                    {s.v.map((t, j) => {
                      const cls =
                        s.hot === 0
                          ? 'hot'
                          : Array.isArray(s.hot) && s.hot.includes(j)
                            ? j < 2
                              ? 'hot'
                              : 'warm'
                            : '';
                      return (
                        <span key={t} className={'skill ' + cls}>
                          {t}
                        </span>
                      );
                    })}
                  </div>
                </React.Fragment>
              ))}
            </div>
          </div>

          <div className="sidebar-block">
            <h5>:set elsewhere</h5>
            <div className="row">
              <span className="k">github</span>
              <a className="v" href={`https://${data.github}`}>
                {data.github.replace('github.com/', '@')}
              </a>
            </div>
            <div className="row">
              <span className="k">linkedin</span>
              <a className="v" href={`https://${data.linkedin}`}>
                {data.linkedin.replace('linkedin.com/in/', 'in/')}
              </a>
            </div>
            <div className="row">
              <span className="k">email</span>
              <a className="v" href={`mailto:${data.email}`}>
                {data.email}
              </a>
            </div>
          </div>
        </div>
      </div>
    </>
  );
}

/* ───── now.md ───── */
function NowBuffer({ deps }) {
  const { data } = deps;
  return (
    <>
      <SectionHead idx="00" title="~/now" subt={`updated April 2026`} />
      <div className="about-prose" style={{ paddingTop: 8 }}>
        <p>
          What I'm actually doing this month. If you've landed here from an email intro,
          <em> the "looking for" card is the one you want</em>.
        </p>
      </div>
      <div className="now-grid">
        {data.now.map((n, i) => (
          <div key={i} className="now-card">
            <div className="status">live</div>
            <h4>{n.title}</h4>
            <p>{n.body}</p>
            <span className="tag">#{n.tag}</span>
          </div>
        ))}
      </div>
    </>
  );
}

/* ───── writing.md ───── */
function WritingBuffer({ deps }) {
  const { posts, routing, utils } = deps;

  // initial state from URL hash: #writing/<slug>
  const initialFromHash = () => {
    const slug = routing.parseWritingSlug();
    if (!slug) return null;
    return posts.find((p) => p.slug === slug) || null;
  };
  const [selectedPost, setSelectedPost] = React.useState(initialFromHash);

  // keep URL in sync with selected post
  React.useEffect(() => {
    const target = routing.hashForBuffer('writing', selectedPost && selectedPost.slug);
    if (window.location.hash !== target) {
      history.replaceState(null, '', target);
    }
  }, [selectedPost]);

  // respond to hashchange (back/forward, pasted link)
  React.useEffect(() => {
    const onHash = () => {
      const { bufferId, slug } = routing.parseHash();
      if (bufferId !== 'writing') return;
      if (!slug) { setSelectedPost(null); return; }
      const p = posts.find((x) => x.slug === slug);
      if (p && (!selectedPost || selectedPost.slug !== slug)) setSelectedPost(p);
    };
    window.addEventListener('hashchange', onHash);
    return () => window.removeEventListener('hashchange', onHash);
  }, [posts, selectedPost]);

  // post view: b = back
  React.useEffect(() => {
    if (!selectedPost) return;
    const handler = (e) => {
      if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') return;
      if (e.key === 'b') {
        e.preventDefault();
        setSelectedPost(null);
      }
    };
    window.addEventListener('keydown', handler);
    return () => window.removeEventListener('keydown', handler);
  }, [selectedPost]);

  if (selectedPost) {
    return (
      <>
        <div className="post-nav">
          <button className="post-back-btn" onClick={() => setSelectedPost(null)}>
            ← writing.md
          </button>
          <span className="post-nav-hint">
            <kbd>b</kbd> back
          </span>
        </div>
        <div className="post-head">
          <h2 className="post-title-lg">{selectedPost.title}</h2>
          <div className="post-head-meta">
            <span className="post-date">{utils.formatPostDate(selectedPost.date)}</span>
            {(selectedPost.tags || []).map((t) => (
              <span key={t} className="tag">
                {t}
              </span>
            ))}
          </div>
        </div>
        <div
          className="post-body"
          dangerouslySetInnerHTML={{ __html: selectedPost.html }}
        />
      </>
    );
  }

  if (!posts.length) {
    return (
      <>
        <SectionHead idx="00" title="~/writing" subt="this buffer is empty" />
        <div className="writing-empty">
          <h3>No posts yet.</h3>
          <div style={{ marginTop: 8, fontSize: 13 }}>
            Add <code>.md</code> files to <code>notes/</code> and run{' '}
            <code>npm run build</code> to publish them here.
          </div>
          <div className="tombstone">
            {`┌────────────────────────────────────┐
│  here lies several drafts, 2025—   │
│  "gone too soon"                   │
└────────────────────────────────────┘`}
          </div>
        </div>
      </>
    );
  }

  return (
    <>
      <SectionHead
        idx="00"
        title="~/writing"
        subt={`${posts.length} post${posts.length !== 1 ? 's' : ''} — j/k to move, Enter to read`}
      />
      <div className="writing-list">
        {posts.map((post, i) => (
          <button
            key={post.slug}
            className="writing-post-btn"
            onClick={() => setSelectedPost(post)}
          >
            <div className="post-meta-line">
              <span className="post-date">{utils.formatPostDate(post.date)}</span>
              {(post.tags || []).map((t) => (
                <span key={t} className="tag">
                  {t}
                </span>
              ))}
            </div>
            <div className="post-title-line">{post.title}</div>
            {post.excerpt && <div className="post-excerpt-line">{post.excerpt}</div>}
          </button>
        ))}
      </div>
    </>
  );
}

/* ───── contact.md ───── */
function ContactBuffer({ deps, form, setForm, onSend, setMode, focusTick, focusAction }) {
  const { data } = deps;
  const objectRefs = React.useRef([]);
  const [activeObject, setActiveObject] = React.useState(3);
  const editable = new Set([3, 4, 5, 6]);

  const clampObject = (i) => Math.max(0, Math.min(7, i));

  const focusObject = (idx) => {
    const el = objectRefs.current[idx];
    if (!el || typeof el.focus !== 'function') return;
    el.focus();
    if (typeof el.setSelectionRange === 'function') {
      const pos = el.value.length;
      el.setSelectionRange(pos, pos);
    }
  };

  const findEditable = (from, dir) => {
    let i = from + dir;
    while (i >= 0 && i <= 7) {
      if (editable.has(i)) return i;
      i += dir;
    }
    return null;
  };

  React.useEffect(() => {
    if (focusTick <= 0) return;

    if (focusAction === 'move_next') {
      setActiveObject((i) => clampObject(i + 1));
      return;
    }
    if (focusAction === 'move_prev') {
      setActiveObject((i) => clampObject(i - 1));
      return;
    }

    const editAt = (idx) => {
      if (!editable.has(idx)) return;
      setActiveObject(idx);
      setMode('INSERT');
      setTimeout(() => focusObject(idx), 0);
    };

    if (focusAction === 'edit_current') {
      editAt(activeObject);
      return;
    }

    if (focusAction === 'edit_next') {
      const idx = findEditable(activeObject, 1);
      if (idx !== null) editAt(idx);
      return;
    }

    if (focusAction === 'edit_prev') {
      const idx = findEditable(activeObject, -1);
      if (idx !== null) editAt(idx);
      return;
    }

    if (focusAction === 'activate') {
      const el = objectRefs.current[activeObject];
      if (!el) return;
      if (editable.has(activeObject)) {
        editAt(activeObject);
        return;
      }
      if (typeof el.click === 'function') el.click();
    }
  }, [focusTick]);

  const setField = (k, v) => setForm({ ...form, [k]: v });

  const onFieldBlur = () => {
    setTimeout(() => {
      const ae = document.activeElement;
      if (!objectRefs.current.some((el) => el === ae)) {
        setMode('NORMAL');
      }
    }, 0);
  };

  const onFieldKeyDown = (e) => {
    if (e.key === 'Escape') {
      e.preventDefault();
      e.currentTarget.blur();
      setMode('NORMAL');
      return;
    }
    if ((e.metaKey || e.ctrlKey) && e.key === 'Enter') {
      e.preventDefault();
      onSend();
    }
  };

  return (
    <>
      <SectionHead idx="00" title="~/contact" subt="normal mode nav + insert style editing" />
      <div className="contact-wrap">
        <div className="contact-intro">
          <p>
            Fastest path is <span style={{ color: 'var(--blue)' }}>{data.email}</span>. I reply
            within a day, unless deadlines are happening — then two.
          </p>
          <div className="links">
            <a
              href={`mailto:${data.email}`}
              className={activeObject === 0 ? 'active' : ''}
              ref={(el) => (objectRefs.current[0] = el)}
              onFocus={() => setActiveObject(0)}
            >
              <span className="k">email →</span>
              <span className="v">{data.email}</span>
            </a>
            <a
              href={`https://${data.github}`}
              target="_blank"
              rel="noreferrer"
              className={activeObject === 1 ? 'active' : ''}
              ref={(el) => (objectRefs.current[1] = el)}
              onFocus={() => setActiveObject(1)}
            >
              <span className="k">github →</span>
              <span className="v">{data.github}</span>
            </a>
            <a
              href={`https://${data.linkedin}`}
              target="_blank"
              rel="noreferrer"
              className={activeObject === 2 ? 'active' : ''}
              ref={(el) => (objectRefs.current[2] = el)}
              onFocus={() => setActiveObject(2)}
            >
              <span className="k">linkedin →</span>
              <span className="v">{data.linkedin}</span>
            </a>
          </div>

          <div className="mail-guide">
            <h5>mail format guide</h5>
            <ul>
              <li>Press <kbd>i</kbd>/<kbd>a</kbd> (or uppercase) to edit current field.</li>
              <li>
                Press <kbd>o</kbd> for field below, <kbd>O</kbd> for field above, then type in insert
                mode.
              </li>
              <li>Press <kbd>Esc</kbd> to return to normal mode and use vim motions.</li>
              <li>In normal mode, use <kbd>h/j/k/l</kbd> to move the selected object.</li>
              <li>
                <code>:w</code> and <code>:wq</code> show send help. To send, click button or run
                <code> :send</code> or <code>:mail</code>.
              </li>
            </ul>
          </div>
        </div>

        <form
          className="contact-form"
          onSubmit={(e) => {
            e.preventDefault();
            onSend();
          }}
        >
          <div className={'field' + (activeObject === 3 ? ' active' : '')}>
            <label>:set name</label>
            <input
              ref={(el) => (objectRefs.current[3] = el)}
              value={form.name}
              onChange={(e) => setField('name', e.target.value)}
              onFocus={() => {
                setActiveObject(3);
                setMode('INSERT');
              }}
              onBlur={onFieldBlur}
              onKeyDown={onFieldKeyDown}
              placeholder="your name"
            />
          </div>
          <div className={'field' + (activeObject === 4 ? ' active' : '')}>
            <label>:set from</label>
            <input
              ref={(el) => (objectRefs.current[4] = el)}
              type="email"
              value={form.from}
              onChange={(e) => setField('from', e.target.value)}
              onFocus={() => {
                setActiveObject(4);
                setMode('INSERT');
              }}
              onBlur={onFieldBlur}
              onKeyDown={onFieldKeyDown}
              placeholder="you@domain.com"
            />
          </div>
          <div className={'field' + (activeObject === 5 ? ' active' : '')}>
            <label>:set subject</label>
            <input
              ref={(el) => (objectRefs.current[5] = el)}
              value={form.subject}
              onChange={(e) => setField('subject', e.target.value)}
              onFocus={() => {
                setActiveObject(5);
                setMode('INSERT');
              }}
              onBlur={onFieldBlur}
              onKeyDown={onFieldKeyDown}
              placeholder="subject"
            />
          </div>
          <div className={'field' + (activeObject === 6 ? ' active' : '')}>
            <label>:start insert — message</label>
            <textarea
              ref={(el) => (objectRefs.current[6] = el)}
              rows={7}
              value={form.msg}
              onChange={(e) => setField('msg', e.target.value)}
              onFocus={() => {
                setActiveObject(6);
                setMode('INSERT');
              }}
              onBlur={onFieldBlur}
              onKeyDown={onFieldKeyDown}
              placeholder="write your message"
            />
          </div>
          <div className="actions">
            <button
              type="submit"
              className={activeObject === 7 ? 'active' : ''}
              ref={(el) => (objectRefs.current[7] = el)}
              onFocus={() => setActiveObject(7)}
            >
              send email
            </button>
            <span className="hint">
              command mode: <code>:send</code>/<code>:mail</code> to send, <code>:w</code>/<code>:wq</code> for help
            </span>
          </div>
          <div className="hint">esc returns to normal mode; h/j/k/l stay available there.</div>
          <div className="mode-legend">
            <span>insert keys: i / a / o / O</span>
            <span>object nav: h / j / k / l</span>
            <span>send: button or :send/:mail</span>
            <span>escape: back to NORMAL</span>
          </div>
        </form>
      </div>
    </>
  );
}

Object.assign(window, {
  ProjectsBuffer,
  ExperienceBuffer,
  AboutBuffer,
  NowBuffer,
  WritingBuffer,
  ContactBuffer,
});
