/* ============================================================
   Ebb chat — an overlay sheet ABOVE the Today tab, on a blurred
   scrim. Default states: Active (empty, keyboard up) · Typing ·
   Sent (conversation). Flow-2 adds Care chips, a "Schedule Care"
   hand-off, and a Care Scheduling panel that replaces the thread.
   ============================================================ */
const { useEffect: useEffectE, useRef: useRefE, useState: useStateE } = React;

/* Ebb's brand glyph beside the greeting — the "Ebb (Active)" mark */
function EbbGreetOrb() {
  return <Icon name="ebb-active" size={26} color="var(--hs-warm-grey-700)" className="ebb-greet-orb" />;
}

/* multi-paragraph bubble text (Ebb replies use \n\n between paragraphs) */
function bubbleParas(text) {
  return String(text).split(/\n\n+/).map((p, i) => <p key={i} className="bubble-p">{p}</p>);
}

/* Ebb's reply streams in character-by-character on first mount */
function StreamText({ text, onTick, onDone }) {
  const [n, setN] = useStateE(0);
  const started = useRefE(false);
  useEffectE(() => {
    if (started.current) return; started.current = true;
    let i = 0;
    const id = window.setInterval(() => {
      i += 2;
      setN(i);
      if (onTick) onTick();
      if (i >= text.length) { setN(text.length); window.clearInterval(id); if (onDone) onDone(); }
    }, 18);
    return () => window.clearInterval(id);
  }, []);
  return <React.Fragment>{bubbleParas(text.slice(0, n))}</React.Fragment>;
}

/* An Ebb reply bubble. When it's the streaming (last) message, its recs/actions/
   care chips hold back until the text finishes typing — avoids reflow flashing. */
function EbbReply({ m, isLast, careStage, onOpenPlayer, onReveal, onScheduleCare, onSOS, onTick }) {
  const D = window.HS_DATA;
  const [streamDone, setStreamDone] = useStateE(!isLast);
  const showExtras = !isLast || streamDone;
  useEffectE(() => { if (streamDone && onTick) { onTick(); requestAnimationFrame(onTick); } }, [streamDone]);
  return (
    <div className="msg ebb enter">
      <div className="bubble">{isLast ? <StreamText text={m.text} onTick={onTick} onDone={() => setStreamDone(true)} /> : bubbleParas(m.text)}</div>
      {showExtras && (m.recs || []).slice(0, m.revealed || 1).map((rid) => (
        <div key={rid} style={{ marginTop: 12 }}>
          <RecCard c={D.C[rid]} onOpen={onOpenPlayer} />
        </div>
      ))}
      {showExtras && (m.recs || []).length > (m.revealed || 1) && (
        <button className="show-more" onClick={() => onReveal(m.id)}>
          Show more <Icon name="caret-down" size={16} />
        </button>
      )}
      {showExtras && <EbbActions />}
      {showExtras && m.careOffer && !careStage && (
        <EbbCareChips inline appear onScheduleCare={onScheduleCare} onSOS={onSOS} />
      )}
    </div>
  );
}

/* Opening prompt. Elevated card when empty; plain thread header once talking.
   When empty it can also carry "invitation" quick actions inside the card. */
function EbbGreeting({ card, text, introChips, badge }) {
  return (
    <div className={"ebb-greet" + (card ? " card" : "")}>
      {badge && (
        <span className="ebb-greet-badge">{badge}</span>
      )}
      <div className="ebb-greet-top">
        <div className="ebb-greet-main">
          <span className="ebb-greet-date">Thur, June 18th</span>
          <h2 className="ebb-greet-q">{text || "Hey Blake, how are things going today?"}</h2>
        </div>
        <EbbGreetOrb />
      </div>
      {card && introChips && introChips.length > 0 && (
        <div className="ebb-greet-chips">
          {introChips.map((c, i) => (
            <button key={i} className="ebb-chip" onClick={c.onClick}>
              <span className="ebb-chip-t">{c.label}</span>
              <span className="ebb-chip-ic"><Icon name={c.icon} size={24} color={c.color} /></span>
            </button>
          ))}
        </div>
      )}
    </div>
  );
}

/* Default quick replies — Action Tile layout (title left, icon right) */
function EbbChips({ hidden, onMeditate, onCheckIn }) {
  return (
    <div className={"ebb-chips" + (hidden ? " hidden" : "")} aria-hidden={hidden}>
      <button className="ebb-chip" onClick={onMeditate}>
        <span className="ebb-chip-t">Meditate</span>
        <span className="ebb-chip-ic"><Icon name="qa-meditate" size={24} color="var(--hs-orange-200, #FF7300)" /></span>
      </button>
      <button className="ebb-chip" onClick={onCheckIn}>
        <span className="ebb-chip-t">Check-in</span>
        <span className="ebb-chip-ic"><Icon name="qa-checkin" size={24} color="var(--hs-green-200, #02873E)" /></span>
      </button>
    </div>
  );
}

/* Care-escalation quick replies — surfaced when Ebb offers to connect Blake */
function EbbCareChips({ hidden, inline, appear, onScheduleCare, onSOS }) {
  return (
    <div className={"ebb-chips" + (inline ? " inline" : "") + (appear ? " appear" : "") + (hidden ? " hidden" : "")} aria-hidden={hidden}>
      <button className="ebb-chip" onClick={onScheduleCare}>
        <span className="ebb-chip-t">Schedule Care</span>
        <span className="ebb-chip-ic"><Icon name="calendar" size={24} color="var(--hs-blue-200, #0061EF)" /></span>
      </button>
      <button className="ebb-chip" onClick={onSOS}>
        <span className="ebb-chip-t">SOS</span>
        <span className="ebb-chip-ic"><Icon name="qa-sos" size={24} /></span>
      </button>
    </div>
  );
}

/* State selector for Care scheduling — floating-label dropdown */
function StateDropdown({ value, onChange }) {
  const [open, setOpen] = useStateE(false);
  const states = ['California', 'New York', 'Texas', 'Washington', 'Illinois', 'Colorado'];
  return (
    <div className={"state-dd" + (open ? " open" : "")}>
      <button className="state-dd-field" onClick={() => setOpen((o) => !o)}>
        <span className="state-dd-label">State</span>
        <span className="state-dd-val">{value}</span>
        <span className="state-dd-caret"><Icon name="sort-down" size={18} /></span>
      </button>
      {open && (
        <div className="state-dd-menu">
          {states.map((s) => (
            <button key={s} className={"state-dd-opt" + (s === value ? " on" : "")}
              onClick={() => { onChange(s); setOpen(false); }}>
              {s}{s === value && <Icon name="check" size={17} />}
            </button>
          ))}
        </div>
      )}
    </div>
  );
}

/* Care Scheduling panel — the thread collapses into a summary card, then a
   dotted keyline, then the scheduling form. Replaces the conversation view. */
function EbbSchedule({ stateVal, setStateVal, onContinue }) {
  return (
    <div className="ebb-schedule">
      <div className="ebb-sum-card">
        <div className="ebb-sum-top">
          <span className="ebb-sum-ic"><Icon name="chat-active" size={22} color="var(--hs-orange-200, #FF7300)" /></span>
          <span className="ebb-sum-info">
            <span className="ebb-sum-label">Ebb conversation</span>
            <span className="ebb-sum-date">Mon, June 22nd · 18 min</span>
          </span>
        </div>
        <button className="ebb-sum-cont" onClick={onContinue}>Continue</button>
      </div>
      <div className="ebb-keyline" aria-hidden="true"></div>
      <div className="ebb-sched">
        <div className="ebb-sched-head">
          <h3>Care Scheduling</h3>
          <button className="ebb-sched-more" aria-label="More"><Icon name="overflow-dots" size={20} /></button>
        </div>
        <p className="ebb-sched-q">Where will you be during your therapy appointments?</p>
        <StateDropdown value={stateVal} onChange={setStateVal} />
      </div>
    </div>
  );
}

/* Input dock — orb · text field · mic · voice/send */
function EbbDock({ draft, setDraft, onSend, onRaiseKb, active, script }) {
  const taRef = useRefE(null);
  const typeRef = useRefE(null);
  const hasText = draft.trim() !== '';
  useEffectE(() => {
    const t = taRef.current;
    if (t) {
      t.style.height = 'auto';
      const cap = 74; // ~3 lines at 16px/1.4 + vertical padding
      t.style.height = Math.min(t.scrollHeight, cap) + 'px';
      t.style.overflowY = t.scrollHeight > cap ? 'auto' : 'hidden';
    }
  }, [draft]);
  // Place a real blinking caret in the field when the keyboard is up
  useEffectE(() => {
    if (active && taRef.current) { try { taRef.current.focus({ preventScroll: true }); } catch (_) { try { taRef.current.focus(); } catch (e) {} } }
  }, [active]);
  useEffectE(() => () => { if (typeRef.current) window.clearInterval(typeRef.current); }, []);
  // Stop auto-typing and return to the inactive field once the keyboard drops (e.g. after send)
  useEffectE(() => { if (!active && typeRef.current) { window.clearInterval(typeRef.current); typeRef.current = null; } }, [active]);
  // Auto-type Blake's scripted reply when he taps the empty field
  const startType = () => {
    if (!script || typeRef.current || draft.trim() !== '') return;
    let i = 0;
    typeRef.current = window.setInterval(() => {
      i++;
      setDraft(script.slice(0, i));
      if (i >= script.length) { window.clearInterval(typeRef.current); typeRef.current = null; }
    }, 24);
  };
  const onTap = () => { onRaiseKb(); startType(); };
  const onManualChange = (e) => {
    if (typeRef.current) { window.clearInterval(typeRef.current); typeRef.current = null; }
    setDraft(e.target.value);
  };
  return (
    <div className="ebb-dock">
      <div className="ebb-dock-field">
        <textarea ref={taRef} value={draft} placeholder="Share your thoughts…" rows={1}
          onFocus={onRaiseKb} onMouseDown={onTap}
          onChange={onManualChange}
          onKeyDown={(e) => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); onSend(); } }} />
      </div>
      <div className="ebb-dock-row">
        <span className="ebb-dock-face" aria-hidden="true"></span>
        <span className="ebb-dock-actions">
          <button className="ebb-dock-btn mic" aria-label="Voice note"><Icon name="microphone" size={21} /></button>
          {hasText
            ? <button className="ebb-dock-btn send" aria-label="Send" onClick={onSend}><Icon name="send" size={17} color="#fff" /></button>
            : <button className="ebb-dock-btn voice" aria-label="Voice mode" onMouseDown={(e) => { e.preventDefault(); onRaiseKb(); }}><Icon name="voice" size={20} color="#fff" /></button>}
        </span>
      </div>
    </div>
  );
}

function EbbSheet({ open, kbUp, messages, pending, draft, setDraft,
  chipSet, careStage, stateVal, setStateVal, greetingText, greetBadge, introChips, careScript,
  onClose, onNewChat, onRaiseKb, onDropKb, onSend, onChar, onBackspace,
  onOpenPlayer, onReveal, onMeditate, onCheckIn, onScheduleCare, onSOS }) {
  const D = window.HS_DATA;
  const RecCard = window.RecCard, EbbActions = window.EbbActions, IOSKeyboard = window.IOSKeyboard;
  const threadRef = useRefE(null);
  const hasMsgs = messages.length > 0 || pending;
  const typing = draft.trim() !== '';
  const scheduling = careStage === 'scheduling';

  useEffectE(() => {
    const el = threadRef.current;
    if (!el || !open || scheduling) return;
    const to = el.scrollHeight - el.clientHeight;
    if (to > 0) {
      const from = el.scrollTop, start = performance.now(), dur = 420;
      const ease = (t) => 1 - Math.pow(1 - t, 3);
      (function step(now) {
        const p = Math.min(1, (now - start) / dur);
        el.scrollTop = from + (to - from) * ease(p);
        if (p < 1) requestAnimationFrame(step);
      })(performance.now());
    }
    // The dock+keyboard grow the shell's bottom padding over ~0.42s, so snap to
    // the true bottom once that transition settles — keeps the last message clear.
    const snap = window.setTimeout(() => { el.scrollTop = el.scrollHeight - el.clientHeight; }, 480);
    return () => window.clearTimeout(snap);
  }, [messages.length, pending, kbUp, open, scheduling]);

  // Footer chips (default flow only — care chips now render inline in the thread)
  let chipsEl = null;
  if (chipSet === 'default') chipsEl = <EbbChips hidden={messages.length > 0 || typing} onMeditate={onMeditate} onCheckIn={onCheckIn} />;

  return (
    <div className={"ebb-sheet" + (open ? " open" : "") + (kbUp ? " kb" : "")} aria-hidden={!open}>
      <div className="ebb-scrim" onClick={() => { if (kbUp) onDropKb(); }}></div>

      <div className="ebb-shell">
        <div className="ebb-header">
          <button className="ebb-nav-btn ghost" aria-label="New chat" onClick={onNewChat}>
            <Icon name="overflow-dots" size={22} />
          </button>
          <button className="ebb-nav-btn" aria-label="Close" onClick={onClose}>
            <Icon name="close" size={17} />
          </button>
        </div>

        <div className={"ebb-thread" + (scheduling ? " scheduling" : "")} ref={threadRef}
          onClick={() => { if (kbUp) onDropKb(); }}>
          <div className="ebb-thread-inner">
            {scheduling ? (
              <EbbSchedule stateVal={stateVal} setStateVal={setStateVal} onContinue={onDropKb} />
            ) : hasMsgs ? (
              <div className="ebb-convo">
                <EbbGreeting card={false} text={greetingText} badge={greetBadge} />

                {messages.map((m, i) => {
                  const isLast = i === messages.length - 1;
                  if (m.from === 'me') {
                    return m.kind === 'action'
                      ? (
                        <div key={m.id} className="msg me enter">
                          <span className="bubble action-bubble">
                            <span>{m.text}</span>
                            <span className="action-ic">
                              <Icon name={m.icon} size={20} color={m.icon === 'qa-care' ? 'var(--hs-blue-200, #0061EF)' : undefined} />
                            </span>
                          </span>
                        </div>
                      )
                      : <div key={m.id} className="msg me enter"><span className="bubble">{m.text}</span></div>;
                  }
                  return (
                    <EbbReply key={m.id} m={m} isLast={isLast} careStage={careStage}
                      onOpenPlayer={onOpenPlayer} onReveal={onReveal}
                      onScheduleCare={onScheduleCare} onSOS={onSOS}
                      onTick={() => { const el = threadRef.current; if (el) el.scrollTop = el.scrollHeight; }} />
                  );
                })}

                {pending && <div className="msg ebb"><div className="typing"><i></i><i></i><i></i></div></div>}
              </div>
            ) : (
              <EbbGreeting card={true} text={greetingText} badge={greetBadge} introChips={introChips} />
            )}
          </div>
        </div>

        <div className="ebb-foot">
          {chipsEl}
          <EbbDock draft={draft} setDraft={setDraft} onSend={onSend} onRaiseKb={onRaiseKb} active={open && kbUp} script={careScript} />
        </div>
      </div>

      <IOSKeyboard open={open && kbUp} onChar={onChar} onBackspace={onBackspace} onReturn={onSend} />
    </div>
  );
}
window.EbbSheet = EbbSheet;
window.EbbDock = EbbDock;
