// screens-details.jsx — optional "special details" capture (ring, necklace, scar…) with notes

const { useState: useD } = React;

const DETAIL_CHIPS = ['Wedding ring', 'Necklace', 'Scar', 'Tattoo', 'Birthmark'];

function DetailsScreen({ ctx }) {
  const initialContact = (ctx && ctx.capture && ctx.capture.contact) || {};
  const [details,   setDetails]   = useD([]);
  const [adding,    setAdding]    = useD(false);
  const [firstName, setFirstName] = useD(initialContact.first_name || '');
  const [email,     setEmail]     = useD(initialContact.email      || '');

  const addDetail = (note, file) => {
    setDetails((d) => [...d, { note, file }]);
    setAdding(false);
  };
  const remove = (i) => setDetails((d) => d.filter((_, j) => j !== i));

  // Stage the contact + details into the cross-screen store, then advance.
  const send = () => {
    if (ctx && ctx.capture) {
      ctx.capture.contact = {
        ...ctx.capture.contact,
        first_name: firstName.trim() || null,
        email:      email.trim().toLowerCase() || null,
      };
      // Remove any previously staged details, then push the current ones.
      ctx.capture.photos = (ctx.capture.photos || []).filter((p) => p.angle !== 'detail');
      details.forEach((d, idx) => {
        if (d.file) ctx.capture.photos.push({ angle: 'detail', file: d.file, note: d.note });
      });
    }
    ctx.go('processing');
  };

  const emailRe = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
  const canSend = email.trim() === '' || emailRe.test(email.trim());

  return (
    <div className="scr scr--light">
      <div style={{ flex: '0 0 auto' }}>
        <TopBar onBack={() => ctx.go('capture')} onHelp={ctx.onHelp} />
      </div>

      <div style={{ flex: 1, minHeight: 0, overflowY: 'auto' }}>
        <div className="pad" style={{ paddingBottom: 16 }}>
          <span className="eyebrow">Almost done · optional</span>
          <h1 className="title" style={{ marginTop: 8 }}>Any special details to keep?</h1>
          <p className="lede" style={{ fontSize: 14.5, marginTop: 10 }}>
            Add a close-up of anything that matters, like a wedding ring, a necklace, or a scar you'd like to remember. Our sculptors will work these in by hand.
          </p>

          {/* contact details so Laila can reach you */}
          <div className="card" style={{ marginTop: 18, padding: 16 }}>
            <div style={{ fontSize: 11.5, fontWeight: 700, letterSpacing: '.06em', textTransform: 'uppercase', color: 'var(--gold)', marginBottom: 10 }}>
              How shall we reach you?
            </div>
            <input
              type="text"
              value={firstName}
              onChange={(e) => setFirstName(e.target.value)}
              placeholder="First name"
              style={{ width: '100%', padding: '12px 14px', borderRadius: 12, border: '1.5px solid var(--hairline)', background: 'var(--paper)', fontFamily: 'var(--sans)', fontSize: 15, color: 'var(--ink)', outline: 'none', boxSizing: 'border-box' }} />
            <input
              type="email"
              value={email}
              onChange={(e) => setEmail(e.target.value)}
              placeholder="Email (so we can send your preview)"
              autoComplete="email"
              style={{ width: '100%', marginTop: 10, padding: '12px 14px', borderRadius: 12, border: '1.5px solid var(--hairline)', background: 'var(--paper)', fontFamily: 'var(--sans)', fontSize: 15, color: 'var(--ink)', outline: 'none', boxSizing: 'border-box' }} />
            <p style={{ margin: '10px 0 0', fontSize: 12.5, lineHeight: 1.5, color: 'var(--ink-mute)' }}>
              Optional, but if you leave it blank we cannot send you the screenshots later.
            </p>
          </div>

          {/* added details */}
          {details.length > 0 && (
            <div style={{ display: 'flex', flexDirection: 'column', gap: 10, marginTop: 18 }}>
              {details.map((d, i) => (
                <div key={i} className="card fadein" style={{ display: 'flex', alignItems: 'center', gap: 12, padding: 10 }}>
                  <div style={{ width: 52, height: 52, borderRadius: 10, overflow: 'hidden', flex: '0 0 auto' }}>
                    <Placeholder label="" dark />
                  </div>
                  <div style={{ flex: 1, minWidth: 0 }}>
                    <div style={{ fontSize: 11, letterSpacing: '.04em', textTransform: 'uppercase', color: 'var(--gold)', fontWeight: 700 }}>Detail {String(i + 1).padStart(2, '0')}</div>
                    <div style={{ fontSize: 14.5, fontWeight: 600, color: 'var(--ink)', marginTop: 1, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{d.note || 'Close-up'}</div>
                  </div>
                  <button onClick={() => remove(i)} aria-label="Remove" style={{ background: 'var(--paper-2)', border: '1px solid var(--hairline)', borderRadius: 999, width: 32, height: 32, display: 'flex', alignItems: 'center', justifyContent: 'center', cursor: 'pointer', color: 'var(--ink-mute)', flex: '0 0 auto' }}>
                    <IcX size={16} />
                  </button>
                </div>
              ))}
            </div>
          )}

          {/* add button */}
          <button onClick={() => setAdding(true)} style={{
            width: '100%', marginTop: 14, padding: '15px', borderRadius: 14, cursor: 'pointer',
            border: '1.5px dashed var(--gold-soft)', background: 'color-mix(in oklch, var(--gold), transparent 92%)',
            display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 9,
            fontFamily: 'var(--sans)', fontWeight: 600, fontSize: 15, color: 'var(--gold)',
          }}>
            <IcPlus size={18} /> {details.length ? 'Add another detail' : 'Add a detail'}
          </button>

          {/* honest disclaimer */}
          <div className="card" style={{ marginTop: 16, background: 'var(--paper-2)' }}>
            <div style={{ display: 'flex', gap: 11 }}>
              <span style={{ color: 'var(--ink-mute)', flex: '0 0 auto', marginTop: 1 }}><IcInfo size={19} /></span>
              <p style={{ margin: 0, fontSize: 13, lineHeight: 1.5, color: 'var(--ink-soft)' }}>
                We can't guarantee every detail survives, as casting is a delicate process, but we'll do our very best to honour the ones you mark.
              </p>
            </div>
          </div>
        </div>
      </div>

      {/* sticky continue */}
      <div style={{ flex: '0 0 auto', padding: '12px 20px 14px', borderTop: '1px solid var(--hairline)', background: 'var(--beige)' }}>
        <button className="btn btn--primary" onClick={send} disabled={!canSend} style={!canSend ? { opacity: .5, pointerEvents: 'none' } : null}>
          {details.length
            ? `Send the capture + ${details.length} detail${details.length > 1 ? 's' : ''}`
            : 'Send without extra details'}
        </button>
      </div>

      {adding && <AddDetailSheet onCancel={() => setAdding(false)} onAdd={addDetail} />}
    </div>
  );
}

// Mirrors the placeholder generator in screens-capture.jsx. A close-up "frame"
// drawn to canvas, so the upload pipeline has a real File to send until the
// real camera is wired in. The note text is overlaid so Laila can tell which
// detail came from where in the captured-photos thumbnail strip.
function makeDetailPlaceholderFile(note) {
  try {
    const c = document.createElement('canvas');
    c.width = 640; c.height = 640;
    const g = c.getContext('2d');
    if (g) {
      const grd = g.createRadialGradient(320, 280, 60, 320, 320, 480);
      grd.addColorStop(0, '#3c463a');
      grd.addColorStop(1, '#14160f');
      g.fillStyle = grd;
      g.fillRect(0, 0, 640, 640);
      g.fillStyle = '#a99a78';
      g.font = '600 30px Cormorant Garamond, Georgia, serif';
      g.textAlign = 'center';
      g.fillText('Special detail', 320, 300);
      g.fillStyle = '#ece7da';
      g.font = '500 24px Hanken Grotesk, system-ui, sans-serif';
      g.fillText(note || 'close-up', 320, 340);
    }
    const dataUrl = c.toDataURL('image/jpeg', 0.85);
    const bin = atob(dataUrl.split(',')[1]);
    const buf = new Uint8Array(bin.length);
    for (let i = 0; i < bin.length; i++) buf[i] = bin.charCodeAt(i);
    return new File([buf], `detail-${Date.now()}.jpg`, { type: 'image/jpeg' });
  } catch (e) {
    return new File([new Uint8Array(1)], 'detail.jpg', { type: 'image/jpeg' });
  }
}

function AddDetailSheet({ onCancel, onAdd }) {
  const [captured, setCaptured] = useD(false);          // dataURL of the freeze frame (null while live)
  const [note, setNote] = useD('');
  const [cameraReady, setCameraReady] = useD(false);
  const [cameraError, setCameraError] = useD(null);
  const videoRef  = React.useRef(null);
  const streamRef = React.useRef(null);

  // Start the rear camera stream when the sheet opens; tear it down when the
  // sheet unmounts. Captured state pauses the feed (we show the frozen frame
  // instead) but keeps the stream alive so Retake is instant.
  React.useEffect(() => {
    if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {
      setCameraError('camera-unsupported');
      return;
    }
    let cancelled = false;
    (async () => {
      try {
        const stream = await navigator.mediaDevices.getUserMedia({
          video: { facingMode: { ideal: 'environment' }, width: { ideal: 1280 }, height: { ideal: 1280 } },
          audio: false,
        });
        if (cancelled) { stream.getTracks().forEach(t => t.stop()); return; }
        streamRef.current = stream;
        if (videoRef.current) {
          videoRef.current.srcObject = stream;
          try { await videoRef.current.play(); } catch (e) {}
        }
        setCameraReady(true);
      } catch (e) {
        const name = (e && e.name) || '';
        if (name === 'NotAllowedError' || name === 'SecurityError') setCameraError('permission-denied');
        else                                                          setCameraError(name || 'camera-error');
      }
    })();
    return () => {
      cancelled = true;
      if (streamRef.current) {
        streamRef.current.getTracks().forEach(t => t.stop());
        streamRef.current = null;
      }
    };
  }, []);

  // Grab the current video frame as a freeze-preview AND keep the JPEG File
  // ready so onAdd can ship it through the upload pipeline.
  const grabFrame = () => {
    const v = videoRef.current;
    if (!v || !v.videoWidth) return null;
    const c = document.createElement('canvas');
    c.width = v.videoWidth; c.height = v.videoHeight;
    const g = c.getContext('2d');
    if (!g) return null;
    g.drawImage(v, 0, 0, c.width, c.height);
    const dataUrl = c.toDataURL('image/jpeg', 0.9);
    const bin = atob(dataUrl.split(',')[1]);
    const buf = new Uint8Array(bin.length);
    for (let i = 0; i < bin.length; i++) buf[i] = bin.charCodeAt(i);
    const file = new File([buf], `detail-${Date.now()}.jpg`, { type: 'image/jpeg' });
    return { dataUrl, file };
  };

  const onShutter = () => {
    const grabbed = grabFrame();
    if (grabbed) setCaptured(grabbed);
    else         setCaptured({ dataUrl: null, file: makeDetailPlaceholderFile(note.trim()) });
  };

  return (
    <div style={{ position: 'absolute', inset: 0, zIndex: 30, background: 'rgba(11,12,8,.5)', backdropFilter: 'blur(3px)', display: 'flex', flexDirection: 'column', justifyContent: 'flex-end' }}>
      <div onClick={(e) => e.stopPropagation()} className="fadein" style={{ background: 'var(--paper)', borderRadius: '26px 26px 0 0', padding: 22, color: 'var(--ink)' }}>
        <div style={{ width: 38, height: 4, borderRadius: 999, background: 'var(--hairline)', margin: '0 auto 16px' }} />
        <h3 className="title" style={{ fontSize: 21 }}>Add a special detail</h3>

        {/* capture area: live video while aiming, frozen frame after shutter.
            Same atelier-warm filter as the main capture screen, display-only,
            uploaded bytes stay raw. */}
        <div style={{ marginTop: 14, borderRadius: 16, overflow: 'hidden', position: 'relative', height: 220, background: '#14160f' }}>
          <video ref={videoRef} autoPlay playsInline muted
            style={{
              position: 'absolute', inset: 0, width: '100%', height: '100%',
              objectFit: 'cover',
              opacity: !captured && cameraReady ? 1 : 0,
              transition: 'opacity .2s',
              filter: 'grayscale(1) blur(5px) contrast(1.25) brightness(1.08)',
            }} />
          {captured && captured.dataUrl && (
            <img src={captured.dataUrl} alt={note || 'close-up'}
              style={{ position: 'absolute', inset: 0, width: '100%', height: '100%', objectFit: 'cover',
                       filter: 'sepia(0.35) saturate(0.7) brightness(1.05) contrast(0.92) blur(1px)' }} />
          )}
          {!captured && !cameraReady && !cameraError && (
            <div style={{ position: 'absolute', inset: 0, display: 'flex', alignItems: 'center', justifyContent: 'center', color: 'var(--on-dark-mute)', fontSize: 13 }}>
              Opening camera…
            </div>
          )}
          {!captured && cameraError === 'permission-denied' && (
            <div style={{ position: 'absolute', inset: 0, display: 'flex', alignItems: 'center', justifyContent: 'center', padding: 18, textAlign: 'center', color: 'var(--rose)', fontSize: 13, lineHeight: 1.5 }}>
              We need camera access. Allow it in your phone settings, then come back here.
            </div>
          )}
          {captured && (
            <button onClick={() => setCaptured(false)} style={{ position: 'absolute', top: 10, right: 10, background: 'rgba(20,22,15,.7)', color: 'var(--on-dark)', border: 'none', borderRadius: 999, padding: '7px 12px', fontFamily: 'var(--sans)', fontWeight: 600, fontSize: 12.5, cursor: 'pointer', display: 'inline-flex', alignItems: 'center', gap: 6 }}>
              <IcRetake size={14} /> Retake
            </button>
          )}
        </div>
        {!captured && (
          <button className="btn btn--accent" style={{ marginTop: 12, opacity: cameraReady ? 1 : .55, pointerEvents: cameraReady ? 'auto' : 'none' }} onClick={onShutter}>
            <IcCamera size={18} /> Take close-up photo
          </button>
        )}

        {/* note */}
        <div style={{ marginTop: 16 }}>
          <label style={{ fontSize: 12.5, fontWeight: 700, color: 'var(--ink-soft)' }}>What is it? <span style={{ color: 'var(--ink-mute)', fontWeight: 500 }}>(a note for the studio)</span></label>
          <input value={note} onChange={(e) => setNote(e.target.value)} placeholder="e.g. wedding ring, left hand"
            style={{ width: '100%', marginTop: 8, padding: '13px 14px', borderRadius: 12, border: '1.5px solid var(--hairline)', background: 'var(--paper-2)', fontFamily: 'var(--sans)', fontSize: 15, color: 'var(--ink)', outline: 'none', boxSizing: 'border-box' }} />
          <div style={{ display: 'flex', flexWrap: 'wrap', gap: 8, marginTop: 10 }}>
            {DETAIL_CHIPS.map((c) => (
              <button key={c} onClick={() => setNote(c)} style={{
                border: '1px solid var(--hairline)', background: note === c ? 'var(--ink)' : 'var(--paper-2)', color: note === c ? 'var(--paper)' : 'var(--ink-soft)',
                borderRadius: 999, padding: '7px 13px', fontFamily: 'var(--sans)', fontWeight: 600, fontSize: 12.5, cursor: 'pointer', whiteSpace: 'nowrap',
              }}>{c}</button>
            ))}
          </div>
        </div>

        <div style={{ display: 'flex', gap: 10, marginTop: 18 }}>
          <button className="btn btn--ghost" style={{ flex: 1 }} onClick={onCancel}>Cancel</button>
          <button className="btn btn--primary" style={{ flex: 1.4, opacity: captured ? 1 : .4, pointerEvents: captured ? 'auto' : 'none' }}
            onClick={() => onAdd(note.trim(), (captured && captured.file) || makeDetailPlaceholderFile(note.trim()))}>
            <IcCheck size={18} /> Add detail
          </button>
        </div>
      </div>
    </div>
  );
}

Object.assign(window, { DetailsScreen, AddDetailSheet });
