// Stage 2: Upload voice note (mic + file) and Stage 3: Transcribe loading
// Rev 2: captures real File/Blob and forwards it to the parent for /api/jobs.

// Checkpoint before spending an LLM call: is the photo legible?
const ImagePreviewStage = ({ file, onExtract, onChooseAnother }) => {
  const [url, setUrl] = React.useState(null);
  React.useEffect(() => {
    const u = URL.createObjectURL(file);
    setUrl(u);
    return () => URL.revokeObjectURL(u);
  }, [file]);

  return (
    <div style={{ maxWidth: 820, margin: "0 auto", padding: "40px 32px" }}>
      <div style={{ marginBottom: 28 }}>
        <Eyebrow style={{ marginBottom: 10 }}>Step 3 of 4 · Preview</Eyebrow>
        <h2 style={{ fontFamily: V.font, fontSize: 28, fontWeight: V.fw.m, color: V.brown, margin: 0, lineHeight: 1.1, letterSpacing: "-0.015em" }}>
          Check the photo is legible
        </h2>
        <p style={{ fontFamily: V.font, fontSize: 13, color: V.brownMid, marginTop: 8 }}>
          Make sure the whole form is in frame and the handwriting is readable — then extract.
        </p>
      </div>

      <Card pad={0} style={{ overflow: "hidden" }}>
        <div style={{ padding: "14px 22px", borderBottom: `1px solid ${V.borderLight}`, background: V.offWhite, display: "flex", alignItems: "center", gap: 10 }}>
          <div style={{ width: 28, height: 28, borderRadius: V.radiusSm, background: V.orangeSubtle, display: "flex", alignItems: "center", justifyContent: "center" }}>
            <Icon name="file" size={14} color={V.orange}/>
          </div>
          <div>
            <div style={{ fontFamily: V.font, fontSize: 13, fontWeight: V.fw.m, color: V.brown }}>{file.name}</div>
            <div style={{ fontFamily: V.font, fontSize: 11, color: V.brownFaded }}>{(file.size / (1024 * 1024)).toFixed(2)} MB</div>
          </div>
        </div>
        <div style={{ padding: 20, textAlign: "center", background: V.offWhite }}>
          {url && <img src={url} alt="Form scan preview" style={{ maxWidth: "100%", maxHeight: "62vh", borderRadius: V.radiusSm, border: `1px solid ${V.borderMed}` }}/>}
        </div>
      </Card>

      <div style={{ display: "flex", justifyContent: "space-between", marginTop: 20 }}>
        <Button variant="outline" icon="refresh" onClick={onChooseAnother}>Choose another photo</Button>
        <Button icon="sparkles" iconRight="arrowRight" onClick={onExtract}>Extract fields</Button>
      </div>
    </div>
  );
};

const UploadStage = ({ formKind, onBack, onTranscribe, onImageReady }) => {
  const [mode, setMode] = React.useState(null); // null | "record" | "file" | "camera"
  const [recording, setRecording] = React.useState(false);
  const [paused, setPaused] = React.useState(false);
  const [elapsed, setElapsed] = React.useState(0);
  const [recordedBlob, setRecordedBlob] = React.useState(null);
  const [recordedMime, setRecordedMime] = React.useState(null);
  const [file, setFile] = React.useState(null);
  const [dragOver, setDragOver] = React.useState(false);
  const [recError, setRecError] = React.useState(null);
  const mediaRecorderRef = React.useRef(null);
  const chunksRef = React.useRef([]);
  const fileInputRef = React.useRef(null);
  const imageInputRef = React.useRef(null);
  const camFallbackRef = React.useRef(null);
  const videoRef = React.useRef(null);
  const camStreamRef = React.useRef(null);

  // Always the TATA Capital Business Loan form scan — parent flips the flow
  // to business_loan once an image is handed up.
  const pickImageFile = (f) => {
    if (!f) return;
    if (!/\.(jpe?g|png|webp)$/i.test(f.name)) { setRecError("Only .jpg .jpeg .png .webp accepted"); return; }
    if (f.size > 15 * 1024 * 1024) { setRecError("Image too large (max 15 MB)"); return; }
    setRecError(null);
    onImageReady(f);
  };

  const startCamera = async () => {
    setRecError(null);
    try {
      const stream = await navigator.mediaDevices.getUserMedia({
        video: { facingMode: "environment", width: { ideal: 1920 } },
      });
      camStreamRef.current = stream;
      setMode("camera");
    } catch (e) {
      // Camera denied/unavailable → native capture input (opens camera on phones).
      camFallbackRef.current && camFallbackRef.current.click();
    }
  };

  const stopCamera = () => {
    if (camStreamRef.current) {
      camStreamRef.current.getTracks().forEach(t => t.stop());
      camStreamRef.current = null;
    }
  };

  React.useEffect(() => {
    if (mode !== "camera") return;
    const v = videoRef.current;
    if (v && camStreamRef.current) {
      v.srcObject = camStreamRef.current;
      v.play().catch(() => {});
    }
    return stopCamera;
  }, [mode]);

  const capturePhoto = () => {
    const v = videoRef.current;
    if (!v || !v.videoWidth) return;
    const canvas = document.createElement("canvas");
    canvas.width = v.videoWidth; canvas.height = v.videoHeight;
    canvas.getContext("2d").drawImage(v, 0, 0);
    canvas.toBlob(b => {
      if (!b) { setRecError("Could not capture a frame — try again"); return; }
      setMode(null); // effect cleanup stops the camera
      onImageReady(new File([b], `capture-${Date.now()}.jpg`, { type: "image/jpeg" }));
    }, "image/jpeg", 0.92);
  };

  // elapsed tick
  React.useEffect(() => {
    if (!recording || paused) return;
    const t = setInterval(() => setElapsed(e => e + 0.1), 100);
    return () => clearInterval(t);
  }, [recording, paused]);

  const startRecording = async () => {
    setRecError(null); setRecordedBlob(null); setElapsed(0);
    try {
      const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
      const mime = MediaRecorder.isTypeSupported("audio/webm;codecs=opus")
        ? "audio/webm;codecs=opus"
        : (MediaRecorder.isTypeSupported("audio/webm") ? "audio/webm" : "");
      const rec = mime ? new MediaRecorder(stream, { mimeType: mime })
                       : new MediaRecorder(stream);
      chunksRef.current = [];
      rec.ondataavailable = (ev) => { if (ev.data && ev.data.size) chunksRef.current.push(ev.data); };
      rec.onstop = () => {
        const blob = new Blob(chunksRef.current, { type: rec.mimeType || "audio/webm" });
        setRecordedBlob(blob); setRecordedMime(rec.mimeType || "audio/webm");
        stream.getTracks().forEach(t => t.stop());
      };
      mediaRecorderRef.current = rec;
      rec.start();
      setRecording(true); setPaused(false); setMode("record");
    } catch (e) {
      setRecError(e?.message || "microphone access denied");
    }
  };

  const pauseRecording = () => {
    const rec = mediaRecorderRef.current;
    if (rec && rec.state === "recording") { rec.pause(); setPaused(true); }
  };

  const resumeRecording = () => {
    const rec = mediaRecorderRef.current;
    if (rec && rec.state === "paused") { rec.resume(); setPaused(false); }
  };

  const stopRecording = () => {
    if (mediaRecorderRef.current && mediaRecorderRef.current.state !== "inactive") {
      mediaRecorderRef.current.stop();
    }
    setRecording(false); setPaused(false);
  };

  const discardRecording = () => {
    stopRecording();
    setRecordedBlob(null); setRecordedMime(null); setElapsed(0); setMode(null);
  };

  const pickFile = (f) => {
    if (!f) return;
    const okExt = /\.(wav|mp3|webm|m4a)$/i.test(f.name);
    if (!okExt) { setRecError("Only .wav .mp3 .webm .m4a accepted"); return; }
    if (f.size > 50 * 1024 * 1024) { setRecError("File too large (max 50 MB)"); return; }
    setRecError(null); setFile(f);
  };

  const onFilePicked = (e) => pickFile(e.target.files && e.target.files[0]);
  const onDrop = (e) => {
    e.preventDefault(); setDragOver(false);
    pickFile(e.dataTransfer.files && e.dataTransfer.files[0]);
  };

  const handleTranscribe = () => {
    if (mode === "record" && recordedBlob) {
      const ext = (recordedMime && recordedMime.includes("webm")) ? ".webm" : ".webm";
      const name = `recording-${Date.now()}${ext}`;
      onTranscribe({ blob: recordedBlob, filename: name, durationSec: elapsed, source: "recorded" });
      return;
    }
    if (mode === "file" && file) {
      onTranscribe({ blob: file, filename: file.name, durationSec: null, source: "uploaded" });
      return;
    }
  };

  const fmtTime = (s) => {
    const m = Math.floor(s / 60), sec = Math.floor(s % 60);
    return `${String(m).padStart(2,"0")}:${String(sec).padStart(2,"0")}`;
  };

  return (
    <div style={{ maxWidth: 820, margin: "0 auto", padding: "40px 32px" }}>
      <button onClick={onBack} style={{
        display: "inline-flex", alignItems: "center", gap: 6, background: "transparent",
        border: "none", cursor: "pointer", color: V.brownMid, fontFamily: V.font,
        fontSize: 12, padding: "6px 10px 6px 0", marginBottom: 20,
      }}>
        <Icon name="arrowLeft" size={13} color={V.brownMid}/> Change form type
      </button>

      <div style={{ marginBottom: 28 }}>
        <Eyebrow style={{ marginBottom: 10 }}>Step 2 of 4 · Voice or Scan</Eyebrow>
        <h2 style={{ fontFamily: V.font, fontSize: 28, fontWeight: V.fw.m, color: V.brown, margin: 0, lineHeight: 1.1, letterSpacing: "-0.015em" }}>
          Record the call, or scan the filled form
        </h2>
        <p style={{ fontFamily: V.font, fontSize: 13, color: V.brownMid, marginTop: 8 }}>
          Dictate the applicant's details in English, Hindi, or Hinglish — or photograph the filled TATA Capital application form and we'll read it.
        </p>
      </div>

      <input ref={imageInputRef} type="file" accept="image/jpeg,image/png,image/webp,.jpg,.jpeg,.png,.webp"
             style={{ display: "none" }}
             onChange={e => { pickImageFile(e.target.files && e.target.files[0]); e.target.value = ""; }}/>
      <input ref={camFallbackRef} type="file" accept="image/*" capture="environment"
             style={{ display: "none" }}
             onChange={e => { pickImageFile(e.target.files && e.target.files[0]); e.target.value = ""; }}/>

      {!mode && (
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 16 }}>
          <OptionTile icon="mic" title="Record now" subtitle="Dictate details live using your mic" onClick={startRecording}/>
          <OptionTile icon="upload" title="Upload audio" subtitle="MP3, WAV, WebM, M4A up to 50 MB" onClick={() => setMode("file")}/>
          <OptionTile icon="camera" title="Capture form image" subtitle="Photograph the filled TATA Capital form with your webcam or phone camera" onClick={startCamera}/>
          <OptionTile icon="file" title="Upload form image" subtitle="JPG, PNG, WebP up to 15 MB — we'll read the handwriting" onClick={() => imageInputRef.current && imageInputRef.current.click()}/>
        </div>
      )}

      {recError && (
        <div style={{ marginTop: 14, padding: "10px 14px", background: "#FEE", border: "1px solid #FAA", borderRadius: 6, fontFamily: V.font, fontSize: 13, color: "#900" }}>
          {recError}
        </div>
      )}

      {mode === "record" && (
        <Card pad={32} style={{ position: "relative", marginTop: 16 }}>
          <FocusCorners color={V.orange} inset={-6} size={12}/>
          <div style={{ display: "flex", flexDirection: "column", alignItems: "center", gap: 20 }}>
            <div style={{ position: "relative", width: 104, height: 104 }}>
              {recording && !paused && (<><div style={pulseRing(0)}/><div style={pulseRing(0.6)}/></>)}
              <div style={{
                position: "relative", width: 104, height: 104, borderRadius: "50%",
                background: recording && !paused ? V.orange : V.brown, display: "flex",
                alignItems: "center", justifyContent: "center",
                boxShadow: recording && !paused ? V.shadowOrange : V.shadowMd,
              }}>
                <Icon name="mic" size={36} color={V.white}/>
              </div>
            </div>
            <div style={{ textAlign: "center" }}>
              <div style={{ fontFamily: V.font, fontSize: 32, fontWeight: V.fw.sb, color: V.brown, fontVariantNumeric: "tabular-nums" }}>
                {fmtTime(elapsed)}
              </div>
              <div style={{ fontFamily: V.font, fontSize: 12, color: recording && !paused ? V.orange : V.brownMid, marginTop: 4 }}>
                {recording && !paused
                  ? "Recording — speak naturally"
                  : (recording && paused ? "Paused — tap resume to continue"
                     : (recordedBlob ? "Recorded — ready to transcribe" : "Ready"))}
              </div>
            </div>
            <Waveform active={recording && !paused}/>
            <div style={{ display: "flex", gap: 10, marginTop: 4 }}>
              {recording ? (
                <>
                  {paused
                    ? <Button variant="outline" size="md" icon="play" onClick={resumeRecording}>Resume</Button>
                    : <Button variant="outline" size="md" icon="pause" onClick={pauseRecording}>Pause</Button>}
                  <Button variant="outline" size="md" icon="stop" onClick={stopRecording}>Stop</Button>
                </>
              ) : (
                <Button variant="outline" size="md" icon="play" onClick={startRecording}>Re-record</Button>
              )}
              <Button variant="ghost" size="md" icon="trash" onClick={discardRecording}>Discard</Button>
              <Button size="md" icon="sparkles" disabled={!recordedBlob} onClick={handleTranscribe}>
                Transcribe
              </Button>
            </div>
          </div>
        </Card>
      )}

      {mode === "camera" && (
        <Card pad={24} style={{ position: "relative", marginTop: 16 }}>
          <FocusCorners color={V.orange} inset={-6} size={12}/>
          <video ref={videoRef} playsInline muted
                 style={{ width: "100%", maxHeight: "56vh", objectFit: "contain", background: V.brown, borderRadius: V.radiusSm, display: "block" }}/>
          <div style={{ fontFamily: V.font, fontSize: 12, color: V.brownMid, textAlign: "center", marginTop: 12 }}>
            Hold the filled TATA Capital form flat in frame, then capture.
          </div>
          <div style={{ display: "flex", justifyContent: "center", gap: 10, marginTop: 14 }}>
            <Button variant="ghost" size="md" icon="x" onClick={() => setMode(null)}>Cancel</Button>
            <Button size="md" icon="camera" onClick={capturePhoto}>Capture photo</Button>
          </div>
        </Card>
      )}

      {mode === "file" && (
        <Card pad={32} style={{ marginTop: 16 }}>
          <input ref={fileInputRef} type="file" accept="audio/wav,audio/mpeg,audio/mp3,audio/webm,audio/m4a,audio/mp4,.wav,.mp3,.webm,.m4a"
                 style={{ display: "none" }} onChange={onFilePicked}/>
          <div onDragOver={e => { e.preventDefault(); setDragOver(true); }}
               onDragLeave={() => setDragOver(false)}
               onDrop={onDrop}
               onClick={() => fileInputRef.current && fileInputRef.current.click()}
               style={{
                 border: `1.5px dashed ${dragOver ? V.orange : V.borderMed}`,
                 borderRadius: V.radius, padding: "44px 24px", textAlign: "center",
                 cursor: "pointer", background: dragOver ? V.orangeSubtle : V.offWhite,
                 transition: "all 0.2s",
               }}>
            {!file ? (
              <>
                <div style={{ width: 52, height: 52, borderRadius: V.radiusLg, background: V.white, border: `1px solid ${V.borderMed}`, display: "inline-flex", alignItems: "center", justifyContent: "center", marginBottom: 14 }}>
                  <Icon name="upload" size={22} color={V.orange}/>
                </div>
                <div style={{ fontFamily: V.font, fontSize: 15, fontWeight: V.fw.m, color: V.brown, marginBottom: 4 }}>
                  Drop audio file here, or click to browse
                </div>
                <div style={{ fontFamily: V.font, fontSize: 12, color: V.brownFaded }}>
                  MP3, WAV, WebM, M4A · up to 50 MB
                </div>
              </>
            ) : (
              <div style={{ display: "flex", alignItems: "center", gap: 14, textAlign: "left" }}>
                <div style={{ width: 44, height: 44, borderRadius: V.radiusSm, background: V.orangeSubtle, display: "flex", alignItems: "center", justifyContent: "center", flexShrink: 0 }}>
                  <Icon name="volume" size={18} color={V.orange}/>
                </div>
                <div style={{ flex: 1 }}>
                  <div style={{ fontFamily: V.font, fontSize: 14, fontWeight: V.fw.m, color: V.brown }}>{file.name}</div>
                  <div style={{ fontFamily: V.font, fontSize: 11, color: V.brownFaded, marginTop: 2 }}>
                    {(file.size / (1024 * 1024)).toFixed(2)} MB
                  </div>
                </div>
                <Button variant="outline" size="sm" icon="trash"
                        onClick={(e) => { e.stopPropagation(); setFile(null); }}>Remove</Button>
              </div>
            )}
          </div>

          <div style={{ display: "flex", justifyContent: "space-between", marginTop: 20 }}>
            <Button variant="ghost" size="md" icon="arrowLeft" onClick={() => { setMode(null); setFile(null); }}>Back</Button>
            <Button size="md" iconRight="arrowRight" icon="sparkles" disabled={!file} onClick={handleTranscribe}>
              Transcribe voice note
            </Button>
          </div>
        </Card>
      )}
    </div>
  );
};

const OptionTile = ({ icon, title, subtitle, onClick }) => {
  const [h, setH] = React.useState(false);
  return (
    <div onMouseEnter={() => setH(true)} onMouseLeave={() => setH(false)} onClick={onClick}
      style={{
        position: "relative", background: V.white, border: `1px solid ${h ? V.orange : V.borderMed}`,
        borderRadius: V.radius, padding: 24, cursor: "pointer",
        transition: "all 0.2s", transform: h ? "translateY(-2px)" : "none",
        boxShadow: h ? V.shadowMd : "none",
      }}>
      <div style={{ width: 44, height: 44, borderRadius: V.radius, background: V.orangeSubtle, display: "flex", alignItems: "center", justifyContent: "center", marginBottom: 14 }}>
        <Icon name={icon} size={20} color={V.orange}/>
      </div>
      <div style={{ fontFamily: V.font, fontSize: 16, fontWeight: V.fw.m, color: V.brown, marginBottom: 4 }}>{title}</div>
      <div style={{ fontFamily: V.font, fontSize: 12, color: V.brownMid, lineHeight: 1.5 }}>{subtitle}</div>
    </div>
  );
};

const pulseRing = (delay) => ({
  position: "absolute", inset: 0, borderRadius: "50%",
  border: `2px solid ${V.orange}`, opacity: 0,
  animation: `v2f-pulse 1.8s ease-out ${delay}s infinite`,
});

const Waveform = ({ active, bars = 48 }) => {
  const [tick, setTick] = React.useState(0);
  React.useEffect(() => {
    if (!active) return;
    const t = setInterval(() => setTick(v => v + 1), 80);
    return () => clearInterval(t);
  }, [active]);
  const heights = React.useMemo(() => Array.from({ length: bars }, (_, i) => {
    if (!active) return 4;
    const seed = (i * 7 + tick * 3) % 17;
    const phase = Math.sin((i + tick) * 0.35) * 0.5 + 0.5;
    return 6 + Math.floor(phase * 30) + (seed % 6);
  }), [tick, active, bars]);
  return (
    <div style={{ display: "flex", alignItems: "center", gap: 3, height: 44, width: "100%", justifyContent: "center" }}>
      {heights.map((h, i) => (
        <div key={i} style={{ width: 3, height: h, borderRadius: 2, background: active ? V.orange : V.borderMed, opacity: active ? 0.75 + (h/100) : 0.5, transition: "height 0.1s ease-out" }}/>
      ))}
    </div>
  );
};

const ProcessingStage = ({ phase, formKind }) => {
  const isImage = formKind === "business_loan";
  const steps = isImage
    ? [{ id: "extract", label: "Reading the form", sub: "Claude Sonnet 4.5 vision on Bedrock" }]
    : [
        { id: "transcribe", label: "Transcribing audio",   sub: "AWS Transcribe · en-IN / hi-IN" },
        { id: "extract",    label: "Extracting fields",    sub: "Claude Sonnet 4.5 on Bedrock" },
      ];
  return (
    <div style={{ maxWidth: 640, margin: "0 auto", padding: "96px 32px" }}>
      <div style={{ textAlign: "center", marginBottom: 36 }}>
        <div style={{ position: "relative", width: 72, height: 72, margin: "0 auto 20px" }}>
          <div style={{ position: "absolute", inset: 0, borderRadius: "50%", border: `3px solid ${V.borderLight}`, borderTopColor: V.orange, animation: "v2f-spin 0.9s linear infinite" }}/>
          <div style={{ position: "absolute", inset: 14, borderRadius: "50%", background: V.orangeSubtle, display: "flex", alignItems: "center", justifyContent: "center" }}>
            <Icon name={phase === "transcribe" ? "waveform" : "sparkles"} size={22} color={V.orange}/>
          </div>
        </div>
        <h3 style={{ fontFamily: V.font, fontSize: 22, fontWeight: V.fw.m, color: V.brown, margin: 0 }}>
          {phase === "transcribe" ? "Transcribing your voice note…"
            : isImage ? "Reading the form scan…" : "Extracting fields…"}
        </h3>
        <p style={{ fontFamily: V.font, fontSize: 13, color: V.brownMid, marginTop: 8 }}>
          {phase === "transcribe"
            ? "Separating speech from silence and converting audio to text."
            : isImage
              ? "Reading the handwriting and mapping it to the Business Loan application schema."
              : "Reading the transcript and mapping it to the " + (formKind === "sep" ? "SEP" : "Salaried") + " loan schema."}
        </p>
      </div>
      <Card pad={22}>
        {steps.map((s, i) => {
          const done = (phase === "extract" && s.id === "transcribe");
          const active = phase === s.id;
          return (
            <div key={s.id} style={{ display: "flex", alignItems: "center", gap: 14, padding: "12px 0", borderBottom: i < steps.length - 1 ? `1px solid ${V.borderLight}` : "none" }}>
              <div style={{ width: 28, height: 28, borderRadius: "50%", background: done ? V.success : active ? V.orange : "transparent", border: !done && !active ? `1.5px solid ${V.borderMed}` : "none", display: "flex", alignItems: "center", justifyContent: "center" }}>
                {done ? <Icon name="check" size={13} color={V.white}/> :
                 active ? <div style={{ width: 8, height: 8, borderRadius: "50%", background: V.white, animation: "v2f-blink 1s ease-in-out infinite" }}/> :
                 <div style={{ width: 6, height: 6, borderRadius: "50%", background: V.brownFaded }}/>}
              </div>
              <div style={{ flex: 1 }}>
                <div style={{ fontFamily: V.font, fontSize: 13, fontWeight: V.fw.m, color: done || active ? V.brown : V.brownFaded }}>{s.label}</div>
                <div style={{ fontFamily: V.font, fontSize: 11, color: V.brownFaded, marginTop: 2 }}>{s.sub}</div>
              </div>
              {active && <div style={{ fontFamily: V.font, fontSize: 11, color: V.orange }}>Running…</div>}
              {done && <div style={{ fontFamily: V.font, fontSize: 11, color: V.success }}>Done</div>}
            </div>
          );
        })}
      </Card>
    </div>
  );
};

Object.assign(window, { UploadStage, ImagePreviewStage, ProcessingStage });
