// ═══════════════════════════════════════════════════════════════════════════
// AGENTIC LAYERS — the parts of the deck a PDF cannot copy.
//
//   Layer 2 · Evidence      <Fig id="…">  every spine figure opens its proof
//   Layer 3 · Conversation  <Objections room="…">  pre-written objection answers
//   Layer 5 · Telemetry     track()  rooms, evidence opens, questions
//
// Build rule from the brief: if a number appears on the spine and has no
// layer-2 evidence behind it, either build the evidence or remove the number.
// `Fig` enforces this loudly — an unknown id renders in red rather than
// silently degrading to plain text, so a missing proof cannot ship unnoticed.
// ═══════════════════════════════════════════════════════════════════════════

const { useState, useEffect, useRef, useCallback } = React;

// ───────────────────────── Layer 5 · telemetry
// Aggregate behaviour only. No covert identification beyond the link the
// recipient was sent — the brief is explicit that this stays proportionate.
const SESSION = (function () {
  try {
    const k = 'admel.sid';
    let v = sessionStorage.getItem(k);
    if (!v) { v = Math.random().toString(36).slice(2, 10); sessionStorage.setItem(k, v); }
    return v;
  } catch (e) { return 'nostore'; }
})();

const TRAIL = [];
window.__trail = TRAIL;

function track(event, props) {
  const row = {
    t: Date.now(),
    session: SESSION,
    event: event,
    ...(props || {}),
  };
  TRAIL.push(row);
  try {
    // Survives a reload so a session that comes back is still one session.
    localStorage.setItem('admel.trail', JSON.stringify(TRAIL.slice(-400)));
  } catch (e) {}
  // No collector wired yet. When one exists, POST here — the shape is stable.
  if (window.__ADMEL_COLLECT) {
    try { window.__ADMEL_COLLECT(row); } catch (e) {}
  }
  return row;
}
window.__track = track;

// Dwell time per room. Fires on leave, so a room opened and abandoned in two
// seconds is distinguishable from one that held attention.
function useRoomTelemetry(room) {
  useEffect(() => {
    if (!room) return;
    const t0 = Date.now();
    track('room_enter', { room: room });
    return () => track('room_leave', { room: room, ms: Date.now() - t0 });
  }, [room]);
}
window.__useRoomTelemetry = useRoomTelemetry;

// ───────────────────────── Layer 2 · evidence
// A figure is a control, not a decoration. Clicking opens the proof in place,
// without leaving the room — that "without leaving" is the whole point, so
// this is a popover anchored to the number, never a route change.

function useEvidence(id) {
  const lang = window.__useLang();
  const T = window.TDATA[lang];
  return (T.evidence || {})[id];
}

function Fig({ id, children, style, tone }) {
  const ev = useEvidence(id);
  const [open, setOpen] = useState(false);
  const btnRef = useRef(null);
  const [place, setPlace] = useState({ left: 0, top: 0, w: 380, above: false, max: 420 });

  // Missing evidence is a build error, not a styling edge case.
  if (!ev) {
    return (
      <span style={{ ...style, color: 'oklch(0.55 0.22 25)', textDecoration: 'underline wavy' }}
        title={'No layer-2 evidence for id "' + id + '"'}>
        {children}
      </span>
    );
  }

  const toggle = useCallback(() => {
    setOpen((o) => {
      if (!o) track('evidence_open', { id: id });
      return !o;
    });
  }, [id]);

  // Anchor to the number. Measured on open so it survives the responsive
  // type scale, which changes the anchor's box at every breakpoint.
  useEffect(() => {
    if (!open || !btnRef.current) return;
    const fit = () => {
      const r = btnRef.current.getBoundingClientRect();
      const vw = window.innerWidth, vh = window.innerHeight;
      const w = Math.min(460, vw - 32);
      let left = r.left + r.width / 2 - w / 2;
      left = Math.max(16, Math.min(left, vw - w - 16));
      // Flip above when there is more room there — on a phone the figure is
      // often already low on the screen.
      // The chat dock owns the bottom of the screen, so usable space below
      // the anchor stops short of the viewport edge.
      const DOCK = 130, GAP = 12;
      const below = vh - r.bottom - DOCK;
      const above = r.top - 16 > below;
      const room = (above ? r.top - 16 : below) - GAP;
      setPlace({ left: left, top: above ? r.top : r.bottom, w: w,
                 above: above, max: Math.max(160, room) });
    };
    fit();
    window.addEventListener('resize', fit);
    window.addEventListener('scroll', fit, true);
    return () => {
      window.removeEventListener('resize', fit);
      window.removeEventListener('scroll', fit, true);
    };
  }, [open]);

  useEffect(() => {
    if (!open) return;
    const onKey = (e) => { if (e.key === 'Escape') setOpen(false); };
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, [open]);

  const accent = tone || 'var(--accent)';

  return (
    <React.Fragment>
      <button
        ref={btnRef}
        onClick={toggle}
        className="fig-control"
        style={{
          ...style,
          font: 'inherit', color: 'inherit', background: 'none',
          border: 'none', padding: 0, margin: 0, cursor: 'pointer',
          // <button> centres its text by default, which silently centred any
          // paragraph wrapped in a Fig.
          textAlign: 'inherit',
          // Reads as a control at 15 metres without becoming a link.
          borderBottom: '1.5px solid ' + accent, paddingBottom: 1,
          position: 'relative',
        }}
      >
        {children}
      </button>

      {open && (
        <React.Fragment>
          <div onClick={() => setOpen(false)} style={{
            position: 'fixed', inset: 0, zIndex: 90, background: 'transparent',
          }} />
          <div className="fig-pop" style={{
            position: 'fixed', zIndex: 91,
            left: place.left, width: place.w,
            top: place.above ? undefined : place.top + 10,
            bottom: place.above ? (window.innerHeight - place.top + 10) : undefined,
            maxHeight: place.max || 420, overflowY: 'auto',
            background: 'var(--paper)',
            borderRadius: 16, padding: 'var(--s3)',
            boxShadow: '0 24px 60px -20px rgba(57,54,48,0.32)',
            textAlign: 'left',
          }}>
            <div style={{
              fontFamily: 'var(--sans)', fontSize: 'var(--t-label)', letterSpacing: '0.08em',
              textTransform: 'uppercase', color: accent, fontWeight: 600, marginBottom: 'var(--s1)',
            }}>
              {ev.label}
            </div>

            {ev.body && (
              <div style={{
                fontFamily: 'var(--sans)', fontSize: 15, lineHeight: 1.5,
                color: 'var(--espresso)', marginBottom: ev.rows ? 'var(--s2)' : 0,
              }}>
                {ev.body}
              </div>
            )}

            {ev.rows && (
              <div style={{ display: 'grid' }}>
                {ev.rows.map((r, i) => (
                  <div key={i} style={{
                    display: 'flex', justifyContent: 'space-between', gap: 14,
                    padding: '8px 0', borderTop: i ? '1px solid var(--ink-12)' : 'none',
                    fontFamily: 'var(--sans)', fontSize: 14, lineHeight: 1.35,
                  }}>
                    <span style={{ color: 'var(--ink-50)' }}>{r.k}</span>
                    <span style={{ fontWeight: 600, textAlign: 'right', whiteSpace: 'pre-line' }}>{r.v}</span>
                  </div>
                ))}
              </div>
            )}

            {/* The uncomfortable half. Rendered distinctly so it reads as
                volunteered rather than buried — that is the whole trade. */}
            {ev.caveat && (
              <div style={{
                marginTop: 'var(--s2)', paddingLeft: 'var(--s2)',
                borderLeft: '2px solid var(--gold)',
                fontFamily: 'var(--sans)', fontSize: 13.5, lineHeight: 1.45,
                color: 'var(--espresso)',
              }}>
                <span style={{
                  fontFamily: 'var(--sans)', fontSize: 'var(--t-label)', letterSpacing: '0.08em',
                  textTransform: 'uppercase', color: 'var(--gold)',
                  display: 'block', marginBottom: 4, fontWeight: 600,
                }}>{ev.caveatLabel || 'Worth knowing'}</span>
                {ev.caveat}
              </div>
            )}

            {ev.source && (
              <div style={{
                marginTop: 'var(--s2)', fontFamily: 'var(--sans)', fontSize: 'var(--t-label)',
                color: 'var(--ink-30)',
              }}>
                {ev.source}
              </div>
            )}
          </div>
        </React.Fragment>
      )}
    </React.Fragment>
  );
}
window.Fig = Fig;

// ───────────────────────── Layer 3 · conversation
// An empty text box in a pitch context is a dead feature. The investor sits
// with their objection and leaves with it unresolved. So the deck voices the
// objection first, and answers are retrieved, never generated.

function Objections({ room, onDark, align, stack }) {
  const lang = window.__useLang();
  const T = window.TDATA[lang];
  const list = ((T.objections || {})[room]) || [];
  if (!list.length) return null;

  // The primary affordance. Plain text links, not chips: clicking one submits
  // the question to the agent and streams the answer in the Otto surface, so
  // a reader experiences the interaction without ever typing.
  const ask = (q) => {
    track('objection_ask', { room: room, q: q });
    if (window.__askDeck) window.__askDeck(q);
  };

  return (
    <div className="objections" data-dark={onDark ? '1' : undefined}
         style={{
           flex: '0 0 auto', marginTop: 'var(--s3)',
           textAlign: align === 'left' ? 'left' : 'center',
         }}>
      <div style={{
        display: 'flex', flexWrap: stack ? 'nowrap' : 'wrap', gap: 'var(--s1)',
        flexDirection: stack ? 'column' : 'row',
        alignItems: stack ? 'flex-start' : undefined,
        justifyContent: align === 'left' ? 'flex-start' : 'center',
      }}>
        {list.map((o, i) => (
          <button key={i} onClick={() => ask(o.q)} className="obj-link" style={{
            font: 'inherit', cursor: 'pointer', textAlign: 'left',
            fontFamily: 'var(--sans)', fontSize: 16, fontWeight: 500,
            lineHeight: 1.2,
            // Same oval as the question bar, so the two read as one system.
            padding: '9px 18px', borderRadius: 999,
            border: '1px solid var(--ink-12)',
            background: 'var(--paper)',
            color: 'var(--espresso)',
            display: 'inline-flex', alignItems: 'center', gap: 8,
            transition: 'border-color 160ms ease, background 160ms ease',
          }}>
            <span aria-hidden="true" style={{ opacity: 0.55 }}>{'\u203A'}</span>
            <span>{o.q}</span>
          </button>
        ))}
      </div>
    </div>
  );
}

window.Objections = Objections;
