// Healify Web — shared chat composer + rich message bubbles. Used by BOTH the
// mobile ChatScreen and the desktop DeskChat so they have 1:1 feature parity:
// text, file/image attachments, and voice notes (record → send → playback).

const { useState: useStateCX, useRef: useRefCX, useEffect: useEffectCX } = React;

// ── Live Anna ─────────────────────────────────────────────────────────────
// Sends one chat turn through the edge proxy (/api/chat), which authenticates
// as the demo persona ("Kathryn", user 1475) and calls the real Healify
// AgentCore backend. Returns { answer, threadId, buttons }. Throws on failure
// so callers can fall back to a graceful message.
async function askAnna(message, threadId) {
  const res = await fetch('/api/chat', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(threadId ? { message, threadId } : { message }),
  });
  if (!res.ok) throw new Error('chat_failed_' + res.status);
  const data = await res.json();
  return {
    answer: data.answer || '',
    threadId: data.threadId || threadId || null,
    buttons: Array.isArray(data.buttons) ? data.buttons : [],
  };
}

function fmtDur(s) { const m = Math.floor(s / 60); const ss = Math.floor(s % 60); return m + ':' + String(ss).padStart(2, '0'); }
function fmtSize(b) { if (b >= 1e6) return (b / 1e6).toFixed(1) + ' MB'; if (b >= 1e3) return Math.round(b / 1e3) + ' KB'; return b + ' B'; }

function revokeMessageBlobUrls(messages) {
  for (const m of messages || []) {
    if (m.type === 'file' && m.file?.url) URL.revokeObjectURL(m.file.url);
  }
}

function useRevokeMessageBlobUrlsOnUnmount(messages) {
  const messagesRef = useRefCX(messages);
  messagesRef.current = messages;
  useEffectCX(() => () => revokeMessageBlobUrls(messagesRef.current), []);
}

// ── Voice-note message bubble (play / pause + waveform progress) ───────────
function VoiceNoteBubble({ seconds, mine, time }) {
  const [playing, setPlaying] = useStateCX(false);
  const [t, setT] = useStateCX(0);
  useEffectCX(() => {
    if (!playing) return;
    const id = setInterval(() => setT(v => { if (v >= seconds) { clearInterval(id); setPlaying(false); return 0; } return v + 0.1; }), 100);
    return () => clearInterval(id);
  }, [playing, seconds]);
  const bars = 26, prog = t / seconds, fg = mine ? '#fff' : H.orange;
  const heights = Array.from({ length: bars }, (_, i) => 0.3 + 0.7 * Math.abs(Math.sin(i * 1.4) * Math.cos(i * 0.5)));
  return (
    <div style={{ alignSelf: mine ? 'flex-end' : 'flex-start', maxWidth: '78%', display: 'flex', flexDirection: 'column', alignItems: mine ? 'flex-end' : 'flex-start', gap: 4 }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 11, background: mine ? H.gradBubble : '#fff', boxShadow: mine ? 'none' : '0 1px 3px rgba(3,4,13,0.06)', borderRadius: mine ? '22px 22px 4px 22px' : '22px 22px 22px 4px', padding: '10px 14px' }}>
        <button onClick={() => setPlaying(p => !p)} aria-label={playing ? 'Pause' : 'Play'} style={{ width: 34, height: 34, borderRadius: 999, border: 0, cursor: 'pointer', background: mine ? 'rgba(255,255,255,0.22)' : H.bg, display: 'grid', placeItems: 'center', flexShrink: 0 }}>
          {playing
            ? <svg width="13" height="13" viewBox="0 0 24 24" fill={fg}><rect x="6" y="5" width="4" height="14" rx="1" /><rect x="14" y="5" width="4" height="14" rx="1" /></svg>
            : <svg width="13" height="13" viewBox="0 0 24 24" fill={fg} style={{ marginLeft: 2 }}><path d="M7 5v14l11-7z" /></svg>}
        </button>
        <div style={{ display: 'flex', alignItems: 'center', gap: 2.5, height: 26 }}>
          {heights.map((h, i) => (<span key={i} style={{ width: 2.5, height: Math.round(h * 24), minHeight: 4, borderRadius: 999, background: fg, opacity: (i / bars) <= prog ? 1 : 0.4 }} />))}
        </div>
        <span style={{ fontFamily: H.body, fontSize: 12, color: mine ? 'rgba(255,255,255,0.9)' : H.fg2, minWidth: 30, fontVariantNumeric: 'tabular-nums' }}>{fmtDur(playing ? t : seconds)}</span>
      </div>
      {time && <span style={{ fontFamily: H.body, fontSize: 11, color: H.fg3, padding: mine ? '0 6px 0 0' : '0 0 0 6px' }}>{time}</span>}
    </div>
  );
}

// ── Attachment message bubble (image preview or file card) ─────────────────
function AttachmentBubble({ file, mine, time }) {
  const fg = mine ? '#fff' : H.fg1;
  const radius = mine ? '20px 20px 6px 20px' : '20px 20px 20px 6px';
  return (
    <div style={{ alignSelf: mine ? 'flex-end' : 'flex-start', maxWidth: '78%', display: 'flex', flexDirection: 'column', alignItems: mine ? 'flex-end' : 'flex-start', gap: 4 }}>
      {file.isImage && file.url ? (
        <div style={{ borderRadius: radius, overflow: 'hidden', maxWidth: 240, boxShadow: mine ? 'none' : '0 1px 3px rgba(3,4,13,0.06)' }}>
          <img src={file.url} alt={file.name} style={{ display: 'block', width: '100%', maxHeight: 280, objectFit: 'cover' }} />
        </div>
      ) : (
        <div style={{ display: 'flex', alignItems: 'center', gap: 11, background: mine ? H.gradBubble : '#fff', boxShadow: mine ? 'none' : '0 1px 3px rgba(3,4,13,0.06)', borderRadius: radius, padding: '12px 14px', minWidth: 190 }}>
          <div style={{ width: 38, height: 38, borderRadius: 10, background: mine ? 'rgba(255,255,255,0.18)' : H.bgSecondary, display: 'grid', placeItems: 'center', flexShrink: 0 }}>
            <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke={fg} strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><path d="M14 3v5h5" /><path d="M14 3l5 5v11a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2z" /></svg>
          </div>
          <div style={{ minWidth: 0 }}>
            <div style={{ fontFamily: H.body, fontWeight: 500, fontSize: 14, color: fg, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', maxWidth: 150 }}>{file.name}</div>
            <div style={{ fontFamily: H.body, fontSize: 12, color: mine ? 'rgba(255,255,255,0.8)' : H.fg3 }}>{file.size}</div>
          </div>
        </div>
      )}
      {time && <span style={{ fontFamily: H.body, fontSize: 11, color: H.fg3, padding: mine ? '0 6px 0 0' : '0 0 0 6px' }}>{time}</span>}
    </div>
  );
}

// Renders a rich (voice/file) message, or null for plain text (caller renders text).
function renderRichMessage(m, i) {
  if (m.type === 'voice') return <VoiceNoteBubble key={i} seconds={m.seconds} mine={m.who === 'user'} time={m.time} />;
  if (m.type === 'file') return <AttachmentBubble key={i} file={m.file} mine={m.who === 'user'} time={m.time} />;
  return null;
}

// ── Composer: attach · text · (mic ⇄ send) with inline recording UI ────────
function ChatComposer({ variant, onSendText, onSendFile, onSendVoice }) {
  const [draft, setDraft] = useStateCX('');
  const [rec, setRec] = useStateCX(false);
  const [sec, setSec] = useStateCX(0);
  const fileRef = useRefCX(null);
  const timer = useRefCX(null);
  const startTime = useRefCX(0);
  const icoSize = 40;
  const btn = (bg) => ({ width: icoSize, height: icoSize, borderRadius: 999, display: 'grid', placeItems: 'center', cursor: 'pointer', flexShrink: 0, border: 0, background: bg });

  const start = () => { startTime.current = Date.now(); setRec(true); setSec(0); timer.current = setInterval(() => setSec((Date.now() - startTime.current) / 1000), 90); };
  const stop = (doSend) => { clearInterval(timer.current); timer.current = null; const d = (Date.now() - startTime.current) / 1000; setRec(false); setSec(0); if (doSend && d >= 0.4) onSendVoice(Math.max(1, Math.round(d))); };
  useEffectCX(() => () => { clearInterval(timer.current); timer.current = null; }, []);
  const onFile = (e) => { const f = e.target.files && e.target.files[0]; if (f) { const img = f.type.startsWith('image/'); onSendFile({ name: f.name, size: fmtSize(f.size), url: img ? URL.createObjectURL(f) : null, isImage: img }); } e.target.value = ''; };
  const sendText = () => { const t = draft.trim(); if (t) { onSendText(t); setDraft(''); } };

  const pill = {
    display: 'flex', alignItems: 'center', gap: 7, background: '#fff', borderRadius: 999, boxSizing: 'border-box',
    padding: '6px 6px 6px 8px',
    boxShadow: variant === 'mobile' ? '0 8px 24px rgba(0,0,0,0.10)' : 'none',
    border: variant === 'desktop' ? '1px solid var(--border-subtle)' : '0',
  };

  if (rec) {
    return (
      <div style={{ ...pill, padding: '6px 6px 6px 12px' }}>
        <button onClick={() => stop(false)} aria-label="Cancel recording" style={btn('transparent')}>
          <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke={H.danger} strokeWidth="1.9" strokeLinecap="round" strokeLinejoin="round"><path d="M3 6h18M8 6V4h8v2M19 6l-1 14H6L5 6M10 11v5M14 11v5" /></svg>
        </button>
        <span style={{ width: 9, height: 9, borderRadius: 999, background: H.danger, flexShrink: 0, animation: 'wallPulse 1.2s ease-in-out infinite' }} />
        <div style={{ flex: 1, display: 'flex', alignItems: 'center', gap: 2.5, height: 24, overflow: 'hidden' }}>
          {Array.from({ length: 40 }).map((_, i) => (<span key={i} style={{ width: 2.5, borderRadius: 999, background: H.orange, height: 4 + Math.abs(Math.sin((i + sec * 4) * 0.7)) * 20, opacity: 0.85 }} />))}
        </div>
        <span style={{ fontFamily: H.body, fontSize: 13, color: H.fg2, fontVariantNumeric: 'tabular-nums', minWidth: 38, textAlign: 'right' }}>{fmtDur(sec)}</span>
        <button onClick={() => stop(true)} aria-label="Send voice note" style={btn(H.orange)}>
          <svg width="16" height="16" viewBox="0 0 24 24" fill="#fff"><path d="M3 20V4l18 8Z" /></svg>
        </button>
      </div>
    );
  }
  return (
    <div style={pill}>
      <input ref={fileRef} type="file" onChange={onFile} style={{ display: 'none' }} accept="image/*,application/pdf,.csv,.txt,.doc,.docx,.heic" />
      <button onClick={() => fileRef.current && fileRef.current.click()} aria-label="Attach file" style={btn('transparent')}>
        <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke={H.fg2} strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="M21 11.5 12.5 20a5 5 0 0 1-7-7l8.5-8.5a3.5 3.5 0 0 1 5 5L10.4 17.1a2 2 0 0 1-3-3l7.1-7.1" /></svg>
      </button>
      <input value={draft} onChange={e => setDraft(e.target.value)} onKeyDown={e => { if (e.key === 'Enter') sendText(); }} placeholder="Ask Anna anything…" style={{ border: 0, outline: 0, flex: 1, fontFamily: H.body, fontSize: 15, background: 'transparent', minWidth: 0, color: H.fg1 }} />
      {draft.trim()
        ? <button onClick={sendText} aria-label="Send" style={btn(H.orange)}><svg width="16" height="16" viewBox="0 0 24 24" fill="#fff"><path d="M3 20V4l18 8Z" /></svg></button>
        : <button onClick={start} aria-label="Record voice note" style={btn(H.orange)}><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#fff" strokeWidth="1.9" strokeLinecap="round" strokeLinejoin="round"><path d="M12 3a3 3 0 0 1 3 3v5a3 3 0 0 1-6 0V6a3 3 0 0 1 3-3z" /><path d="M5 11a7 7 0 0 0 14 0M12 18v3" /></svg></button>}
    </div>
  );
}

Object.assign(window, { fmtDur, fmtSize, revokeMessageBlobUrls, useRevokeMessageBlobUrlsOnUnmount, VoiceNoteBubble, AttachmentBubble, renderRichMessage, ChatComposer });
