// Session screen — real WebSocket mode + scripted demo fallback
const { useState: uS, useEffect: uE, useRef: uR } = React;

const DEMO_SCRIPTS = {
  Interview: [
    { side: "them", text: "So, walk me through a system you're really proud of. Something you architected end-to-end." },
    { side: "you",  text: "Sure. The most fun one was a billing reconciliation pipeline at my last role…" },
    { side: "them", text: "How did you handle partial failures — like when a payment provider returns 500 mid-batch?" },
    { side: "you",  text: "We split the batch into idempotent jobs with a per-row retry queue…" },
    { side: "them", text: "And how did you know it actually worked? What were you measuring?" },
  ],
  Sales: [
    { side: "them", text: "We're already using HubSpot, so honestly I'm not sure what you'd add for us." },
    { side: "you",  text: "Totally fair. Can I ask — what's the one workflow that still feels manual today?" },
    { side: "them", text: "Probably routing inbound leads to the right rep. It takes ages." },
  ],
  "1:1": [
    { side: "them", text: "How are you feeling about your current scope? Anything you want to talk about?" },
    { side: "you",  text: "Honestly — I think I'm ready for more ownership on the platform team…" },
    { side: "them", text: "What would that look like for you, concretely?" },
  ],
  Other: [
    { side: "them", text: "Tell me more about what you're working on right now." },
    { side: "you",  text: "We just shipped a beta version of the onboarding redesign." },
    { side: "them", text: "And what's the early signal looking like?" },
  ],
};

const HINTS = {
  Interview: [
    "Lead with the specific metric (e.g. failed-charge rate dropping 40%).",
    "Mention what you'd measure if you ran it again.",
    "End with the business outcome — money saved or churn avoided.",
  ],
  Sales: [
    "Acknowledge their setup — don't compete with HubSpot, complement it.",
    "Anchor on the painful workflow they just named.",
    "Offer a 10-min walkthrough specifically on inbound routing.",
  ],
  "1:1": [
    "Be concrete: name the team, the projects, the timeline.",
    "Tie it to business impact, not just personal growth.",
    "Have one ask ready (a stretch project, a mentor, a comp review).",
  ],
  Other: [
    "Share one early metric or piece of user feedback.",
    "Be honest about what's still unclear or risky.",
    "Invite their perspective — what would they want to see next?",
  ],
};

function StatusPill({ on, label }) {
  return (
    <span className={"status-pill" + (on ? " on" : "")}>
      <span className="status-dot" />
      {label}
    </span>
  );
}

function FlowStepper({ step1Done, step2Done, st }) {
  const active = !step1Done ? 1 : 2;
  const steps = [
    { n: 1, label: st.step1, sub: step1Done ? st.step1done : st.step1sub, done: step1Done },
    { n: 2, label: st.step2, sub: step2Done ? st.step2done : st.step2sub, done: step2Done },
  ];
  return (
    <div className="flow-stepper">
      {steps.map((s, i) => (
        <React.Fragment key={s.n}>
          <button
            className={"flow-step" + (s.done ? " is-done" : "") + (active === s.n ? " is-active" : "")}
            disabled
          >
            <span className="flow-bullet">{s.done ? "✓" : s.n}</span>
            <span className="flow-meta">
              <span className="flow-label">{s.label}</span>
              <span className="flow-sub">{s.sub}</span>
            </span>
          </button>
          {i < steps.length - 1 && <span className={"flow-arrow" + (s.done ? " is-done" : "")} />}
        </React.Fragment>
      ))}
    </div>
  );
}

function previewText(text, maxLen = 180) {
  if (!text?.trim()) return null;
  const sentences = text.match(/[^.!?\n]+[.!?\n]*/g) || [];
  let out = sentences.slice(0, 3).join("").trim();
  if (out.length > maxLen) out = out.slice(0, maxLen).trimEnd() + "…";
  if (!out) out = text.slice(0, maxLen).trimEnd() + (text.length > maxLen ? "…" : "");
  return out;
}

function ContextModal({ open, onClose, label, value, onSave, placeholder }) {
  const [draft, setDraft] = uS(value || "");
  uE(() => { if (open) setDraft(value || ""); }, [open, value]);
  if (!open) return null;
  return (
    <div className="modal-backdrop" onClick={(e) => { if (e.target === e.currentTarget) onClose(); }}>
      <div className="ctx-modal">
        <div className="ctx-modal-head">
          <h3>{label}</h3>
          <button className="modal-x" onClick={onClose}>×</button>
        </div>
        <textarea
          className="ctx-modal-textarea"
          value={draft}
          onChange={(e) => setDraft(e.target.value)}
          placeholder={placeholder}
          autoFocus
        />
        <div className="ctx-modal-foot">
          <button className="btn btn-ghost" onClick={onClose}>Скасувати</button>
          <button className="btn btn-primary" onClick={() => { onSave(draft); onClose(); }}>Зберегти</button>
        </div>
      </div>
    </div>
  );
}

function ContextField({ label, value, onSave, placeholder, required, requiredBadge }) {
  const [open, setOpen] = uS(false);
  const preview = previewText(value);
  const isEmpty = !value?.trim();
  return (
    <React.Fragment>
      <div className={"ctx-field-card" + (isEmpty && required ? " is-required" : "")} onClick={() => setOpen(true)}>
        <div className="ctx-field-card-header">
          <span className="ctx-field-card-label">{label}</span>
          {required && isEmpty
            ? <span className="ctx-field-badge required">{requiredBadge || "fill in"}</span>
            : !required && isEmpty
              ? <span className="ctx-field-badge optional">optional</span>
              : <span className="ctx-field-badge filled">✓</span>}
        </div>
        {isEmpty
          ? <div className="ctx-field-card-ph">{placeholder}</div>
          : <div className="ctx-field-card-preview">{preview}</div>}
      </div>
      <ContextModal open={open} onClose={() => setOpen(false)} label={label} value={value} onSave={onSave} placeholder={placeholder} />
    </React.Fragment>
  );
}

function fmt(sec) {
  const m = Math.floor(sec / 60), s = sec % 60;
  return [String(m).padStart(2, "0"), String(s).padStart(2, "0")];
}

function AccountChip({ onSignIn }) {
  const auth = (typeof useAuth === 'function') ? useAuth() : { user: null };
  const [open, setOpen] = uS(false);

  if (!auth.user) {
    return (
      <button className="btn btn-ghost btn-sm" onClick={onSignIn} style={{ whiteSpace: 'nowrap' }}>
        Увійти
      </button>
    );
  }

  const letter = (auth.user.user_metadata?.full_name || auth.user.email || '?')[0].toUpperCase();
  return (
    <div style={{ position: 'relative' }}>
      <button
        onClick={() => setOpen(o => !o)}
        title={auth.user.email}
        style={{ width: 32, height: 32, borderRadius: '50%', background: 'var(--accent)', color: '#fff', border: 'none', cursor: 'pointer', fontWeight: 700, fontSize: 14, display: 'flex', alignItems: 'center', justifyContent: 'center' }}
      >
        {letter}
      </button>
      {open && (
        <React.Fragment>
          <div style={{ position: 'fixed', inset: 0, zIndex: 99 }} onClick={() => setOpen(false)} />
          <div style={{ position: 'absolute', top: 38, right: 0, background: '#fff', border: '1px solid #e5e7eb', borderRadius: 10, boxShadow: '0 4px 16px rgba(0,0,0,.1)', padding: '6px 0', minWidth: 180, zIndex: 100 }}>
            <div style={{ padding: '6px 14px 8px', fontSize: 12.5, color: '#6b7280', borderBottom: '1px solid #f3f4f6', marginBottom: 4 }}>{auth.user.email}</div>
            <button
              onClick={() => { setOpen(false); window.MH_Auth.signOut(); }}
              style={{ width: '100%', padding: '8px 14px', textAlign: 'left', background: 'none', border: 'none', cursor: 'pointer', fontSize: 13.5, color: '#374151' }}
              onMouseEnter={e => e.currentTarget.style.background = '#f9fafb'}
              onMouseLeave={e => e.currentTarget.style.background = 'none'}
            >
              Sign out
            </button>
          </div>
        </React.Fragment>
      )}
    </div>
  );
}

function Session({ t, lang, setLang, onCTAUnlock, onClose, unlocked, meetingType, setMeetingType, context, setContext, company, setCompany, onSignIn }) {
  const ts = t.session;
  const auth = (typeof useAuth === 'function') ? useAuth() : { user: null, invite: '' };
  const needsSignIn = !auth.user && !auth.invite;
  const [running, setRunning] = uS(false);
  const [lines, setLines] = uS([]);
  const [hints, setHints] = uS([]);
  const [thinking, setThinking] = uS(false);
  const [contextSize, setContextSize] = uS(20);
  const [editingIdx, setEditingIdx] = uS(null);
  const [editDraft, setEditDraft] = uS("");
  const [trialLeft, setTrialLeft] = uS(window.MH_TRIAL_SECONDS || 300);
  const [paywallOpen, setPaywallOpen] = uS(false);
  const [statusMsg, setStatusMsg] = uS("");
  const [isDemo, setIsDemo] = uS(false);
  const [hasTabVideo, setHasTabVideo] = uS(false);
  const [hintFormat, setHintFormat] = uS(() => localStorage.getItem('mh-hint-format') || 'bullets');

  // Real mode refs
  const micWsRef = uR(null);
  const tabWsRef = uR(null);
  const micStreamRef = uR(null);
  const tabStreamRef = uR(null);
  const tabVideoRef = uR(null);
  const tabAccRef = uR("");
  const isSuggestingRef = uR(false);
  const messagesRef = uR([]);
  const transcriptRef = uR(null);
  const langRef = uR(lang);
  const runningRef = uR(running);
  const unlockedRef = uR(unlocked);
  const authUserIdRef = uR(auth.user?.id);
  uE(() => { authUserIdRef.current = auth.user?.id; }, [auth.user?.id]);
  uE(() => { runningRef.current = running; }, [running]);
  uE(() => { unlockedRef.current = unlocked; }, [unlocked]);
  uE(() => {
    langRef.current = lang;
    if (!runningRef.current) return;
    // Reconnect Deepgram with new language — close old WS, keep media streams alive
    [micWsRef.current, tabWsRef.current].forEach(ws => {
      if (!ws) return;
      try { ws._recorder?.stop(); } catch {}
      try { ws.close(); } catch {}
    });
    micWsRef.current = null;
    tabWsRef.current = null;
    openConnections(micStreamRef.current, tabStreamRef.current);
  }, [lang]);

  // Auto-scroll transcript to top (newest) — newest is first in reversed render
  uE(() => {
    if (transcriptRef.current) transcriptRef.current.scrollTop = 0;
  }, [lines]);

  // Demo mode refs
  const stepIdx = uR(0);
  const timers = uR([]);

  const cleanTimers = () => { timers.current.forEach(clearTimeout); timers.current = []; };

  uE(() => () => { cleanTimers(); stopReal(); }, []);

  // Server-side minute tick — deduct 1 min/60s from DB, update display
  uE(() => {
    if (!running || !unlocked || auth.invite || auth.plan === 'pro') return;
    const tick = async () => {
      const token = typeof window.MH_getToken === 'function' ? await window.MH_getToken() : null;
      if (!token) return;
      try {
        const res = await fetch('/api/session/tick', {
          method: 'POST',
          headers: { 'Authorization': `Bearer ${token}` },
        });
        const data = await res.json();
        window.MH_Auth?.syncCredits(authUserIdRef.current, data.minutes);
        if (data.out_of_credits) {
          setStatusMsg('Хвилини закінчились — сесію зупинено');
          stopAll();
        }
      } catch {}
    };
    const id = setInterval(tick, 60000);
    return () => clearInterval(id);
  }, [running, unlocked]);

  // Trial countdown — 10s grace period prevents auth token refresh flicker
  // from triggering the trial timer mid-session
  uE(() => {
    if (!running || unlocked) return;
    let id;
    const grace = setTimeout(() => {
      if (unlockedRef.current) return; // auth recovered during grace period
      id = setInterval(() => {
        setTrialLeft(s => {
          if (s <= 1) { clearInterval(id); setRunning(false); setPaywallOpen(true); return 0; }
          return s - 1;
        });
      }, 1000);
    }, 10000);
    return () => { clearTimeout(grace); clearInterval(id); };
  }, [running, unlocked]);

  // ---- REAL MODE ----
  const startReal = async () => {
    if (trialLeft <= 0 && !unlocked) { setPaywallOpen(true); return; }

    setStatusMsg("Запит дозволу мікрофона...");
    let mic;
    try {
      mic = await navigator.mediaDevices.getUserMedia({
        audio: { echoCancellation: true, noiseSuppression: true }, video: false,
      });
    } catch {
      setStatusMsg("Не вдалося отримати мікрофон. Перевір дозволи браузера.");
      return;
    }

    setStatusMsg("Вибери вкладку (увімкни Share tab audio)...");
    let display;
    try {
      display = await navigator.mediaDevices.getDisplayMedia({
        video: true, audio: true, preferCurrentTab: false, selfBrowserSurface: "exclude",
      });
    } catch {
      mic.getTracks().forEach(tr => tr.stop());
      setStatusMsg("Скасовано — вибери вкладку і увімкни Share tab audio.");
      return;
    }

    const audioTracks = display.getAudioTracks();
    const videoTracks = display.getVideoTracks();
    const tab = new MediaStream(audioTracks);

    micStreamRef.current = mic;
    tabStreamRef.current = tab;
    if (videoTracks.length && tabVideoRef.current) {
      tabVideoRef.current.srcObject = new MediaStream(videoTracks);
      setHasTabVideo(true);
    }
    messagesRef.current = [];
    tabAccRef.current = "";

    setLines([]);
    setHints([]);
    setThinking(false);
    setIsDemo(false);
    setRunning(true);
    if (!audioTracks.length) setStatusMsg("Аудіо таба не отримано — увімкни Share tab audio");
    else setStatusMsg("");

    openConnections(mic, tab);
  };

  const openConnections = (mic, tab) => {
    const proto = location.protocol === "https:" ? "wss:" : "ws:";
    const base = `${proto}//${location.host}/ws`;
    micWsRef.current = connectWS(`${base}?speaker=mic&language=${langRef.current}`, mic, "mic");
    if (tab?.getTracks().length > 0) {
      tabWsRef.current = connectWS(`${base}?speaker=tab&language=${langRef.current}`, tab, "tab");
    }
  };

  const connectWS = (url, stream, speaker) => {
    const ws = new WebSocket(url);
    let recorder = null;
    ws.onopen = () => {
      const mimeType = MediaRecorder.isTypeSupported("audio/webm;codecs=opus") ? "audio/webm;codecs=opus" : "audio/webm";
      recorder = new MediaRecorder(stream, { mimeType });
      recorder.ondataavailable = (e) => {
        if (e.data.size > 0 && ws.readyState === WebSocket.OPEN) ws.send(e.data);
      };
      recorder.start(250);
    };
    ws.onmessage = (e) => { try { handleWsMsg(JSON.parse(e.data)); } catch {} };
    ws.onclose = () => { try { if (recorder?.state !== "inactive") recorder?.stop(); } catch {} };
    ws.onerror = () => setStatusMsg(`Помилка з'єднання (${speaker})`);
    ws._recorder = recorder;
    return ws;
  };

  const handleWsMsg = (msg) => {
    switch (msg.type) {
      case "ready":
        setStatusMsg("Активний — говори або слухай");
        break;
      case "transcript": {
        const { speaker, text, is_final, speech_final } = msg;
        const side = speaker === "mic" ? "you" : "them";
        if (!is_final) {
          setLines(prev => {
            let lastLiveIdx = -1;
            for (let i = prev.length - 1; i >= 0; i--) {
              if (prev[i].live && prev[i].side === side) { lastLiveIdx = i; break; }
            }
            if (lastLiveIdx >= 0) return prev.map((l, i) => i === lastLiveIdx ? { ...l, text } : l);
            return [...prev, { side, text, live: true }];
          });
        } else {
          setLines(prev => {
            const filtered = prev.filter(l => !(l.live && l.side === side));
            return text.trim() ? [...filtered, { side, text, live: false }] : filtered;
          });
          if (text.trim()) {
            messagesRef.current.push({ speaker, text });
            if (speaker === "tab") {
              tabAccRef.current += " " + text;
              if (speech_final) maybeSuggestOnFinal();
            }
          }
        }
        break;
      }
      case "utterance_end":
        if (msg.speaker === "tab") maybeSuggestOnPause();
        break;
      case "error":
        setStatusMsg("Deepgram: " + msg.message);
        break;
      case "deepgram_closed":
        setStatusMsg("⚠️ Транскрипція обірвалась — натисни Почати знову");
        stopAll();
        break;
      case "deepgram_reconnecting": {
        const sp = msg.speaker;
        setStatusMsg("Перепідключення...");
        const proto = location.protocol === "https:" ? "wss:" : "ws:";
        const base = `${proto}//${location.host}/ws`;
        if (sp === "mic") {
          try { micWsRef.current?.close(); } catch {}
          setTimeout(() => {
            if (!runningRef.current || !micStreamRef.current) return;
            micWsRef.current = connectWS(`${base}?speaker=mic&language=${langRef.current}`, micStreamRef.current, "mic");
          }, 300);
        } else {
          try { tabWsRef.current?.close(); } catch {}
          setTimeout(() => {
            if (!runningRef.current || !tabStreamRef.current?.getTracks().length) return;
            tabWsRef.current = connectWS(`${base}?speaker=tab&language=${langRef.current}`, tabStreamRef.current, "tab");
          }, 300);
        }
        setTimeout(() => setStatusMsg(""), 3000);
        break;
      }
    }
  };

  // Called on speech_final — only punctuation, never mid-sentence
  const maybeSuggestOnFinal = () => {
    const q = tabAccRef.current.trim();
    if (q.length < 15 || isSuggestingRef.current) return;
    if (/[?!.]$/.test(q)) {
      getSuggestion(q);
      tabAccRef.current = "";
    }
  };

  // Called on utterance_end (Deepgram 1s pause) — fire on accumulated content
  const maybeSuggestOnPause = () => {
    const q = tabAccRef.current.trim();
    if (q.length < 40 || isSuggestingRef.current) return;
    getSuggestion(q);
    tabAccRef.current = "";
  };

  // Map localized meeting type to English key for the API
  const TYPE_MAP = {
    "Співбесіда": "interview", "Interview": "interview", "Собеседование": "interview",
    "Продаж": "sales", "Sales": "sales", "Продажи": "sales",
    "1:1": "1on1",
    "Інше": "other", "Other": "other", "Другое": "other",
  };

  const getSuggestion = async (question, forced = false) => {
    isSuggestingRef.current = true;
    setThinking(true);
    const ctx = messagesRef.current.slice(-contextSize).map(m => ({ speaker: m.speaker, text: m.text }));
    const token = typeof window.MH_getToken === 'function' ? await window.MH_getToken() : null;
    try {
      const res = await fetch("/api/suggest", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          ...(token ? { "Authorization": `Bearer ${token}` } : {}),
        },
        body: JSON.stringify({ question, skills: [context, company ? `Company info: ${company}` : ""].filter(Boolean).join("\n\n"), context: ctx, meetingType: TYPE_MAP[meetingType] || "other", forced, lang, hintFormat }),
      });
      if (res.status === 402) {
        setThinking(false);
        isSuggestingRef.current = false;
        setStatusMsg('Хвилини закінчились — поповни баланс');
        stopAll();
        setPaywallOpen(true);
        return;
      }
      const reader = res.body.getReader();
      const decoder = new TextDecoder();
      let buf = "";
      let full = "";
      while (true) {
        const { done, value } = await reader.read();
        if (done) break;
        buf += decoder.decode(value, { stream: true });
        const parts = buf.split("\n");
        buf = parts.pop();
        for (const line of parts) {
          if (line.startsWith("data: ") && line !== "data: [DONE]") {
            try { const d = JSON.parse(line.slice(6)); if (d.text) full += d.text; } catch {}
          }
        }
      }
      const raw = full.split("\n").map(l => l.replace(/^[-–•*]\s*/, "").trim()).filter(Boolean);
      // Detect label lines: all-caps word(s) followed by |, with any spacing
      const LABEL_RE = /^[А-ЯІЇЄҐA-Z]{2,}[А-ЯІЇЄҐA-Z\s]{0,10}\|/;
      const isLabeled = raw.some(l => LABEL_RE.test(l));
      let bullets;
      if (isLabeled) {
        bullets = [];
        for (const line of raw) {
          if (LABEL_RE.test(line)) { bullets.push(line); }
          else if (bullets.length > 0) { bullets[bullets.length - 1] += ' ' + line; }
        }
        // Normalize pipe format so parseLabel always sees " | "
        bullets = bullets.map(b => b.replace(/^([А-ЯІЇЄҐA-Z][А-ЯІЇЄҐA-Z\s]*?)\s*\|\s*/, '$1 | '));
      } else {
        bullets = raw;
      }
      const meaningful = bullets.filter(b => !/^[\[—\-–\]]+$/.test(b) && b.length > 2);
      if (meaningful.length) setHints(prev => [{ bullets: meaningful }, ...prev]);
    } catch (err) {
      setHints(prev => [{ bullets: ["Помилка: " + err.message] }, ...prev]);
    } finally {
      isSuggestingRef.current = false;
      setThinking(false);
    }
  };

  const startEdit = (origIdx, text) => { setEditingIdx(origIdx); setEditDraft(text); };

  const saveEdit = (origIdx) => {
    const newText = editDraft.trim();
    if (newText) {
      const oldText = lines[origIdx]?.text;
      setLines(prev => prev.map((l, i) => i === origIdx ? { ...l, text: newText } : l));
      const msgIdx = messagesRef.current.findLastIndex(m => m.text === oldText);
      if (msgIdx >= 0) messagesRef.current[msgIdx] = { ...messagesRef.current[msgIdx], text: newText };
    }
    setEditingIdx(null);
  };

  const stopReal = () => {
    [micWsRef.current, tabWsRef.current].forEach(ws => {
      if (!ws) return;
      try { ws._recorder?.stop(); } catch {}
      try { ws.close(); } catch {}
    });
    [micStreamRef.current, tabStreamRef.current].forEach(s => s?.getTracks().forEach(tr => tr.stop()));
    if (tabVideoRef.current) { tabVideoRef.current.srcObject?.getTracks().forEach(tr => tr.stop()); tabVideoRef.current.srcObject = null; setHasTabVideo(false); }
    micWsRef.current = null; tabWsRef.current = null;
    micStreamRef.current = null; tabStreamRef.current = null;
  };

  // ---- DEMO MODE ----
  const startDemo = () => {
    if (trialLeft <= 0 && !unlocked) { setPaywallOpen(true); return; }
    cleanTimers();
    setLines([]); setHint(null);
    stepIdx.current = 0;
    setIsDemo(true);
    setRunning(true);
    setStatusMsg("Demo mode");
    scheduleNext(0);
  };

  const scheduleNext = (delay) => {
    const script = DEMO_SCRIPTS[meetingType] || DEMO_SCRIPTS.Interview;
    const idx = stepIdx.current;
    if (idx >= script.length) return;
    const cur = script[idx];
    const t0 = setTimeout(() => {
      setLines(prev => [...prev, { side: cur.side, text: "", live: true }]);
      const words = cur.text.split(" ");
      let w = 0;
      const typer = () => {
        w++;
        setLines(prev => {
          const next = [...prev];
          next[next.length - 1] = { side: cur.side, text: words.slice(0, w).join(" "), live: w < words.length };
          return next;
        });
        if (w < words.length) {
          timers.current.push(setTimeout(typer, 85 + Math.random() * 80));
        } else {
          if (cur.side === "them") {
            setThinking(true);
            timers.current.push(setTimeout(() => {
              setThinking(false);
              setHints(prev => [{ bullets: HINTS[meetingType] || HINTS.Interview }, ...prev]);
              stepIdx.current = idx + 1;
              scheduleNext(2200);
            }, 1400));
          } else {
            stepIdx.current = idx + 1;
            scheduleNext(900);
          }
        }
      };
      timers.current.push(setTimeout(typer, 100));
    }, delay);
    timers.current.push(t0);
  };

  // ---- SHARED CONTROLS ----
  const stopAll = () => {
    cleanTimers();
    if (!isDemo) stopReal();
    setRunning(false);
    setThinking(false);
    setStatusMsg("");
    setLines(prev => prev.map(l => ({ ...l, live: false })));
  };

  const clearAll = () => {
    cleanTimers();
    if (!isDemo) stopReal();
    setLines([]); setHints([]); setThinking(false); setRunning(false);
    stepIdx.current = 0;
    tabAccRef.current = "";
    messagesRef.current = [];
    setStatusMsg("");
    setIsDemo(false);
  };

  const trialPct = Math.max(0, Math.min(100, (trialLeft / (window.MH_TRIAL_SECONDS || 300)) * 100));
  const [mm, ss] = fmt(trialLeft);
  const warnTrial = !unlocked && trialLeft > 0 && trialLeft <= 60;

  return (
    <div className="session-shell">
      <div className="session-bar">
        <a className="brand" href="#" onClick={(e) => { e.preventDefault(); onClose(); }}>
          <span className="brand-mark">M</span>
          Meeting Helper
        </a>
        <FlowStepper
          step1Done={running}
          step2Done={lines.length > 0}
          st={ts.stepper}
        />
        <span className="spacer" />
        {auth.user && !auth.invite && auth.plan !== 'pro' && (
          <div style={{ display: 'flex', alignItems: 'center', gap: 6, marginRight: 4 }}>
            <span style={{ fontSize: 13.5, fontWeight: 600, color: auth.credits <= 10 ? '#ef4444' : '#374151' }}>
              {auth.credits} {ts.header.minLabel}
            </span>
            <button
              className="btn btn-outline btn-sm"
              onClick={onCTAUnlock}
              style={{ padding: '3px 10px', fontSize: 12.5 }}
            >
              {ts.header.buyBtn}
            </button>
          </div>
        )}
        <button className="btn btn-ghost" onClick={clearAll}>{ts.header.clear}</button>
        {running
          ? <button className="btn btn-stop" onClick={stopAll}>⏹ {ts.header.stop}</button>
          : needsSignIn
            ? <button className="btn btn-primary" disabled style={{ opacity: 0.5 }}>▶ {ts.header.start}</button>
            : <button className="btn btn-primary" onClick={startReal}>▶ {ts.header.start}</button>}
        <select className="lang-flag-select" value={lang} onChange={(e) => setLang(e.target.value)} title="Мова">
          <option value="uk">🇺🇦 UA</option>
          <option value="en">🇬🇧 EN</option>
          <option value="ru">🌐 RU</option>
        </select>
        <AccountChip onSignIn={onSignIn} />
      </div>
      {running && (
        <div className="recording-notice">{ts.recordingNotice}</div>
      )}

      {!unlocked && (
        <div className={"trial-banner" + (warnTrial ? " warn" : "")}>
          <span>⏱</span>
          <span>{ts.trialBanner(mm, ss)}</span>
          <button className="btn btn-primary upgrade" style={{ padding: "6px 14px", fontSize: 13 }} onClick={() => setPaywallOpen(true)}>
            {ts.unlock}
          </button>
        </div>
      )}

      <div className="session-body" style={{ gridTemplateColumns: "320px 1.45fr 1fr" }}>
        <div className="settings-pane">
          <video ref={tabVideoRef} className={"tab-preview" + (hasTabVideo ? " is-active" : "")} muted autoPlay playsInline />
          <div className="settings-body">
            {hasTabVideo && <div className="settings-section-label">Налаштування</div>}
            <div className="settings-group">
              <label className="settings-label">{ts.langLabel}</label>
              <select className="lang-select" style={{ width: "100%" }} value={lang} onChange={(e) => setLang(e.target.value)}>
                <option value="uk">🇺🇦 Українська</option>
                <option value="en">🇬🇧 English</option>
                <option value="ru">🌐 Русский</option>
              </select>
              <div className="settings-hint">{ts.langHint}</div>
            </div>
            <div className="settings-group">
              <label className="settings-label">{ts.memoryLabel}</label>
              <select className="lang-select" style={{ width: "100%" }} value={contextSize} onChange={(e) => setContextSize(Number(e.target.value))}>
                <option value={10}>10</option>
                <option value={20}>20</option>
                <option value={30}>30</option>
                <option value={40}>40</option>
                <option value={50}>50</option>
              </select>
              <div className="settings-hint">{ts.memoryHint}</div>
            </div>
            <ContextField
              label={ts.aboutYou}
              value={context}
              onSave={setContext}
              placeholder={ts.aboutYouPh}
              requiredBadge={ts.aboutYouBadge}
              required
            />
            <ContextField
              label={ts.aboutCompany}
              value={company}
              onSave={setCompany}
              placeholder={ts.aboutCompanyPh}
              requiredBadge={ts.aboutYouBadge}
              required={false}
            />
          </div>
        </div>
        <div className="hint-pane" style={{ borderRight: "1px solid var(--line)" }}>
          <div className="pane-header">
            <h3>{ts.hintsTitle}</h3>
            <div className="format-toggle">
              <button className={"fmt-btn" + (hintFormat === 'bullets' ? ' active' : '')} onClick={() => { setHintFormat('bullets'); localStorage.setItem('mh-hint-format', 'bullets'); }} title="Список">☰</button>
              <button className={"fmt-btn" + (hintFormat === 'prose' ? ' active' : '')} onClick={() => { setHintFormat('prose'); localStorage.setItem('mh-hint-format', 'prose'); }} title="Текст">¶</button>
            </div>
            {hints.length > 0 && (
              <button className="btn btn-ghost" style={{ padding: "4px 10px", fontSize: 12 }} onClick={() => setHints([])}>{ts.clearHints}</button>
            )}
          </div>
          <div style={{ display: "flex", flexDirection: "column", gap: 12, overflowY: "auto", maxHeight: "calc(100vh - 180px)" }}>
            {thinking && (
              <div className="thinking-card">
                <div className="claude-avatar">C</div>
                <span className="thinking-wave"><span /><span /><span /></span>
                <span className="thinking-text">AI is thinking…</span>
              </div>
            )}
            {hints.length === 0 && !thinking && (
              <div className="empty-state" style={{ padding: "40px 12px" }}>
                <p>{ts.hintsEmpty}</p>
              </div>
            )}
            {hints.map((h, i) => (
              <div key={i} className="claude-bubble">
                <div className="claude-head">
                  <div className="claude-avatar">C</div>
                  <span className="claude-name">Claude</span>
                </div>
                {hintFormat === 'prose'
                  ? <div className="hint-prose">{h.bullets.map((b, j) => {
                      const sep = b.indexOf(' | ');
                      const body = sep > 0 && sep <= 15 ? b.slice(sep + 3).trim() : b;
                      return <p key={j}>{body}</p>;
                    })}</div>
                  : <ol>{h.bullets.map((b, j) => {
                      const sep = b.indexOf(' | ');
                      const hasLabel = sep > 0 && sep <= 15;
                      const label = hasLabel ? b.slice(0, sep).trim() : null;
                      const body = hasLabel ? b.slice(sep + 3).trim() : b;
                      return <li key={j}><span>{label && <span className="hint-label">{label}</span>}{body}</span></li>;
                    })}</ol>}
                <div className="hint-actions">
                  <span className="meta">Натисни рядок — скопіює</span>
                  <span className="spacer" />
                  <button className="icon-btn" onClick={() => navigator.clipboard?.writeText(h.bullets.join("\n"))}>⎘ Копіювати все</button>
                </div>
              </div>
            ))}
          </div>
        </div>

        <div className="transcript-pane">
          <div className="pane-header">
            <h3>{ts.transcript}</h3>
          </div>
          {statusMsg && <div className="status-msg" style={{ padding: "8px 16px", fontSize: 13, color: "#6b7280" }}>{statusMsg}</div>}
          {lines.length === 0 ? (
            <div className="empty-state">
              <p>{ts.empty[0]}</p>
              <p>{ts.empty[1]}</p>
            </div>
          ) : (
            <div ref={transcriptRef} className="transcript" style={{ overflowY: "auto", maxHeight: "calc(100vh - 180px)" }}>
              {[...lines].reverse().map((l, i) => {
                const origIdx = lines.length - 1 - i;
                const isEditing = editingIdx === origIdx;
                return (
                  <div
                    className={"t-line " + l.side + (l.live ? " live" : "")}
                    key={i}
                    style={{ position: "relative", paddingRight: isEditing ? 4 : 68 }}
                  >
                    <span className={"t-tag " + l.side}>{l.side === "them" ? "Them" : "You"}</span>
                    {isEditing ? (
                      <input
                        className="t-edit-input"
                        value={editDraft}
                        onChange={e => setEditDraft(e.target.value)}
                        onBlur={() => saveEdit(origIdx)}
                        onKeyDown={e => { if (e.key === "Enter") saveEdit(origIdx); if (e.key === "Escape") setEditingIdx(null); }}
                        autoFocus
                      />
                    ) : (
                      <span className="t-text">{l.text}</span>
                    )}
                    {!l.live && !isEditing && (
                      <div className="line-btns">
                        <button className="line-edit-btn" onClick={() => startEdit(origIdx, l.text)} title="Редагувати">✎</button>
                        <button className="line-hint-btn" onClick={() => getSuggestion(l.text, true)} title="Підказка AI">✦</button>
                      </div>
                    )}
                  </div>
                );
              })}
            </div>
          )}
        </div>
      </div>

      {paywallOpen && (
        <div className="modal-shade" onClick={(e) => { if (e.target.classList.contains("modal-shade")) setPaywallOpen(false); }}>
          <div className="modal">
            <div className="seal">⏱</div>
            <h2>{t.paywall.title}</h2>
            <p className="sub">{t.paywall.sub}</p>
            <ul className="bullets">
              {t.paywall.bullets.map((b, i) => <li key={i}>{b}</li>)}
            </ul>
            <div className="actions">
              <button className="btn btn-ghost" onClick={() => setPaywallOpen(false)}>{t.paywall.later}</button>
              <button className="btn btn-primary" onClick={() => { setPaywallOpen(false); onCTAUnlock(); }}>{t.paywall.cta}</button>
            </div>
          </div>
        </div>
      )}
    </div>
  );
}

window.Session = Session;
