// src/cohort.jsx — Bayesian gender/age inference + ThemeProvider + Cockpit overlay (R2)
// R2 changes:
//  - Codex MED4 fix: transition microcopy uses useEffect keyed on resolved cohort
//    (eliminates stale React closure that fired one question late)
//  - Operator-mode plumbing — cohortKey transitions emit events that consumers (Quiz)
//    subscribe to via the new `useCohortTransitions` hook
//  - Mobile cockpit: collapses to bottom-sheet drawer ≤768px

const { useState, useEffect, useMemo, useRef, useCallback, createContext, useContext } = React;

const INITIAL_COHORT = {
  gender:   { f: 0.5, m: 0.5 },
  age:      { '18-29': 0.25, '30-44': 0.25, '45-59': 0.25, '60+': 0.25 },
  goal:     null,
  forced:   { gender: null, age: null, goal: null },
  history:  [],
  confidence: { gender: 0.5, age: 0.25 },
};

function applyWeights(prior, weights) {
  if (!weights) return prior;
  const eps = 0.02;
  const post = {};
  let sum = 0;
  for (const k of Object.keys(prior)) {
    const w = Math.max(eps, weights[k] ?? 1);
    post[k] = prior[k] * w;
    sum += post[k];
  }
  for (const k of Object.keys(post)) post[k] = post[k] / sum;
  return post;
}

function maxKey(dist) {
  let best = null, bestV = -1;
  for (const [k, v] of Object.entries(dist)) if (v > bestV) { best = k; bestV = v; }
  return { key: best, value: bestV };
}

function resolvedCohort(state) {
  const g = state.forced.gender ?? (state.confidence.gender >= 0.72 ? maxKey(state.gender).key : 'unknown');
  const a = state.forced.age    ?? (state.confidence.age    >= 0.55 ? maxKey(state.age).key    : 'unknown');
  return { gender: g, age: a, goal: state.forced.goal ?? state.goal };
}

const CohortCtx = createContext(null);
function useCohort() { return useContext(CohortCtx); }

function CohortProvider({ children, forced = {}, archetype = 'trust-clinical', heroType = 'serif', theme = 'light', motion = 'on' }) {
  const [state, setState] = useState(() => ({
    ...INITIAL_COHORT,
    forced: { gender: forced.gender ?? null, age: forced.age ?? null, goal: forced.goal ?? null },
  }));

  useEffect(() => {
    setState(s => ({ ...s, forced: { gender: forced.gender ?? null, age: forced.age ?? null, goal: forced.goal ?? null } }));
  }, [forced.gender, forced.age, forced.goal]);

  const recordAnswer = useCallback((q, optionWeights, meta = {}) => {
    setState(s => {
      const next = { ...s };
      if (optionWeights?.gender) next.gender = applyWeights(s.gender, optionWeights.gender);
      if (optionWeights?.age)    next.age    = applyWeights(s.age,    optionWeights.age);
      if (meta.locksGoal && meta.goal) next.goal = meta.goal;
      if (meta.locksAge  && meta.age)  next.age  = { '18-29': 0, '30-44': 0, '45-59': 0, '60+': 0, [meta.age]: 1 };
      if (meta.locksGender && meta.gender)
        next.gender = { f: meta.gender === 'f' ? 1 : 0, m: meta.gender === 'm' ? 1 : 0 };
      if (meta.gender === 'unknown') {
        // Codex MED3 baked: nonbinary / prefer-not-to-say → force unknown
        next.forced = { ...next.forced, gender: 'unknown' };
      }
      next.confidence = { gender: maxKey(next.gender).value, age: maxKey(next.age).value };
      next.history = [...s.history, { q, applied: optionWeights ?? null, meta }];
      return next;
    });
  }, []);

  const resolved = resolvedCohort(state);
  const cohortKey = `${resolved.gender}:${resolved.age}:${resolved.goal ?? 'unknown'}`;

  useEffect(() => {
    const root = document.documentElement;
    root.dataset.cohortGender = resolved.gender;
    root.dataset.ageBracket   = resolved.age;
    root.dataset.archetype    = archetype;
    root.dataset.heroType     = heroType;
    root.dataset.theme        = theme;
    root.dataset.motion       = motion;
  }, [resolved.gender, resolved.age, archetype, heroType, theme, motion]);

  const value = useMemo(() => ({
    state, resolved, cohortKey, recordAnswer, archetype, theme,
    setForced: (patch) => setState(s => ({ ...s, forced: { ...s.forced, ...patch } })),
    reset: () => setState({ ...INITIAL_COHORT, forced: state.forced }),
  }), [state, resolved, cohortKey, recordAnswer, archetype, theme]);

  return <CohortCtx.Provider value={value}>{children}</CohortCtx.Provider>;
}

// ─────────────────────────────────────────────────────────────────────────────
// useCohortTransitions — fires a callback when resolved gender/age cross thresholds
// Replaces the R1 stale-closure transition microcopy logic (Codex MED4)
// ─────────────────────────────────────────────────────────────────────────────
function useCohortTransitions(onTransition, enabled = true) {
  const { resolved } = useCohort();
  const prev = useRef({ gender: 'unknown', age: 'unknown' });
  const firstRun = useRef(true);

  useEffect(() => {
    if (!enabled) return;
    if (firstRun.current) {
      // Establish baseline without firing
      prev.current = { gender: resolved.gender, age: resolved.age };
      firstRun.current = false;
      return;
    }
    const genderChanged = resolved.gender !== prev.current.gender && resolved.gender !== 'unknown';
    const ageChanged    = resolved.age    !== prev.current.age    && resolved.age    !== 'unknown';
    if (genderChanged || ageChanged) {
      onTransition?.({
        gender: resolved.gender, age: resolved.age,
        genderChanged, ageChanged,
        previousGender: prev.current.gender, previousAge: prev.current.age,
      });
      prev.current = { gender: resolved.gender, age: resolved.age };
    }
  }, [resolved.gender, resolved.age, enabled, onTransition]);
}

// ─────────────────────────────────────────────────────────────────────────────
// COCKPIT OVERLAY — operator/dev view of live inference state
// Desktop: floating top-right. Mobile (≤768px): bottom-sheet drawer.
// ─────────────────────────────────────────────────────────────────────────────
function CockpitOverlay({ visible, sessionId, variant }) {
  const { state, resolved, cohortKey } = useCohort();
  const isMobile = useMedia('(max-width: 768px)');
  const [collapsed, setCollapsed] = useState(false);
  if (!visible) return null;
  const pct = (n) => `${Math.round(n * 100)}%`;
  const bar = (v) => ({ width: `${Math.round(v * 100)}%` });

  const wrapStyle = isMobile ? {
    position: 'fixed', left: 0, right: 0, bottom: 0, zIndex: 60,
    background: 'rgba(11,15,26,0.92)', color: '#E8ECF3',
    borderTop: '1px solid rgba(110,88,240,0.32)',
    borderRadius: '14px 14px 0 0',
    fontFamily: 'JetBrains Mono, SF Mono, monospace',
    fontSize: 10.5, backdropFilter: 'blur(12px)',
    boxShadow: '0 -8px 32px rgba(0,0,0,0.4)',
    lineHeight: 1.4,
    transition: 'transform 280ms cubic-bezier(0.16,1,0.3,1)',
    transform: collapsed ? 'translateY(calc(100% - 36px))' : 'translateY(0)',
  } : {
    position: 'fixed', top: 16, right: 16, zIndex: 60,
    width: 280, background: 'rgba(11,15,26,0.86)', color: '#E8ECF3',
    border: '1px solid rgba(110,88,240,0.32)',
    borderRadius: 12, fontFamily: 'JetBrains Mono, SF Mono, monospace',
    fontSize: 10.5, backdropFilter: 'blur(12px)',
    boxShadow: '0 8px 32px rgba(0,0,0,0.4)',
    lineHeight: 1.4,
  };

  return (
    <div style={wrapStyle}>
      <div
        onClick={() => isMobile && setCollapsed(v => !v)}
        style={{
          display: 'flex', alignItems: 'center', gap: 6,
          padding: isMobile ? '10px 14px 8px' : '10px 10px 8px',
          borderBottom: '1px solid rgba(255,255,255,0.08)',
          cursor: isMobile ? 'pointer' : 'default',
        }}
      >
        <span style={{ width: 6, height: 6, borderRadius: 999, background: '#0FB9A3', boxShadow: '0 0 8px #0FB9A3' }} />
        <span style={{ letterSpacing: '0.08em', textTransform: 'uppercase', fontSize: 9.5, opacity: 0.85 }}>
          cohort engine · live
        </span>
        <span style={{ marginLeft: 'auto', opacity: 0.45, fontSize: 9.5 }}>sess_{sessionId}</span>
        {isMobile && (
          <span style={{ marginLeft: 6, opacity: 0.6, transition: 'transform 280ms',
                         transform: collapsed ? 'rotate(180deg)' : 'rotate(0deg)' }}>
            <Icon kind="chev-down" size={12} color="#E8ECF3" />
          </span>
        )}
      </div>
      <div style={{
        padding: isMobile ? '10px 14px 14px' : '8px 10px 10px',
        display: 'flex', flexDirection: 'column', gap: 6,
      }}>
        <CockpitRow label="gender" value={resolved.gender.toUpperCase()} conf={pct(state.confidence.gender)} />
        <div style={cockpitS.dist}>
          <span style={{ ...cockpitS.distF, ...bar(state.gender.f) }} />
          <span style={{ ...cockpitS.distM, ...bar(state.gender.m) }} />
        </div>
        <CockpitRow label="age" value={resolved.age} conf={pct(state.confidence.age)} />
        <div style={cockpitS.distRow}>
          {Object.entries(state.age).map(([k, v]) => (
            <div key={k} style={cockpitS.distCell}>
              <span style={cockpitS.distCellLbl}>{k}</span>
              <span style={{ ...cockpitS.distCellBar, ...bar(v) }} />
            </div>
          ))}
        </div>
        <CockpitRow label="goal" value={resolved.goal ?? '—'} />
        <CockpitRow label="variant" value={variant ?? '—'} />
        <div style={cockpitS.cohort}>
          <span style={cockpitS.lbl}>cohort_key</span>
          <span style={{ color: '#A6F5E5', fontSize: 10.5 }}>{cohortKey}</span>
        </div>
      </div>
    </div>
  );
}

function CockpitRow({ label, value, conf }) {
  return (
    <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
      <span style={cockpitS.lbl}>{label}</span>
      <span style={{ color: '#fff', fontWeight: 600, fontSize: 11 }}>{value}</span>
      {conf && <span style={{ marginLeft: 'auto', opacity: 0.65, fontSize: 10 }}>P={conf}</span>}
    </div>
  );
}

const cockpitS = {
  lbl: { opacity: 0.45, fontSize: 9.5, letterSpacing: '0.06em', textTransform: 'uppercase', minWidth: 54 },
  dist: { display: 'flex', height: 4, background: 'rgba(255,255,255,0.06)', borderRadius: 999, overflow: 'hidden', marginTop: -2 },
  distF: { background: 'linear-gradient(90deg, #FF8FB1, #E14C8A)', height: '100%', transition: 'width 240ms ease-out' },
  distM: { background: 'linear-gradient(90deg, #6CA9F5, #2E8AC9)', height: '100%', transition: 'width 240ms ease-out' },
  distRow: { display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: 4, marginTop: -2 },
  distCell: { display: 'flex', flexDirection: 'column', gap: 2 },
  distCellLbl: { fontSize: 8.5, opacity: 0.5 },
  distCellBar: { display: 'block', height: 3, background: '#6E58F0', borderRadius: 999, transition: 'width 240ms ease-out' },
  cohort: { display: 'flex', flexDirection: 'column', gap: 2, marginTop: 4, paddingTop: 6, borderTop: '1px solid rgba(255,255,255,0.06)' },
};

Object.assign(window, {
  CohortProvider, useCohort, useCohortTransitions, CockpitOverlay,
  INITIAL_COHORT, resolvedCohort,
});
