/* eslint-disable */
/* global React */

/* ============================================================
   EXPM — 4 deep dives + chip list
   ============================================================ */

function ExpmRecordingDiagram() {
  return (
    <svg viewBox="0 0 460 240" preserveAspectRatio="xMidYMid meet" style={{width: "100%", height: "auto"}}>
      <defs>
        <marker id="er1" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="8" markerHeight="8" orient="auto">
          <path d="M0,0 L10,5 L0,10 z" fill="currentColor" />
        </marker>
      </defs>

      <text x="6" y="22" fontFamily="var(--mono)" fontSize="9" fill="var(--ink-3)" letterSpacing="0.12em">REGION · IN</text>
      <g className="arch-node"><rect x="6" y="32" width="92" height="48" /><text x="52" y="55" textAnchor="middle" fontSize="10" fontFamily="var(--mono)">BBB · IN</text><text x="52" y="68" textAnchor="middle" fontSize="9" fontFamily="var(--mono)" fill="var(--ink-3)">post_publish</text></g>
      <g className="arch-node accent"><rect x="120" y="32" width="92" height="48" /><text x="166" y="55" textAnchor="middle" fontSize="10" fontFamily="var(--mono)">AZURE BLOB</text><text x="166" y="68" textAnchor="middle" fontSize="9" fontFamily="var(--mono)" fill="var(--ink-3)">IN storage</text></g>
      <g className="arch-node"><rect x="232" y="32" width="92" height="48" /><text x="278" y="55" textAnchor="middle" fontSize="10" fontFamily="var(--mono)">PROXY · IN</text><text x="278" y="68" textAnchor="middle" fontSize="9" fontFamily="var(--mono)" fill="var(--ink-3)">Range · cache</text></g>

      <text x="6" y="122" fontFamily="var(--mono)" fontSize="9" fill="var(--ink-3)" letterSpacing="0.12em">REGION · AU</text>
      <g className="arch-node"><rect x="6" y="132" width="92" height="48" /><text x="52" y="155" textAnchor="middle" fontSize="10" fontFamily="var(--mono)">BBB · AU</text><text x="52" y="168" textAnchor="middle" fontSize="9" fontFamily="var(--mono)" fill="var(--ink-3)">post_publish</text></g>
      <g className="arch-node sage"><rect x="120" y="132" width="92" height="48" /><text x="166" y="155" textAnchor="middle" fontSize="10" fontFamily="var(--mono)">AZURE BLOB</text><text x="166" y="168" textAnchor="middle" fontSize="9" fontFamily="var(--mono)" fill="var(--ink-3)">AU storage</text></g>
      <g className="arch-node"><rect x="232" y="132" width="92" height="48" /><text x="278" y="155" textAnchor="middle" fontSize="10" fontFamily="var(--mono)">PROXY · AU</text><text x="278" y="168" textAnchor="middle" fontSize="9" fontFamily="var(--mono)" fill="var(--ink-3)">Range · cache</text></g>

      <g className="arch-node"><rect x="350" y="82" width="100" height="48" /><text x="400" y="105" textAnchor="middle" fontSize="10" fontFamily="var(--mono)">BROWSER</text><text x="400" y="118" textAnchor="middle" fontSize="9" fontFamily="var(--mono)" fill="var(--ink-3)">SPA · seekable</text></g>

      <g style={{color: "var(--ink)"}}>
        <path className="arch-edge" d="M98 56 H120" markerEnd="url(#er1)" />
        <path className="arch-edge" d="M212 56 H232" markerEnd="url(#er1)" />
        <path className="arch-edge" d="M98 156 H120" markerEnd="url(#er1)" />
        <path className="arch-edge" d="M212 156 H232" markerEnd="url(#er1)" />
        <path className="arch-edge" d="M324 56 Q 340 56 350 96" markerEnd="url(#er1)" />
        <path className="arch-edge" d="M324 156 Q 340 156 350 116" markerEnd="url(#er1)" />
        <path className="arch-edge dashed" d="M52 80 V132" />
        <text x="58" y="108" fontSize="9" fontFamily="var(--mono)" fill="var(--orange)">failover</text>
      </g>
    </svg>
  );
}

function ExpmSurveillanceDiagram() {
  return (
    <svg viewBox="0 0 460 240" preserveAspectRatio="xMidYMid meet" style={{width: "100%", height: "auto"}}>
      <defs>
        <marker id="es1" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="8" markerHeight="8" orient="auto">
          <path d="M0,0 L10,5 L0,10 z" fill="currentColor" />
        </marker>
      </defs>

      <g><rect x="10" y="14" width="440" height="216" fill="none" stroke="var(--ink-3)" strokeDasharray="3 3" /><text x="20" y="28" fontFamily="var(--mono)" fontSize="9" fill="var(--ink-3)" letterSpacing="0.12em">DASHBOARD ORIGIN · OPS</text></g>
      <g><rect x="30" y="44" width="400" height="172" fill="color-mix(in oklab, var(--orange) 4%, var(--bg))" stroke="var(--orange)" strokeDasharray="3 3" /><text x="40" y="58" fontFamily="var(--mono)" fontSize="9" fill="var(--orange)" letterSpacing="0.12em">PROXY.HTML · BBB ORIGIN (SAME-ORIGIN BRIDGE)</text></g>
      <g><rect x="50" y="74" width="240" height="130" fill="var(--bg)" stroke="var(--ink)" /><text x="60" y="88" fontFamily="var(--mono)" fontSize="9" fill="var(--ink-3)" letterSpacing="0.12em">BBB HTML5 CLIENT</text><text x="60" y="110" fontFamily="var(--mono)" fontSize="10" fill="var(--ink)">{'<audio>'} element</text><text x="60" y="128" fontFamily="var(--mono)" fontSize="10" fill="var(--ink)">video streams</text><text x="60" y="146" fontFamily="var(--mono)" fontSize="10" fill="var(--ink)">camera tiles</text></g>

      <g className="arch-node"><rect x="310" y="84" width="110" height="46" /><text x="365" y="106" textAnchor="middle" fontSize="10" fontFamily="var(--mono)">ANALYSERNODE</text><text x="365" y="120" textAnchor="middle" fontSize="9" fontFamily="var(--mono)" fill="var(--ink-3)">200ms sample</text></g>
      <g className="arch-node accent"><rect x="310" y="148" width="110" height="46" /><text x="365" y="170" textAnchor="middle" fontSize="10" fontFamily="var(--mono)">RISK ENGINE</text><text x="365" y="184" textAnchor="middle" fontSize="9" fontFamily="var(--mono)" fill="var(--ink-3)">5 tiers · downgrade</text></g>

      <g style={{color: "var(--ink)"}}>
        <path className="arch-edge" d="M290 108 H310" markerEnd="url(#es1)" />
        <text x="300" y="100" textAnchor="middle" fontSize="8" fontFamily="var(--mono)" fill="var(--ink-3)">audio</text>
        <path className="arch-edge dashed" d="M365 130 V148" markerEnd="url(#es1)" />
        <path className="arch-edge" d="M310 171 Q 230 220 60 200" markerEnd="url(#es1)" />
        <text x="180" y="218" textAnchor="middle" fontSize="8" fontFamily="var(--mono)" fill="var(--ink-3)">postMessage · click "Play audio" · mute / unmute</text>
      </g>
    </svg>
  );
}

function ExpmCard({ nr, ttl, blurb, stat, statLbl, chips, diagram }) {
  return (
    <div className="expm-card">
      <div>
        <div className="nr">{nr}</div>
        <div className="ttl">{ttl}</div>
      </div>
      <div className="blurb">{blurb}</div>
      {diagram ? <div style={{padding: 12, border: "1px solid var(--rule)", background: "var(--bg)"}}>{diagram}</div> : null}
      <div className="headline-stat">
        <div className="big">{stat}</div>
        <div className="small">{statLbl}</div>
      </div>
      <div className="mini-stack">{chips.map((c, i) => <span key={i} className="chip">{c}</span>)}</div>
    </div>
  );
}

function EXPM() {
  return (
    <section id="expm" className="section" style={{paddingTop: 96, paddingBottom: 96}}>
      <div className="wrap">

        <div className="product-head">
          <div className="index">05 — Day job · senior engineering</div>
          <h2 className="product-name"><em>EXPM</em>.</h2>
          <div style={{display: "flex", flexDirection: "column", gap: 8, alignItems: "flex-end"}}>
            <span className="visit" style={{cursor: "default", borderColor: "var(--orange)", color: "var(--orange)"}}>
              <span>★ Q1 '26 · Excellence</span>
            </span>
            <span className="visit" style={{cursor: "default"}}>
              <span>★ Q3 '25 · Excellence</span>
            </span>
          </div>
        </div>

        <div className="product-tag">
          <p className="pitch">
            Sole senior engineer on the platform. <em>Nine</em> production systems, owned end-to-end.
          </p>
          <p className="body">
            EXPM Learning (formerly Employability.Life, acquired by Federation University Australia) is an enterprise learning platform — Microsoft Teams &amp; BigBlueButton orchestration, multi-region, multi-tenant. The work below isn't tickets; it's the systems the platform actually runs on. <span style={{color: "var(--orange)"}}>Excellence Award winner two quarters running</span> — Q3 2025 &amp; Q1 2026.
          </p>
        </div>

        <div className="expm-grid">
          <ExpmCard
            nr="System 01 · Video infrastructure"
            ttl="Multi-region recording pipeline → Azure Blob"
            blurb="Built the entire BigBlueButton recording pipeline end-to-end: a post-publish hook (Ruby + bash) uploads every artefact to Azure Blob with SAS auth, an Express playback proxy adds HTTP Range support (Blob doesn't natively), and pre-caches the ~14 MB BBB SPA. IN and AU each have their own storage + proxy so a region is isolated by design."
            stat={<span>&lt; 1<span style={{fontSize: "0.45em", color: "var(--ink-3)", marginLeft: 8}}>hr</span></span>}
            statLbl="Failover from IN to AU when the production VM crashed. Recording playback never went dark."
            chips={["Azure Blob SAS", "Range-request proxy", "Post-publish hook", "Per-region isolation"]}
            diagram={<ExpmRecordingDiagram />}
          />

          <ExpmCard
            nr="System 02 · Incident response"
            ttl="The Outlook duplicate incident"
            blurb="Up to 118 calendar events for a single day. 56 mailboxes affected. One user with 16,226 orphan events accumulated over weeks. Root cause was subtle: Graph's per-mailbox throttle was returning a transient error after writes had already succeeded — so 'failed' rows were filtered out of the cleanup path and silently re-created on each sync. Fixed with bestTrackingMap (success-first, then most-recent), 404-as-success on delete, and a Graph $batch round-robin across mailboxes."
            stat="43,424"
            statLbl="Orphan events drained in two passes (~5 hours). Zero recurrence."
            chips={["Graph $batch", "Round-robin", "Exp backoff 2/4/8s", "Filter fix · 11 sites", "404-as-success"]}
          />

          <ExpmCard
            nr="System 03 · Real-time"
            ttl="Live-class surveillance dashboard"
            blurb="Ops were joining 50+ live classes one by one. Built a single dashboard that embeds every BBB room with a cross-origin postMessage bridge — outer dashboard → proxy.html (same-origin with BBB) → BBB HTML5 client. The proxy has DOM access to the BBB audio element, so an admin click → postMessage → proxy auto-clicks BBB's 'Play audio' prompt → mutes the bot. Web Audio AnalyserNode samples every 200ms for live audio level. A 5-tier risk engine with 'secondary-covers-primary' downgrade matches how ops actually reads the floor."
            stat="50+"
            statLbl="Concurrent live classes monitored from one screen. A 'not-created' detector caught ≥2 cron drifts before users noticed."
            chips={["Nested iframe", "postMessage proxy", "Web Audio API", "5-tier risk", "30s data-only refresh"]}
            diagram={<ExpmSurveillanceDiagram />}
          />

          <ExpmCard
            nr="System 04 · Observability"
            ttl="Elasticsearch, Kibana, @Monitored()"
            blurb="Triage used to mean SSH + grep + cross-reference. Built the platform in layers, each useful on its own: Winston → ES transport with daily indices; an HTTP interceptor stamping correlationId / latency / userId on every request; a custom TypeORM logger flagging anything over 1000 ms; and a @Monitored() cron decorator that acquires a Redis lock so jobs don't double-fire, then writes lifecycle to ES."
            stat={<span>30<span style={{color: "var(--ink-3)", fontSize: "0.5em", margin: "0 6px"}}>→</span>5</span>}
            statLbl="Minutes of triage on a typical production incident. Caught a 7-day schema drift on a critical cron the moment it started failing."
            chips={["Winston", "Elasticsearch", "Kibana", "Redis lock", "TypeORM slow log", "@Monitored() decorator"]}
          />
        </div>

        <div className="expm-more">
          <h4>Five more · short form</h4>
          <div className="expm-more-list">
            <div className="item">
              <div className="nr">SYSTEM 05 · SECURITY</div>
              <div className="ttl">UUID-obfuscated recording URLs</div>
              <div className="note">Decoy UUIDs in list endpoints. BBB-format obfuscated IDs minted on Watch with 2h Redis TTL. Express proxy with FIFO 10k cap, negative cache and 5s AbortController. Search space went from a small hash to 2¹²⁸; zero FE rewrites.</div>
            </div>
            <div className="item">
              <div className="nr">SYSTEM 06 · I18N</div>
              <div className="ttl">Timezone independence · 3 regions, 1 codebase</div>
              <div className="note">One-shot UTC migration across ~30k rows. IANA timezone columns on team + user. 25+ ad-hoc <code>new Date()</code> call sites unified into a helper library. 30-minute bucketed cron dispatcher covers both :00 and :30 zones.</div>
            </div>
            <div className="item">
              <div className="nr">SYSTEM 07 · MIGRATION</div>
              <div className="ttl">Azure Blob · 1,400 file references</div>
              <div className="note">42 API shapes. 30 FE display sites. 6 third-party integrations. SAS URLs with 4h expiry. Dual-field non-breaking rollout. ServeStaticModule soft-deleted, not removed.</div>
            </div>
            <div className="item">
              <div className="nr">SYSTEM 08 · INFRA</div>
              <div className="ttl">Iframe-safe BBB embedding</div>
              <div className="note">Custom nginx strips X-Frame-Options. frame-ancestors CSP for explicit dashboard origins. cookie.same-site=None + secure on bbb-web. Overrides live in <code>/etc</code> and survive package upgrades.</div>
            </div>
            <div className="item">
              <div className="nr">SYSTEM 09 · API DESIGN</div>
              <div className="ttl">Scheduler ↔ Platform sync API</div>
              <div className="note">POST <code>/data-overview/sync-to-play</code>. schedules[] + mappings[] in one transactional payload. Validates grouping rules, primary-PM consistency, team freshness. Dry-run preview. All-or-nothing.</div>
            </div>
          </div>
        </div>

        <div className="pullquote" style={{margin: "96px 0 0"}}>
          The system fails into a state I can <em>see</em>, not one I have to <em>discover.</em>
          <div className="attrib">How I think about backend systems</div>
        </div>
      </div>
    </section>
  );
}

window.EXPM = EXPM;
