// VoiceMemo.jsx — the heartbeat. Real browser audio capture (MediaRecorder),
// a breathing waveform, then two ways to leave it: with a name, or anonymously.
// Warm and human — not a podcast widget.
function VoiceMemo() {
  const S = { IDLE:'idle', RECORDING:'recording', RECORDED:'recorded', SENT_C:'sent-contact', SENT_A:'sent-anon', DENIED:'denied' };
  const [state, setState] = React.useState(S.IDLE);
  const [seconds, setSeconds] = React.useState(0);
  const [levels, setLevels] = React.useState(() => new Array(36).fill(0.08));
  const [playing, setPlaying] = React.useState(false);
  const [name, setName] = React.useState('');
  const [email, setEmail] = React.useState('');

  const mediaRef = React.useRef(null);
  const streamRef = React.useRef(null);
  const chunksRef = React.useRef([]);
  const audioRef = React.useRef(null);
  const urlRef = React.useRef(null);
  const acRef = React.useRef(null);
  const analyserRef = React.useRef(null);
  const rafRef = React.useRef(null);
  const timerRef = React.useRef(null);

  const fmt = (s) => `${Math.floor(s/60)}:${String(Math.floor(s)%60).padStart(2,'0')}`;

  const stopMeter = () => { if (rafRef.current) cancelAnimationFrame(rafRef.current); rafRef.current = null; };
  const cleanupStream = () => {
    if (streamRef.current) { streamRef.current.getTracks().forEach((t)=>t.stop()); streamRef.current = null; }
    if (acRef.current && acRef.current.state !== 'closed') { acRef.current.close().catch(()=>{}); acRef.current = null; }
  };

  React.useEffect(() => () => {
    stopMeter(); cleanupStream(); clearInterval(timerRef.current);
    if (urlRef.current) URL.revokeObjectURL(urlRef.current);
  }, []);

  const runMeter = () => {
    const analyser = analyserRef.current; if (!analyser) return;
    const buf = new Uint8Array(analyser.frequencyBinCount);
    const tick = () => {
      analyser.getByteFrequencyData(buf);
      const n = 36; const out = new Array(n);
      const lo = 2, hi = Math.min(buf.length, 120);
      for (let i=0;i<n;i++){
        const idx = lo + Math.floor((i/n)*(hi-lo));
        out[i] = Math.min(1, Math.max(0.06, (buf[idx]/255) * 1.25));
      }
      setLevels(out);
      rafRef.current = requestAnimationFrame(tick);
    };
    tick();
  };

  const start = async () => {
    try {
      const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
      streamRef.current = stream;
      chunksRef.current = [];
      const mr = new MediaRecorder(stream);
      mediaRef.current = mr;
      mr.ondataavailable = (e) => { if (e.data && e.data.size) chunksRef.current.push(e.data); };
      mr.onstop = () => {
        const blob = new Blob(chunksRef.current, { type: mr.mimeType || 'audio/webm' });
        if (urlRef.current) URL.revokeObjectURL(urlRef.current);
        urlRef.current = URL.createObjectURL(blob);
        if (audioRef.current) audioRef.current.src = urlRef.current;
        cleanupStream();
        setState(S.RECORDED);
      };
      // live meter
      try {
        const AC = window.AudioContext || window.webkitAudioContext;
        const ac = new AC(); acRef.current = ac;
        const src = ac.createMediaStreamSource(stream);
        const analyser = ac.createAnalyser(); analyser.fftSize = 256; analyser.smoothingTimeConstant = 0.78;
        src.connect(analyser); analyserRef.current = analyser; runMeter();
      } catch (_) {}
      mr.start();
      setSeconds(0);
      clearInterval(timerRef.current);
      timerRef.current = setInterval(() => setSeconds((s)=>s+1), 1000);
      setState(S.RECORDING);
    } catch (err) {
      setState(S.DENIED);
    }
  };

  const stop = () => {
    clearInterval(timerRef.current);
    stopMeter();
    setLevels(new Array(36).fill(0.1));
    try { mediaRef.current && mediaRef.current.state !== 'inactive' && mediaRef.current.stop(); }
    catch (_) { cleanupStream(); setState(S.RECORDED); }
  };

  const reset = () => {
    clearInterval(timerRef.current); stopMeter(); cleanupStream();
    if (urlRef.current) { URL.revokeObjectURL(urlRef.current); urlRef.current = null; }
    setPlaying(false); setSeconds(0); setName(''); setEmail('');
    setLevels(new Array(36).fill(0.08));
    setState(S.IDLE);
  };

  const togglePlay = () => {
    const a = audioRef.current; if (!a) return;
    if (a.paused) { a.play(); setPlaying(true); } else { a.pause(); setPlaying(false); }
  };

  const sendWithContact = (e) => { e.preventDefault(); setState(S.SENT_C); };
  const sendAnon = () => setState(S.SENT_A);

  // ---------- shared bits ----------
  const Waveform = ({ live }) => (
    <div style={{ display:'flex', alignItems:'center', gap:3, height:36, flex:1, minWidth:0 }} aria-hidden="true">
      {levels.map((v,i) => (
        <span key={i} style={{
          flex:'1 1 0', minWidth:0, maxWidth:5,
          height: `${Math.round((live ? v : 0.16) * 100)}%`,
          background: 'var(--fiorella-sand)', borderRadius: 3,
          opacity: live ? 0.5 + v*0.5 : 0.4,
          transition: 'height 110ms linear, opacity 110ms linear',
        }} />
      ))}
    </div>
  );

  const MicIcon = () => (
    <svg viewBox="0 0 24 24" style={{ width:26, height:26, stroke:'var(--on-dark)', strokeWidth:1.5, fill:'none', strokeLinecap:'round', strokeLinejoin:'round' }}>
      <path d="M12 2a3 3 0 0 0-3 3v6a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3z"/>
      <path d="M5 10v1a7 7 0 0 0 14 0v-1"/><line x1="12" y1="18" x2="12" y2="22"/>
    </svg>
  );
  const StopIcon = () => (
    <svg viewBox="0 0 24 24" style={{ width:22, height:22, fill:'var(--on-dark)' }}><rect x="7" y="7" width="10" height="10" rx="2"/></svg>
  );

  return (
    <div style={cardWrap} className="vm-card">
      <div style={{ fontFamily:'var(--sans-body)', fontWeight:400, fontSize:11.5, letterSpacing:'0.24em', textTransform:'uppercase', color:'var(--fg-faint)', fontVariant:'all-small-caps' }}>
        Before you scroll further
      </div>

      <h2 style={prompt}>What are you carrying right now?</h2>

      {(state === S.IDLE) && (
        <p style={bodyText}>Say it out loud. Even if you can't finish the sentence. This is anonymous. No one will judge it, grade it, or ask you to fix it.</p>
      )}

      {/* ---------- IDLE ---------- */}
      {state === S.IDLE && (
        <div style={{ display:'flex', alignItems:'center', gap:18, marginTop:22 }}>
          <button onClick={start} aria-label="Press to begin recording" style={recordBtn}
            onMouseEnter={(e)=>e.currentTarget.style.background='var(--sea-glass-deep)'}
            onMouseLeave={(e)=>e.currentTarget.style.background='var(--sea-glass)'}>
            <span style={haloRing} />
            <MicIcon />
          </button>
          <div style={{ fontFamily:'var(--serif-display)', fontStyle:'italic', fontWeight:400, fontSize:'clamp(20px,2.4vw,24px)', color:'var(--tides-dark)', lineHeight:1.2 }}>
            Press to begin
          </div>
        </div>
      )}

      {/* ---------- RECORDING ---------- */}
      {state === S.RECORDING && (
        <div style={{ marginTop:22 }}>
          <div style={{ display:'flex', alignItems:'center', gap:16 }}>
            <button onClick={stop} aria-label="Press to stop recording" style={{ ...recordBtn, background:'var(--sea-glass-deep)' }}>
              <span style={{ ...haloRing, animation:'fsPulse 1.9s var(--ease-settle) infinite', borderColor:'var(--sea-glass)' }} />
              <StopIcon />
            </button>
            <Waveform live={true} />
            <span style={timerText}>{fmt(seconds)}</span>
          </div>
          <div style={{ ...statusLine, marginTop:18 }}>
            <span style={{ display:'inline-block', width:7, height:7, borderRadius:999, background:'var(--fiorella-sand)', marginRight:9, verticalAlign:'middle', animation:'fsBreathe 1.8s ease-in-out infinite' }} />
            Recording — press to stop
          </div>
        </div>
      )}

      {/* ---------- RECORDED: review + two ways to leave it ---------- */}
      {state === S.RECORDED && (
        <div style={{ marginTop:22 }}>
          <div style={playbackRow}>
            <button onClick={togglePlay} aria-label={playing ? 'Pause' : 'Listen back'} style={playBtn}>
              {playing ? (
                <svg viewBox="0 0 24 24" style={{ width:18, height:18, fill:'var(--on-sand)' }}><rect x="6" y="5" width="4" height="14" rx="1.3"/><rect x="14" y="5" width="4" height="14" rx="1.3"/></svg>
              ) : (
                <svg viewBox="0 0 24 24" style={{ width:18, height:18, fill:'var(--on-sand)' }}><path d="M8 5.5v13a1 1 0 0 0 1.5.86l11-6.5a1 1 0 0 0 0-1.72l-11-6.5A1 1 0 0 0 8 5.5z"/></svg>
              )}
            </button>
            <div style={{ display:'flex', alignItems:'center', gap:3, height:30, flex:1, minWidth:0 }} aria-hidden="true">
              {new Array(34).fill(0).map((_,i)=>(
                <span key={i} style={{ flex:'1 1 0', maxWidth:5, height:`${20 + Math.abs(Math.sin(i*0.9))*70}%`, background:'var(--fiorella-sand)', opacity:0.4, borderRadius:3 }} />
              ))}
            </div>
            <span style={{ ...timerText, color:'var(--fg-muted)' }}>{fmt(seconds)}</span>
          </div>
          <audio ref={audioRef} onEnded={()=>setPlaying(false)} style={{ display:'none' }} />

          <div style={hair} />

          <form onSubmit={sendWithContact}>
            <p style={{ ...bodyText, fontSize:13.5, marginTop:0 }}>
              Would you like a personal response from Fiorella? Leave your name and email — not required.
            </p>
            <div style={fieldRow}>
              <input value={name} onChange={(e)=>setName(e.target.value)} placeholder="Your name" style={field} aria-label="Your name" />
              <input value={email} onChange={(e)=>setEmail(e.target.value)} type="email" placeholder="Your email" style={field} aria-label="Your email" />
            </div>
            <button type="submit" style={primaryBtn}
              onMouseEnter={(e)=>e.currentTarget.style.background='var(--sea-glass-deep)'}
              onMouseLeave={(e)=>e.currentTarget.style.background='var(--sea-glass)'}>
              Send — I'd love a response
            </button>
          </form>

          <div style={{ display:'flex', alignItems:'center', gap:20, marginTop:16, flexWrap:'wrap' }}>
            <button onClick={sendAnon} style={ghostBtn}>Send anonymously</button>
            <button onClick={reset} style={quietLink}>Record again</button>
          </div>
        </div>
      )}

      {/* ---------- confirmations ---------- */}
      {(state === S.SENT_C || state === S.SENT_A) && (
        <div style={{ marginTop:26, textAlign:'left' }}>
          <div style={{ fontFamily:'var(--serif-display)', fontStyle:'italic', fontWeight:400, fontSize:'clamp(22px,2.6vw,27px)', color:'var(--tides-dark)', lineHeight:1.28 }}>
            {state === S.SENT_C ? 'Thank you. Fiorella will respond to you personally.' : 'Received. Your voice is held here.'}
          </div>
          <button onClick={reset} style={{ ...quietLink, marginTop:18 }}>Leave another</button>
        </div>
      )}

      {/* ---------- mic denied ---------- */}
      {state === S.DENIED && (
        <div style={{ marginTop:22 }}>
          <p style={bodyText}>Your browser didn't allow the microphone this time. You can enable it in your settings — or simply read on. You're welcome here either way.</p>
          <button onClick={start} style={{ ...ghostBtn, marginTop:6 }}>Try again</button>
        </div>
      )}

      {(state === S.IDLE || state === S.RECORDING) && (
        <div style={accent}>Your voice is safe here.</div>
      )}
    </div>
  );
}

// ---------- styles ----------
const cardWrap = {
  width:'100%', maxWidth:560, margin:'0 auto', textAlign:'left',
  background:'rgba(251,248,243,0.90)', backdropFilter:'blur(14px) saturate(1.05)', WebkitBackdropFilter:'blur(14px) saturate(1.05)',
  border:'1px solid var(--fiorella-sand)', borderRadius:12,
  boxShadow:'0 8px 48px rgba(85,57,39,0.16)',
  padding:'clamp(24px,3.4vw,34px)',
};
const prompt = { fontFamily:'var(--serif-display)', fontWeight:400, fontSize:'clamp(27px,3.4vw,36px)', lineHeight:1.1, color:'var(--tides-dark)', margin:'12px 0 0' };
const bodyText = { fontFamily:'var(--sans-body)', fontWeight:300, fontSize:14.5, lineHeight:1.62, color:'var(--fg-muted)', margin:'14px 0 0', maxWidth:460 };
const accent = { fontFamily:'var(--serif-display)', fontStyle:'italic', fontWeight:400, fontSize:'clamp(17px,2vw,20px)', color:'var(--fiorella-sand)', marginTop:22 };

const recordBtn = {
  position:'relative', flex:'0 0 auto', width:62, height:62, borderRadius:999,
  background:'var(--sea-glass)', border:'none', cursor:'pointer',
  display:'flex', alignItems:'center', justifyContent:'center',
  transition:'background 500ms var(--ease-settle), transform 200ms ease',
  boxShadow:'0 4px 18px rgba(85,57,39,0.16)',
};
const haloRing = { position:'absolute', inset:-6, borderRadius:999, border:'1.5px solid var(--sea-glass)', opacity:0, pointerEvents:'none' };
const timerText = { fontFamily:'var(--sans-body)', fontWeight:300, fontSize:14, color:'var(--fg-muted)', letterSpacing:'0.06em', flex:'0 0 auto' };
const statusLine = { fontFamily:'var(--sans-body)', fontWeight:400, fontSize:12.5, letterSpacing:'0.04em', color:'var(--fg-muted)' };

const playbackRow = { display:'flex', alignItems:'center', gap:14 };
const playBtn = { flex:'0 0 auto', width:42, height:42, borderRadius:999, background:'var(--fiorella-sand)', border:'none', cursor:'pointer', display:'flex', alignItems:'center', justifyContent:'center', transition:'background 400ms ease' };
const hair = { height:1, background:'var(--stone-line)', margin:'22px 0 20px' };
const fieldRow = { display:'flex', gap:12, marginTop:14, flexWrap:'wrap' };
const field = {
  flex:'1 1 160px', minWidth:0, background:'transparent', border:'none', borderBottom:'1px solid var(--stone-line)',
  padding:'9px 2px', fontFamily:'var(--sans-body)', fontWeight:300, fontSize:15, color:'var(--tides-dark)', outline:'none',
  transition:'border-color 400ms ease',
};
const primaryBtn = {
  marginTop:22, width:'100%', fontFamily:'var(--sans-body)', fontWeight:400, fontSize:12.5, letterSpacing:'0.14em', textTransform:'uppercase',
  color:'var(--on-dark)', background:'var(--sea-glass)', border:'none', borderRadius:999, padding:'15px 26px', cursor:'pointer',
  transition:'background 400ms ease',
};
const ghostBtn = {
  fontFamily:'var(--sans-body)', fontWeight:400, fontSize:12, letterSpacing:'0.12em', textTransform:'uppercase',
  color:'var(--tides-dark)', background:'transparent', border:'1px solid var(--stone-line)', borderRadius:999,
  padding:'12px 24px', cursor:'pointer', transition:'border-color 400ms ease, color 400ms ease',
};
const quietLink = { fontFamily:'var(--sans-body)', fontWeight:400, fontSize:11.5, letterSpacing:'0.1em', textTransform:'uppercase', color:'var(--fg-faint)', background:'transparent', border:'none', cursor:'pointer' };

window.VoiceMemo = VoiceMemo;
