// InsuranceCapture.jsx — Scan / Speak / Type tabs to capture insurance info.
// Scan → POST /api/scan-insurance (Claude Vision card OCR, multipart).
// Speak → CA §632 consent gate → browser SpeechRecognition (no backend needed);
//         falls back to MediaRecorder → POST /api/transcribe if unavailable.
// Type → traditional text inputs.
// Emits onChange({carrier, plan, memberId, groupId}) to the parent.
const { useState: useICs, useRef: useICr } = React;

function InsuranceCapture({ value = {}, onChange }) {
  const [tab, setTab] = useICs('scan');
  const [scanLoading, setScanLoading] = useICs(false);
  const [scanErr, setScanErr] = useICs(null);
  const [sttErr, setSttErr] = useICs(null);
  const [recording, setRecording] = useICs(false);
  const [sttStatus, setSttStatus] = useICs(''); // 'listening' | 'processing' | ''
  const [consentOk, setConsentOk] = useICs(() => {
    try { return !!localStorage.getItem('td_voice_consent'); } catch { return false; }
  });
  const mediaRef = useICr(null);
  const chunksRef = useICr([]);
  const recognitionRef = useICr(null);

  const update = (patch) => onChange && onChange({ ...value, ...patch });

  // ── Scan ──────────────────────────────────────────────────────────────────
  const onScanFile = async (e) => {
    const file = e.target.files && e.target.files[0];
    if (!file) return;
    setScanLoading(true); setScanErr(null);
    try {
      const fd = new FormData();
      fd.append('image', file);
      const resp = await fetch('/api/scan-insurance', { method: 'POST', body: fd });
      const d = await resp.json().catch(() => ({}));
      if (!resp.ok || d.ok === false) {
        setScanErr(d.error || `Couldn't read the card (${resp.status})`);
        return;
      }
      // Response shape: { ok, source, parsed: { carrier, plan_type, group_id, member_id, ... } }
      const p = d.parsed || d;
      if (!p.carrier && !p.member_id && !p.group_id) {
        setScanErr('Card scanned but no fields were recognised. Please type the details below.');
        return;
      }
      update({
        carrier:  p.carrier   || value.carrier  || '',
        plan:     p.plan_type || p.plan         || value.plan    || '',
        memberId: p.member_id || p.memberId     || value.memberId || '',
        groupId:  p.group_id  || p.groupId      || value.groupId  || '',
        _scan_source: d.source,
        _scan_notes:  p.notes || p.note || '',
      });
    } catch {
      setScanErr('Network error scanning card. Please try again or type it in.');
    } finally {
      setScanLoading(false);
    }
  };

  // ── STT helpers ───────────────────────────────────────────────────────────
  const parseTranscript = (text) => {
    const t = text || '';
    const carrierRx = /delta|aetna|cigna|metlife|blue\s*cross|blue\s*shield|united\s*health(?:care)?|kaiser|guardian|humana|premera|dentaquest|denti-?cal|medicaid|sunlife|principal|ameritas|careington/i;
    const memberRx  = /member(?:\s*id)?[:\s#]*([\w-]+)/i;
    const groupRx   = /group(?:\s*(?:id|number))?[:\s#]*([\w-]+)/i;
    const planRx    = /\b(ppo|hmo|dhmo|epo|indemnity|medicaid|medicare)\b/i;
    const carrierM  = carrierRx.exec(t);
    const memberM   = memberRx.exec(t);
    const groupM    = groupRx.exec(t);
    const planM     = planRx.exec(t);
    update({
      carrier:  carrierM ? carrierM[0].trim() : value.carrier  || '',
      plan:     planM    ? planM[1].toUpperCase() : value.plan  || '',
      memberId: memberM  ? memberM[1]  : value.memberId || '',
      groupId:  groupM   ? groupM[1]   : value.groupId  || '',
      _transcript: t,
    });
  };

  const grantConsent = () => {
    const ok = window.confirm(
      'California Penal Code § 632 consent\n\n' +
      'We’ll transcribe your spoken insurance details using your browser’s speech recognition. ' +
      'Audio is processed locally in your browser and not sent to our servers. ' +
      'Press OK to consent and continue.'
    );
    if (!ok) return false;
    try { localStorage.setItem('td_voice_consent', new Date().toISOString()); } catch {}
    setConsentOk(true);
    return true;
  };

  // Primary: browser Web Speech API (Chrome/Edge — no backend needed)
  const startBrowserSTT = () => {
    const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
    const rec = new SpeechRecognition();
    recognitionRef.current = rec;
    rec.continuous = false;
    rec.lang = 'en-US';
    rec.interimResults = false;
    rec.maxAlternatives = 1;

    rec.onstart  = () => { setRecording(true); setSttStatus('listening'); setSttErr(null); };
    rec.onend    = () => { setRecording(false); setSttStatus(''); };
    rec.onerror  = (ev) => {
      setRecording(false); setSttStatus('');
      if (ev.error === 'not-allowed') setSttErr('Microphone access denied. Type it in instead.');
      else if (ev.error === 'no-speech') setSttErr('Nothing heard. Try again or type it in.');
      else setSttErr(`Recognition error: ${ev.error}. Type it in instead.`);
    };
    rec.onresult = (ev) => {
      const text = ev.results[0][0].transcript;
      parseTranscript(text);
    };
    rec.start();
  };

  // Fallback: MediaRecorder → POST /api/transcribe
  const startFallbackSTT = async () => {
    try {
      const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
      const mr = new MediaRecorder(stream);
      mediaRef.current = mr;
      chunksRef.current = [];
      mr.ondataavailable = (e) => { if (e.data && e.data.size) chunksRef.current.push(e.data); };
      mr.onstop = async () => {
        stream.getTracks().forEach(t => t.stop());
        setSttStatus('processing');
        try {
          const blob = new Blob(chunksRef.current, { type: 'audio/webm' });
          const fd = new FormData();
          fd.append('audio', blob, 'insurance.webm');
          const resp = await fetch('/api/transcribe', { method: 'POST', body: fd });
          const d = await resp.json().catch(() => ({}));
          if (!resp.ok || d.ok === false) {
            setSttErr(d.error || 'Transcription failed. Please type it in.');
          } else if (d.text) {
            parseTranscript(d.text);
          } else {
            setSttErr('Nothing heard. Try again or type it in.');
          }
        } catch {
          setSttErr('Network error during transcription. Type it in instead.');
        } finally {
          setSttStatus('');
          setRecording(false);
        }
      };
      mr.start();
      setRecording(true);
      setSttStatus('listening');
      setSttErr(null);
      // Auto-stop after 15 s
      setTimeout(() => {
        if (mr.state === 'recording') { mr.stop(); setRecording(false); }
      }, 15000);
    } catch {
      setSttErr('Microphone access denied. Type it in instead.');
      setRecording(false); setSttStatus('');
    }
  };

  const consentAndRecord = async () => {
    if (!consentOk && !grantConsent()) return;
    const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
    if (SpeechRecognition) {
      startBrowserSTT();
    } else {
      await startFallbackSTT();
    }
  };

  const stopRecording = () => {
    if (recognitionRef.current) { recognitionRef.current.stop(); recognitionRef.current = null; }
    if (mediaRef.current && mediaRef.current.state === 'recording') mediaRef.current.stop();
    setRecording(false); setSttStatus('');
  };

  // ── Render ────────────────────────────────────────────────────────────────
  const TABS = [['scan', 'Scan card'], ['speak', 'Speak'], ['type', 'Type']];

  return (
    <div style={{ border:'1px solid var(--ink-5)', borderRadius:14, background:'var(--paper)' }}>
      <div role="tablist" aria-label="Insurance capture method"
        style={{ display:'flex', borderBottom:'1px solid var(--ink-5)' }}>
        {TABS.map(([k, label]) => (
          <button key={k} role="tab" aria-selected={tab===k}
            onClick={()=>{ setTab(k); setScanErr(null); setSttErr(null); }}
            style={{
              flex:1, padding:'10px 12px', fontSize:13, fontWeight:600, cursor:'pointer',
              background: tab===k ? 'var(--bone)' : 'var(--paper)',
              color: tab===k ? 'var(--ink-1)' : 'var(--ink-3)',
              border:0, borderBottom: tab===k ? '2px solid var(--seal)' : '2px solid transparent',
            }}>{label}</button>
        ))}
      </div>

      <div style={{ padding:'var(--s-4)' }}>
        {tab === 'scan' && (
          <div>
            <p style={{margin:'0 0 var(--s-3)',fontSize:13,color:'var(--ink-2)'}}>
              Take a photo of the front of your insurance card. The image is processed server-side only and not retained.
            </p>
            <label className="btn btn-secondary btn-md" style={{display:'inline-block',cursor:'pointer'}}>
              <input type="file" accept="image/*" capture="environment" onChange={onScanFile}
                style={{position:'absolute',width:1,height:1,opacity:0}}/>
              {scanLoading ? 'Reading card…' : 'Take or upload a photo'}
            </label>
            {scanErr && (
              <div role="alert" style={{marginTop:8,color:'var(--seal)',fontSize:13,padding:'8px 10px',background:'#fff0f0',borderRadius:8}}>
                {scanErr}
              </div>
            )}
            {value._scan_notes && (
              <div style={{marginTop:8,fontSize:12,color:'var(--ink-3)',padding:'6px 8px',background:'var(--bone)',borderRadius:6}}>
                {value._scan_notes}
              </div>
            )}
          </div>
        )}

        {tab === 'speak' && (
          <div>
            <p style={{margin:'0 0 var(--s-3)',fontSize:13,color:'var(--ink-2)'}}>
              Say your carrier name, plan type, member ID, and group ID. Speak clearly and pause between items.
            </p>
            {!recording && sttStatus !== 'processing' ? (
              <button type="button" className="btn btn-secondary btn-md" onClick={consentAndRecord}>
                {consentOk ? 'Start recording' : 'Consent + start recording'}
              </button>
            ) : sttStatus === 'processing' ? (
              <div style={{fontSize:13,color:'var(--ink-3)',padding:'8px 0'}}>Transcribing…</div>
            ) : (
              <button type="button" className="btn btn-primary btn-md" onClick={stopRecording}
                style={{background:'var(--seal)',color:'#fff'}}>
                ■ Stop recording
              </button>
            )}
            {recording && sttStatus === 'listening' && (
              <div style={{marginTop:8,fontSize:13,color:'var(--seal)',display:'flex',alignItems:'center',gap:6}}>
                <span style={{width:8,height:8,borderRadius:'50%',background:'var(--seal)',display:'inline-block',animation:'pulse 1s ease-in-out infinite'}}/>
                Listening… speak now
              </div>
            )}
            {sttErr && (
              <div role="alert" style={{marginTop:8,color:'var(--seal)',fontSize:13,padding:'8px 10px',background:'#fff0f0',borderRadius:8}}>
                {sttErr}
              </div>
            )}
            {value._transcript && (
              <div style={{marginTop:'var(--s-2)',padding:'8px 10px',background:'var(--bone)',borderRadius:8,fontSize:13,color:'var(--ink-2)'}}>
                <strong>Heard:</strong> "{value._transcript}"
              </div>
            )}
          </div>
        )}

        {tab === 'type' && (
          <p style={{margin:'0 0 var(--s-3)',fontSize:13,color:'var(--ink-2)'}}>
            Enter your insurance details below.
          </p>
        )}

        <div style={{display:'grid',gridTemplateColumns:'repeat(2, 1fr)',gap:'var(--s-3)',marginTop:'var(--s-3)'}}>
          <Field label="Carrier" value={value.carrier} onChange={v=>update({carrier:v})} placeholder="Delta Dental PPO"/>
          <Field label="Plan type" value={value.plan} onChange={v=>update({plan:v})} placeholder="PPO"/>
          <Field label="Member ID" value={value.memberId} onChange={v=>update({memberId:v})} placeholder="ABC1234567"/>
          <Field label="Group ID" value={value.groupId} onChange={v=>update({groupId:v})} placeholder="0001234"/>
        </div>
      </div>
    </div>
  );
}

function Field({ label, value, onChange, placeholder }) {
  return (
    <label style={{display:'flex',flexDirection:'column',gap:4,fontSize:12,color:'var(--ink-3)',fontWeight:600}}>
      {label}
      <input type="text" value={value || ''} onChange={(e)=>onChange(e.target.value)} placeholder={placeholder}
        style={{padding:'8px 10px',border:'1px solid var(--ink-5)',borderRadius:8,fontSize:14,color:'var(--ink-1)',background:'var(--paper)'}}/>
    </label>
  );
}

window.InsuranceCapture = InsuranceCapture;
