// Brook Consultancy — Main App

// Brand mark — uses the real Brook Consultancy logo image
function BrookMark({ size = 36, light = false }) {
  const src = light ? 'assets/brook-mark-white.png' : 'assets/brook-mark.png';
  return (
    <img
      src={src}
      width={size}
      height={size}
      alt="Brook Consultancy Partners"
      style={{ display: 'block', objectFit: 'contain' }}
    />
  );
}

// Full lockup (mark + wordmark) for splash / report headers
function BrookLockup({ height = 64, light = false }) {
  const src = 'assets/brook-logo.png';
  return (
    <img
      src={src}
      style={{ height, width: 'auto', display: 'block', objectFit: 'contain', filter: light ? 'invert(1) brightness(2)' : 'none' }}
      alt="Brook Consultancy Partners Ltd"
    />
  );
}

// ---------------------------------------------------------------
// PIN GATE
// ---------------------------------------------------------------
function PinGate({ onUnlock }) {
  const [pin, setPin] = React.useState('');
  const [error, setError] = React.useState('');

  const submit = (e) => {
    e.preventDefault();
    if (onUnlock(pin)) {
      setError('');
    } else {
      setError('Incorrect PIN. Please try again.');
      setPin('');
    }
  };

  return (
    <div className="pin-screen">
      <form className="pin-card" onSubmit={submit}>
        <div className="pin-brand pin-brand-lockup">
          <BrookLockup height={68} />
          <div className="pin-brand-sub">Consultation Tool</div>
        </div>
        <h1 className="pin-title">Secure access</h1>
        <p className="pin-sub">This system contains confidential client information. Enter your team PIN to continue.</p>
        <input
          className="pin-input"
          type="password"
          inputMode="numeric"
          autoComplete="off"
          value={pin}
          onChange={e => setPin(e.target.value.replace(/\D/g, '').slice(0, 8))}
          placeholder="••••"
          autoFocus
          maxLength={8}
        />
        <div className="pin-error">{error}&nbsp;</div>
        <button className="pin-btn" type="submit">Unlock</button>
        <div className="pin-hint">Default team PIN for this prototype: <strong>4274</strong> (BROK on a phone keypad)</div>
      </form>
    </div>
  );
}

// ---------------------------------------------------------------
// TWEAKS PANEL
// ---------------------------------------------------------------
const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "primaryNavy": "#0d2742",
  "accentTeal": "#2c7a7b",
  "accentAmber": "#c89c3f",
  "fontScale": 1,
  "showSerifHeadings": true,
  "denseSidebar": false
}/*EDITMODE-END*/;

function applyTweaks(t) {
  const root = document.documentElement;
  if (t.primaryNavy) root.style.setProperty('--brook-navy', t.primaryNavy);
  if (t.accentTeal) root.style.setProperty('--brook-teal', t.accentTeal);
  if (t.accentAmber) root.style.setProperty('--brook-amber', t.accentAmber);
  document.body.style.fontSize = (15 * (t.fontScale || 1)) + 'px';
  if (!t.showSerifHeadings) {
    root.style.setProperty('--font-serif', 'var(--font-sans)');
  } else {
    root.style.setProperty('--font-serif', "'Source Serif 4', 'Source Serif Pro', Georgia, serif");
  }
}

function TweaksPanel({ tweaks, setTweaks, onClose }) {
  const update = (k, v) => {
    const next = { ...tweaks, [k]: v };
    setTweaks(next);
    applyTweaks(next);
    try { window.parent.postMessage({ type: '__edit_mode_set_keys', edits: { [k]: v } }, '*'); } catch {}
  };
  return (
    <div className="tweaks-panel">
      <div className="tweaks-header">
        <span>Tweaks</span>
        <button onClick={onClose} style={{ background: 'none', border: 'none', color: 'white', fontSize: 16 }}>×</button>
      </div>
      <div className="tweaks-body">
        <div className="tweak-row">
          <label>Primary navy</label>
          <input type="color" value={tweaks.primaryNavy} onChange={e => update('primaryNavy', e.target.value)} />
        </div>
        <div className="tweak-row">
          <label>Accent teal</label>
          <input type="color" value={tweaks.accentTeal} onChange={e => update('accentTeal', e.target.value)} />
        </div>
        <div className="tweak-row">
          <label>Accent amber</label>
          <input type="color" value={tweaks.accentAmber} onChange={e => update('accentAmber', e.target.value)} />
        </div>
        <div className="tweak-row">
          <label>Font scale: {tweaks.fontScale}×</label>
          <input type="range" min="0.9" max="1.15" step="0.05" value={tweaks.fontScale} onChange={e => update('fontScale', parseFloat(e.target.value))} />
        </div>
        <div className="tweak-row">
          <label style={{ display: 'flex', alignItems: 'center', gap: 6, textTransform: 'none', letterSpacing: 0, fontSize: 12, color: '#1a2436' }}>
            <input type="checkbox" checked={tweaks.showSerifHeadings} onChange={e => update('showSerifHeadings', e.target.checked)} />
            Use serif for headings
          </label>
        </div>
      </div>
    </div>
  );
}

// ---------------------------------------------------------------
// SIDEBAR
// ---------------------------------------------------------------
function Sidebar({ activeSection, activeSub, onJump, store, onShowReport, onShowLog, onAutoComplete, onResetSession, onExport, onImport, fastTrack, showAllSections, onToggleShowAll, onSendForAnalysis, sendDisabled, sendDisabledReason }) {
  const allSections = window.BROOK_SCHEMA.sections;
  // Fast-track: show only sections flagged fastTrack:true plus the dashboard.
  // The "Show all sections" toggle reveals the full v1 set.
  const sections = (fastTrack && !showAllSections)
    ? allSections.filter(s => s.fastTrack || s.isDashboard)
    : allSections;
  const overall = window.computeOverallProgress(store.data);
  const isAiActive = activeSection === 'ai';
  const aiDefs = window.getBrookPromptDefs ? window.getBrookPromptDefs() : [];
  const aiAppliedCount = aiDefs.filter(d => d.key !== 'master' && window.isPromptApplied && window.isPromptApplied(store, d)).length;
  const aiTotal = aiDefs.filter(d => d.key !== 'master').length;

  return (
    <div className="sidebar">
      <div className="sidebar-header">
        <div className="sidebar-progress">
          <span className="label">Consultation Progress</span>
          <span className="pct">{overall}%</span>
        </div>
        <div className="progress-bar"><div className="fill" style={{ width: `${overall}%` }}></div></div>
      </div>

      <div className="sidebar-nav">
        {/* AI Assist — top-level destination */}
        <button
          className={`nav-section${isAiActive ? ' active' : ''}`}
          onClick={() => onJump('ai')}
          style={{ borderLeftColor: isAiActive ? 'var(--brook-amber)' : 'transparent' }}
        >
          <div className="section-row">
            <span className="section-num" style={{ color: 'var(--brook-amber)' }}>✦</span>
            <span className="section-title">AI Assist (notes)</span>
            {aiAppliedCount > 0 && (
              <span style={{ fontSize: 10.5, fontWeight: 600, color: aiAppliedCount === aiTotal ? 'var(--success)' : 'var(--brook-amber)', background: aiAppliedCount === aiTotal ? '#dcfce7' : 'var(--brook-amber-bg)', padding: '2px 7px', borderRadius: 10, letterSpacing: '0.04em' }}>
                {aiAppliedCount}/{aiTotal}
              </span>
            )}
          </div>
          <div className="section-meta">
            Bring-your-own-AI · Copy / paste workflow
          </div>
        </button>

        {sections.map(section => {
          const status = window.computeSectionStatus(section, store.data);
          const isActive = activeSection === section.id;
          // Fast-track subsection allowlist (e.g. ['1.1'] for Org Overview)
          const subs = (fastTrack && !showAllSections && Array.isArray(section.fastTrackSubs))
            ? section.subs.filter(s => section.fastTrackSubs.includes(s.id))
            : section.subs;
          const firstSubId = subs[0]?.id;
          return (
            <div key={section.id}>
              <button
                className={`nav-section${isActive ? ' active' : ''}`}
                onClick={() => onJump(section.id, firstSubId)}
              >
                <div className="section-row">
                  <span className="section-num">{section.id}.</span>
                  <span className="section-title">{section.title}</span>
                  <span className={`section-status ${status}`} title={status}></span>
                </div>
                <div className="section-meta">
                  {section.minutes ? `~${section.minutes} min` : 'no time set'}
                  {section.internal && <span className="internal-flag"> · Internal</span>}
                  {section.isDashboard && <span style={{ color: 'var(--brook-amber)' }}> · AI populated</span>}
                  {fastTrack && !showAllSections && Array.isArray(section.fastTrackSubs) && subs.length < section.subs.length && (
                    <span style={{ color: 'var(--brook-teal)' }}> · fast-track</span>
                  )}
                </div>
              </button>
              {isActive && subs.length > 0 && (
                <div className="nav-subsections">
                  {subs.map(sub => (
                    <button
                      key={sub.id}
                      className={`nav-sub${activeSub === sub.id ? ' active' : ''}`}
                      onClick={() => onJump(section.id, sub.id)}
                    >
                      <span className="sub-num">{sub.id}</span>{sub.title}
                    </button>
                  ))}
                </div>
              )}
            </div>
          );
        })}

        {fastTrack && (
          <button
            className="nav-show-all"
            onClick={onToggleShowAll}
            title={showAllSections ? 'Hide non-fast-track sections' : 'Reveal the full set of v1 sections'}
          >
            {showAllSections ? '▾ Hide non-fast-track sections' : '▸ Show all sections'}
          </button>
        )}
      </div>

      <div className="sidebar-footer">
        {onSendForAnalysis && (
          <>
            <button
              className="sidebar-send-for-analysis"
              onClick={onSendForAnalysis}
              disabled={sendDisabled}
              title={sendDisabledReason || (sendDisabled ? 'Already sent — reopen the session to send again.' : 'Flip status to Ready for analysis and notify the operator')}
            >
              ✦ Send for analysis →
            </button>
            {sendDisabledReason && (
              <div style={{ fontSize: 11, color: 'var(--brook-amber)', textAlign: 'center', marginTop: -4, marginBottom: 4, fontWeight: 500 }}>
                {sendDisabledReason}
              </div>
            )}
          </>
        )}
        <button onClick={() => onJump('ai')}>
          <span style={{ color: 'var(--brook-amber)' }}>✦</span> Open AI Assist
        </button>
        <button onClick={onShowReport} className="primary">
          📄 Generate Report
        </button>
        <button onClick={onShowLog}>
          📚 Consultation Log
        </button>
        <div style={{ display: 'flex', gap: 6 }}>
          <button onClick={onExport} style={{ flex: 1, fontSize: 12 }} title="Export as brook-consultancy JSON envelope">
            ↓ Export JSON
          </button>
          <button onClick={onImport} style={{ flex: 1, fontSize: 12 }} title="Import from a brook-consultancy JSON file">
            ↑ Import
          </button>
        </div>
        <button onClick={onResetSession} style={{ color: 'var(--text-soft)', fontSize: 12 }}>
          ↻ New Consultation / Reset
        </button>
      </div>
    </div>
  );
}

// ---------------------------------------------------------------
// Record pill — sits in the header next to the timer.
// Click to start; while recording shows duration + audio level meter;
// click to stop and start the background upload.
// ---------------------------------------------------------------
function RecordPill({ recorder }) {
  const { state, durationSec, level, uploadProgress, error } = recorder;

  const isIdle      = state === 'idle' || state === 'failed' || state === 'interrupted';
  const isRequesting = state === 'requesting';
  const isLive      = state === 'recording';
  const isPaused    = state === 'paused';
  const isStopping  = state === 'stopping';
  const isUploading = state === 'uploading';
  const isComplete  = state === 'complete';

  const onClick = () => {
    if (isIdle) return recorder.start();
    if (isLive || isPaused) return recorder.stop();
    // While requesting/stopping/uploading, do nothing.
  };

  let title = 'Click to start recording';
  if (isLive) title = 'Recording — click to stop and upload';
  else if (isPaused) title = 'Paused (timer paused) — click to stop and upload';
  else if (isRequesting) title = 'Requesting microphone permission…';
  else if (isStopping) title = 'Stopping…';
  else if (isUploading) title = `Uploading to Drive… ${uploadProgress}%`;
  else if (isComplete) title = `Audio recording attached (${window.fmtDuration(durationSec)})`;
  else if (state === 'failed') title = error || 'Recording failed — click to retry';
  else if (state === 'interrupted') title = 'Recording was interrupted — start a new recording';

  const cls = [
    'record-pill',
    isLive ? 'live' : '',
    isPaused ? 'paused' : '',
    isUploading ? 'uploading' : '',
    isComplete ? 'complete' : '',
    state === 'failed' ? 'failed' : ''
  ].filter(Boolean).join(' ');

  return (
    <button
      type="button"
      className={cls}
      onClick={onClick}
      disabled={isRequesting || isStopping || isUploading}
      title={title}
    >
      {/* Icon */}
      {isLive && <span className="record-dot live-dot" aria-hidden />}
      {isPaused && <span className="record-dot paused-dot" aria-hidden />}
      {isRequesting && <span className="record-dot pending-dot" aria-hidden />}
      {isStopping && <span className="record-dot pending-dot" aria-hidden />}
      {isUploading && <span className="record-dot uploading-dot" aria-hidden />}
      {isComplete && <span className="record-check" aria-hidden>✓</span>}
      {isIdle && <span className="record-dot idle-dot" aria-hidden />}

      {/* Label */}
      <span className="record-label">
        {isIdle && 'Record'}
        {isRequesting && 'Mic…'}
        {isLive && (
          <>
            <span className="record-live-text">REC</span>
            <span className="record-duration">{window.fmtDuration(durationSec)}</span>
          </>
        )}
        {isPaused && (
          <>
            <span className="record-paused-text">Paused</span>
            <span className="record-duration">{window.fmtDuration(durationSec)}</span>
          </>
        )}
        {isStopping && 'Stopping…'}
        {isUploading && (
          <>
            <span>Uploading</span>
            <span className="record-duration">{uploadProgress}%</span>
          </>
        )}
        {isComplete && (
          <>
            <span>Recorded</span>
            <span className="record-duration">{window.fmtDuration(durationSec)}</span>
          </>
        )}
        {state === 'failed' && 'Retry'}
        {state === 'interrupted' && 'Record'}
      </span>

      {/* Audio level meter — only while live */}
      {isLive && (
        <span className="record-meter" aria-hidden>
          <span className="record-meter-fill" style={{ width: `${Math.round(level * 100)}%` }} />
        </span>
      )}
    </button>
  );
}

// ---------------------------------------------------------------
// HEADER
// ---------------------------------------------------------------
function AppHeader({ store, sessionTimer, onAutoComplete, onLock, onAiAssist, role, onGoQueue, recorder }) {
  const f = (store.data && store.data.fields) || {};
  const orgName = f.org_name || (role === 'operator' ? 'Operator console' : 'New Consultation');
  const roleLabel = role === 'operator' ? 'OPERATOR' : role === 'consultant' ? 'CONSULTANT' : null;
  return (
    <div className="app-header">
      <div className="brand-mark">
        <BrookMark size={32} light />
        <div className="brand-text">
          <div className="name">Brook Consultancy</div>
          <div className="sub">Consultation Tool</div>
        </div>
      </div>
      <div className="header-divider"></div>
      <div className="header-context">
        {roleLabel && <span className="header-role-pill">{roleLabel}</span>}
        {role === 'operator' && onGoQueue && (
          <button className="btn-ghost-light" style={{ padding: '4px 10px', fontSize: 12 }} onClick={onGoQueue}>← Queue</button>
        )}
        <span style={{ fontWeight: 500 }}>{orgName}</span>
        {f.client_contact_name && <span className="pill">👤 {f.client_contact_name}</span>}
        {f.consultation_method && <span className="pill">{f.consultation_method}</span>}
      </div>
      <div className="header-actions">
        <span className={`save-indicator ${store.saveStatus}`}>
          {store.saveStatus === 'saving' && '○ Saving…'}
          {store.saveStatus === 'saved' && <><span className="check">✓</span> Saved</>}
          {store.saveStatus === 'error' && '⚠ Save failed'}
        </span>
        <span className={`session-timer${sessionTimer.paused ? ' paused' : ''}`}>
          <button
            type="button"
            className="session-timer-btn"
            onClick={sessionTimer.toggle}
            title={sessionTimer.paused ? 'Paused — click to resume' : 'Running — click to pause'}
            aria-label={sessionTimer.paused ? 'Resume timer' : 'Pause timer'}
            aria-pressed={sessionTimer.paused}
          >
            {sessionTimer.paused ? (
              <svg className="session-timer-icon" viewBox="0 0 10 10" aria-hidden>
                <path d="M2 1 L9 5 L2 9 Z" />
              </svg>
            ) : (
              <svg className="session-timer-icon" viewBox="0 0 10 10" aria-hidden>
                <rect x="1.5" y="1" width="2.5" height="8" />
                <rect x="6" y="1" width="2.5" height="8" />
              </svg>
            )}
          </button>
          <span className="session-timer-time">{sessionTimer.formatted}</span>
        </span>
        {recorder && <RecordPill recorder={recorder} />}
        <button className="btn-autocomplete" onClick={onAiAssist}>
          <span className="icon">✦</span>
          AI Assist
        </button>
        <button className="btn-ghost-light" onClick={onLock} title="Lock the session">🔒</button>
      </div>
    </div>
  );
}

// ---------------------------------------------------------------
// MAIN APP
// ---------------------------------------------------------------
function App() {
  // Resolve role once on boot. The public booking page short-circuits
  // before any of the v1 chrome / store / PIN gate runs.
  const role = (window.brookGetRole && window.brookGetRole()) || 'consultant';
  const roleFlags = (window.brookRoleFlags && window.brookRoleFlags()) || {};

  // Public booking page: no PIN, no sync polling, no consultation store needed.
  if (role === 'book') {
    return <window.BookingPage />;
  }

  // TV kiosk: no PIN, no consultation store needed.
  if (role === 'tv') {
    return <window.TVDisplay />;
  }

  return <AppShell role={role} roleFlags={roleFlags} />;
}

function AppShell({ role, roleFlags }) {
  const pin = window.usePinGate();
  const store = window.useConsultation();
  // Session timer is now keyed off the active record's start time so each
  // consultation shows its own elapsed time across reloads.
  const sessionTimer = window.useSessionTimer(store.data?._started_at, store.activeRecordId);
  const consultationLog = window.useConsultationLog(store.store);
  // Recorder is per-active-record; only consultant + office roles see the
  // record pill in the header (operator + tv + book don't need it).
  const recorder = (window.useRecorder ? window.useRecorder({ record: store.data, store }) : null);
  const showRecorder = (role === 'consultant' || role === 'office') && !!store.data;

  // Pause / resume the recording in lockstep with the session timer's
  // pause / resume state. The brief locked this in: timer pause = recording
  // pause, so the audio file has no silent gaps.
  React.useEffect(() => {
    if (!recorder) return;
    if (sessionTimer.paused && recorder.state === 'recording') recorder.pauseRec();
    else if (!sessionTimer.paused && recorder.state === 'paused') recorder.resumeRec();
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [sessionTimer.paused]);

  // Operator role lands on the queue; consultant/office land on a section.
  const [activeSection, setActiveSection] = React.useState(role === 'operator' ? 'queue' : '1');
  const [activeSub, setActiveSub] = React.useState('1.1');
  const [showAllSections, setShowAllSections] = React.useState(false);
  const [showAutoComplete, setShowAutoComplete] = React.useState(false);
  const [showReport, setShowReport] = React.useState(false);
  const [showLog, setShowLog] = React.useState(false);
  const [showTweaks, setShowTweaks] = React.useState(false);
  const [tweaks, setTweaks] = React.useState(TWEAK_DEFAULTS);
  const [autofillBanner, setAutofillBanner] = React.useState(null);

  const mainRef = React.useRef(null);

  // Log is derived directly from the multi-record store now — no explicit upsert needed.

  // Apply default tweaks on mount
  React.useEffect(() => { applyTweaks(tweaks); }, []);

  // Tweaks message protocol
  React.useEffect(() => {
    const handler = (e) => {
      if (!e.data || !e.data.type) return;
      if (e.data.type === '__activate_edit_mode') setShowTweaks(true);
      if (e.data.type === '__deactivate_edit_mode') setShowTweaks(false);
    };
    window.addEventListener('message', handler);
    try { window.parent.postMessage({ type: '__edit_mode_available' }, '*'); } catch {}
    return () => window.removeEventListener('message', handler);
  }, []);

  // Keyboard: Cmd/Ctrl+K → AI Assist screen
  React.useEffect(() => {
    const onKey = (e) => {
      if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === 'k') {
        e.preventDefault();
        jumpTo('ai');
      }
    };
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, []);

  const jumpTo = (sectionId, subId) => {
    setActiveSection(sectionId);
    setActiveSub(subId || (window.BROOK_SCHEMA.sections.find(s => s.id === sectionId)?.subs[0]?.id));
    if (mainRef.current) mainRef.current.scrollTop = 0;
    if (subId) {
      // Defer the scroll so that the subsection is rendered
      setTimeout(() => {
        const el = document.getElementById(`sub-${subId}`);
        if (el && mainRef.current) {
          const top = el.offsetTop - 24;
          mainRef.current.scrollTo({ top, behavior: 'smooth' });
        }
      }, 60);
    }
  };

  const handleAutofillResult = ({ raw, mapped, summary, transcript }) => {
    store.applyAutofill(mapped, { summary, transcript });
    setAutofillBanner({ type: 'amber', text: 'Auto-fill complete — please review all highlighted (amber) fields before generating your report.' });
    // Jump to dashboard if any AI areas were returned
    const areaIds = Object.keys(mapped.aiResults || {}).filter(k => !['statutory','findings','executive_summary'].includes(k));
    if (areaIds.length > 0) jumpTo('11');
  };

  const exportConsultation = () => {
    const filename = window.downloadExport(store.data, { consultancyName: 'Brook Consultancy Partners Ltd', consultantName: store.data.fields.consultant_name });
    setAutofillBanner({ type: 'success', text: `Exported as ${filename}. The file uses the brook-consultancy envelope and is ready to feed into your downstream agent.` });
  };

  const importConsultation = () => {
    const input = document.createElement('input');
    input.type = 'file';
    input.accept = '.json,.txt,application/json,text/plain';
    input.onchange = async () => {
      const file = input.files && input.files[0];
      if (!file) return;
      try {
        const text = await file.text();
        const env = JSON.parse(text);
        const data = window.parseImportEnvelope(env);
        if (!confirm(`Import consultation for "${env.consultation?.setting?.organisationName || 'unnamed organisation'}"?\n\nThis will replace the current consultation on this device. The current data will remain in the consultation log.`)) return;
        store.replaceAll(data);
        setActiveSection('1');
        setActiveSub('1.1');
        setAutofillBanner({ type: 'success', text: `Imported consultation from ${file.name}. All fields, AI results, and source content restored.` });
      } catch (e) {
        setAutofillBanner({ type: 'error', text: `Import failed: ${e.message}` });
      }
    };
    input.click();
  };

  const resetSession = () => {
    if (!confirm('Start a new consultation? A new record will be created on this device. (Existing consultations remain in the log and stay accessible.)')) return;
    store.newRecord();
    setActiveSection('1');
    setActiveSub('1.1');
    setAutofillBanner(null);
  };

  const loadLogEntry = (id) => {
    // v2: re-opening past records is now first-class. Just switch the active record.
    store.switchTo(id);
    setShowLog(false);
    setActiveSection('1');
    setActiveSub('1.1');
    setAutofillBanner(null);
  };

  const claimAndOpen = (id) => {
    // Stamp claimedBy + status, then switch in.
    store.setStore(prev => {
      const rec = prev.records[id];
      if (!rec) return prev;
      return {
        ...prev,
        records: {
          ...prev.records,
          [id]: { ...rec, claimedBy: prev.deviceId, status: 'analysing', updatedAt: new Date().toISOString() }
        },
        activeRecordId: id
      };
    });
    setShowLog(false);
    setActiveSection('ai');
    setActiveSub(null);
    setAutofillBanner(null);
  };

  const deleteLogEntry = (id) => {
    if (!confirm('Delete this consultation from this device? This cannot be undone.')) return;
    store.removeRecord(id);
  };

  if (!pin.unlocked) return <PinGate onUnlock={pin.tryUnlock} />;

  if (showReport) {
    return <window.ReportView
      data={store.data}
      onBack={() => setShowReport(false)}
      onMarkComplete={role === 'operator' ? () => {
        store.updateActive(d => ({ ...d, status: 'complete', updatedAt: new Date().toISOString() }));
      } : null}
    />;
  }

  const section = window.BROOK_SCHEMA.sections.find(s => s.id === activeSection);
  const isAi = activeSection === 'ai';
  const isQueue = activeSection === 'queue';
  const isOperator = role === 'operator';
  const isConsultant = role === 'consultant';
  const isFastTrack = isConsultant && !showAllSections;

  // Read-only banner — consultant sees this when the active record has been
  // sent for analysis or completed by the operator.
  const readOnly = isConsultant && store.data && store.data.status && store.data.status !== 'in_progress';

  const sendForAnalysis = () => {
    store.updateActive(d => ({ ...d, status: 'ready_for_analysis', updatedAt: new Date().toISOString() }));
    setAutofillBanner({ type: 'success', text: "Sent to analyst — the client will receive their one-pager within 5 minutes." });
    setActiveSection('sent');
  };
  const reopenForEditing = () => {
    store.updateActive(d => ({ ...d, status: 'in_progress', claimedBy: null, updatedAt: new Date().toISOString() }));
    setAutofillBanner(null);
  };
  const markArrived = (id) => {
    store.setStore(prev => {
      const r = prev.records[id];
      if (!r || r.kind !== 'booking') return prev;
      return { ...prev, records: { ...prev.records, [id]: { ...r, status: 'arrived', updatedAt: new Date().toISOString() } } };
    });
  };
  const convertBooking = (id) => {
    const newId = store.convertBookingToConsultation(id);
    if (newId) {
      setActiveSection('1');
      setActiveSub('1.1');
    }
  };

  return (
    <>
      <div className={`app${isOperator ? ' app-operator' : ''}${recorder?.state === 'recording' ? ' app-recording' : ''}`}>
        <AppHeader
          store={store}
          sessionTimer={sessionTimer}
          onAiAssist={() => jumpTo('ai')}
          onLock={() => pin.lock()}
          role={role}
          onGoQueue={() => setActiveSection('queue')}
          recorder={showRecorder ? recorder : null}
        />

        <window.SyncBanner
          store={store.store}
          setStore={store.setStore}
          role={role}
        />

        <div className="gdpr-banner">
          <span className="lock">🔒</span>
          <span>
            <strong>GDPR notice — </strong>
            Information captured here is confidential and must be handled in line with Brook Consultancy's data protection policy. Auto-saves locally to this device only.
          </span>
        </div>

        {!isOperator && (
          <Sidebar
            activeSection={activeSection}
            activeSub={activeSub}
            onJump={jumpTo}
            store={store}
            onShowReport={() => setShowReport(true)}
            onShowLog={() => setShowLog(true)}
            onResetSession={resetSession}
            onExport={exportConsultation}
            onImport={importConsultation}
            fastTrack={isFastTrack}
            showAllSections={showAllSections}
            onToggleShowAll={() => setShowAllSections(s => !s)}
            onSendForAnalysis={isConsultant ? sendForAnalysis : null}
            sendDisabled={
              !store.data ||
              store.data.status !== 'in_progress' ||
              recorder?.state === 'recording' ||
              recorder?.state === 'paused' ||
              recorder?.state === 'uploading' ||
              recorder?.state === 'stopping'
            }
            sendDisabledReason={
              recorder?.state === 'recording' ? 'Stop the recording first.' :
              recorder?.state === 'paused' ? 'Stop the recording first.' :
              recorder?.state === 'uploading' ? `Waiting for audio upload (${recorder.uploadProgress}%)…` :
              recorder?.state === 'stopping' ? 'Finishing recording…' : null
            }
          />
        )}

        <div className={`main-area${isOperator ? ' main-area-full' : ''}`} ref={mainRef}>
          {recorder?.state === 'recording' && (
            <div className="recording-indicator">
              <span className="recording-indicator-dot" />
              <span><strong>Recording in progress.</strong> The audio will upload to Drive when you click Stop.</span>
              <span className="recording-indicator-duration">{window.fmtDuration(recorder.durationSec)}</span>
            </div>
          )}
          {recorder?.state === 'paused' && (
            <div className="recording-indicator paused">
              <span className="recording-indicator-dot" />
              <span><strong>Recording paused.</strong> Resume the timer to continue.</span>
              <span className="recording-indicator-duration">{window.fmtDuration(recorder.durationSec)}</span>
            </div>
          )}
          {recorder?.state === 'uploading' && (
            <div className="recording-indicator uploading">
              <span className="recording-indicator-dot uploading-dot" />
              <span><strong>Uploading audio to Drive — {recorder.uploadProgress}%</strong>. The Send-for-analysis button will enable when upload completes.</span>
              <div className="recording-indicator-progress"><div className="recording-indicator-progress-fill" style={{ width: `${recorder.uploadProgress}%` }} /></div>
            </div>
          )}
          {recorder?.state === 'failed' && recorder.error && (
            <div className="recording-indicator failed">
              <span className="recording-indicator-dot failed-dot" />
              <span><strong>Audio upload failed.</strong> {recorder.error}</span>
              <button className="btn" style={{ padding: '4px 12px', fontSize: 12 }} onClick={recorder.retryUpload}>Retry upload</button>
            </div>
          )}
          {recorder?.state === 'interrupted' && (
            <div className="recording-indicator failed">
              <span className="recording-indicator-dot failed-dot" />
              <span><strong>Recording was interrupted by a page reload.</strong> Any audio captured before the reload was lost. Start a new recording if needed.</span>
            </div>
          )}
          {autofillBanner && (
            <div className={`app-banner ${autofillBanner.type === 'amber' ? '' : autofillBanner.type}`}>
              <span><strong>✦ </strong>{autofillBanner.text}</span>
              <button className="dismiss" onClick={() => setAutofillBanner(null)}>×</button>
            </div>
          )}
          {readOnly && (
            <div className="app-banner" style={{ background: '#fef3c7', borderBottomColor: '#e8d8a8', color: '#6e5314' }}>
              <span>
                <strong>This session is with the analyst.</strong> Edits won't sync until you reopen it. Status: <em>{window.statusMeta(store.data.status).label}</em>.
              </span>
              <button className="btn" style={{ padding: '4px 10px', fontSize: 12 }} onClick={reopenForEditing}>
                Reopen for editing
              </button>
            </div>
          )}
          <div className="main-content" style={isOperator ? { maxWidth: 1200, padding: '24px 32px 80px' } : {}}>
            {activeSection === 'sent' && (
              <SessionSentLanding onNew={() => { store.newRecord(); setActiveSection('1'); setActiveSub('1.1'); setAutofillBanner(null); }} />
            )}
            {isQueue && (
              <window.OperatorQueue
                store={store.store}
                log={consultationLog.log.map(e => {
                  // attach the booking's headline_challenge for the operator row
                  if (e.kind === 'booking') {
                    const r = store.store.records[e.id];
                    if (r) e._headline_challenge = r.booking?.headline_challenge || '';
                  }
                  return e;
                })}
                onClaim={claimAndOpen}
                onOpen={loadLogEntry}
                onConvertBooking={convertBooking}
                onMarkArrived={markArrived}
                onNewConsultation={() => { store.newRecord(); setActiveSection('1'); setActiveSub('1.1'); }}
              />
            )}
            {isAi && <window.AiAssistView store={store} onJumpToDashboard={() => jumpTo('11')} />}
            {!isAi && !isQueue && activeSection !== 'sent' && section && <window.SectionView section={section} store={store} />}
          </div>
        </div>
      </div>

      <window.QuickCapture />

      {showLog && (
        <window.ConsultationLog
          log={consultationLog.log}
          activeRecordId={store.activeRecordId}
          onClose={() => setShowLog(false)}
          onLoad={loadLogEntry}
          onClaim={claimAndOpen}
          onDelete={deleteLogEntry}
          onNew={() => { setShowLog(false); resetSession(); }}
        />
      )}

      {showTweaks && (
        <TweaksPanel tweaks={tweaks} setTweaks={setTweaks} onClose={() => setShowTweaks(false)} />
      )}
    </>
  );
}

// ---------------------------------------------------------------
// SessionSentLanding — shown to consultant after Send for analysis
// ---------------------------------------------------------------
function SessionSentLanding({ onNew }) {
  return (
    <div style={{ maxWidth: 560, margin: '80px auto', textAlign: 'center', padding: '40px 24px' }}>
      <div style={{ width: 72, height: 72, margin: '0 auto 24px', borderRadius: '50%', background: 'var(--brook-amber-bg)', border: '2px solid var(--brook-amber)', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 32, color: 'var(--brook-amber)' }}>✦</div>
      <h1 style={{ fontSize: 28, marginBottom: 12 }}>Sent to analyst</h1>
      <p style={{ color: 'var(--text-soft)', fontSize: 15, lineHeight: 1.55, marginBottom: 28 }}>
        Your notes are with the operator. They'll run the AI analysis, push an anonymised insight to the stand TVs, and email the client their one-pager within the next 5 minutes.
      </p>
      <p style={{ color: 'var(--text-soft)', fontSize: 14, marginBottom: 32 }}>
        Take a breath, see your client off warmly, point them at coffee — and start the next session when you're ready.
      </p>
      <button className="btn btn-primary" style={{ padding: '12px 24px', fontSize: 15 }} onClick={onNew}>
        Start new session →
      </button>
    </div>
  );
}

Object.assign(window, { App, AppShell, BrookMark, BrookLockup, SessionSentLanding });
