/* Studio 76 — Try It On. Upload your photo + a piece → we place the real piece on you,
   true to size, with a palette read from your skin. Talks only to blueprint.php. */

const PLACES = [
  { k: 'neck',  label: 'Neck' },
  { k: 'ears',  label: 'Ears' },
  { k: 'hand',  label: 'Hand' },
  { k: 'wrist', label: 'Wrist' },
];

function placeFor(type) {
  const t = (type || '').toLowerCase();
  if (/ring/.test(t)) return 'hand';
  if (/ear/.test(t)) return 'ears';
  if (/bracelet|bangle|cuff|anklet/.test(t)) return 'wrist';
  return 'neck'; // necklace / pendant / choker / default
}

async function api(action, payload) {
  const r = await fetch('blueprint.php', { method: 'POST', headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(Object.assign({ action }, payload)) });
  let j = {}; try { j = await r.json(); } catch (e) {}
  if (!r.ok || j.error) throw new Error(j.error || ('Something went wrong (' + r.status + ')'));
  return j;
}

function downscale(file, max) {
  return new Promise((res, rej) => {
    const fr = new FileReader();
    fr.onerror = () => rej(new Error('read'));
    fr.onload = () => {
      const img = new Image();
      img.onload = () => {
        const s = Math.min(1, max / Math.max(img.width, img.height));
        const w = Math.round(img.width * s), h = Math.round(img.height * s);
        const c = document.createElement('canvas'); c.width = w; c.height = h;
        c.getContext('2d').drawImage(img, 0, 0, w, h);
        res(c.toDataURL('image/jpeg', 0.86));
      };
      img.onerror = () => rej(new Error('img'));
      img.src = fr.result;
    };
    fr.readAsDataURL(file);
  });
}

const isData = x => typeof x === 'string' && x.slice(0, 5) === 'data:';
const absUrl = u => { try { return new URL(u, location.href).href; } catch (e) { return u; } };

function Drop({ label, hint, onFile }) {
  const ref = React.useRef(null);
  const [over, setOver] = React.useState(false);
  return (
    <div className={'ti-drop' + (over ? ' over' : '')}
      onClick={() => ref.current && ref.current.click()}
      onDragOver={e => { e.preventDefault(); setOver(true); }}
      onDragLeave={() => setOver(false)}
      onDrop={e => { e.preventDefault(); setOver(false); onFile(e.dataTransfer.files[0]); }}>
      <div className="ti-drop-icon">
        <svg viewBox="0 0 24 24" width="30" height="30" fill="none"><path d="M12 16V5m0 0L8 9m4-4 4 4" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"/><path d="M4 15v3a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-3" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round"/></svg>
      </div>
      <p className="ti-drop-t">{label} <span>browse</span></p>
      <p className="ti-drop-s">{hint}</p>
      <input ref={ref} type="file" accept="image/*" hidden onChange={e => onFile(e.target.files[0])} />
    </div>
  );
}

function TryOn() {
  const [selfie, setSelfie] = React.useState(null);     // dataUrl
  const [piece, setPiece]   = React.useState(null);     // dataUrl OR absolute url
  const [spec, setSpec]     = React.useState(null);
  const [place, setPlace]   = React.useState('neck');
  const [adv, setAdv]       = React.useState(null);      // null | 'loading' | {undertone, metals, stones, note}
  const [out, setOut]       = React.useState('idle');    // idle | loading | dataUrl
  const [cap, setCap]       = React.useState(null);      // null | 'loading' | {caption, hashtags}
  const [copied, setCopied] = React.useState(false);
  const [pieceUrlText, setPieceUrlText] = React.useState('');
  const [err, setErr]       = React.useState('');

  // Arrive from a saved set (?set=), a direct image (?img=), or a piece handed off from the Stylist
  React.useEffect(() => {
    let handed = null;
    try { handed = sessionStorage.getItem('s76_piece'); if (handed) sessionStorage.removeItem('s76_piece'); } catch (e) {}
    if (handed) {
      setPiece(handed); setSpec(null);
      api('analyze', { image: handed }).then(a => { setSpec(a.spec); setPlace(placeFor(a.spec && a.spec.piece_type)); }).catch(() => {});
      return;
    }
    const q = new URLSearchParams(location.search);
    const setId = (q.get('set') || '').replace(/[^a-f0-9]/g, '');
    const img = q.get('img');
    if (/^[a-f0-9]{20}$/.test(setId)) {
      const base = 'sets/' + setId + '/';
      fetch(base + 'index.json').then(r => r.json()).then(m => {
        const cover = m.original ? base + m.original : (m.items && m.items[0] ? base + m.items[0].file : '');
        if (cover) setPiece(absUrl(cover));
        if (m.spec) { setSpec(m.spec); setPlace(placeFor(m.spec.piece_type)); }
      }).catch(() => {});
    } else if (img) {
      bringPiece(img);
    }
  }, []);

  async function onSelfie(file) {
    if (!file || !/^image\//.test(file.type)) { setErr('Please choose an image file.'); return; }
    setErr(''); setAdv('loading');
    try {
      const d = await downscale(file, 1280);
      setSelfie(d);
      try { const a = await api('skintone', { selfie: d }); setAdv(a); } catch (e) { setAdv(null); }
    } catch (e) { setErr('Could not read that photo.'); setAdv(null); }
  }

  async function onPieceFile(file) {
    if (!file || !/^image\//.test(file.type)) { setErr('Please choose an image file.'); return; }
    setErr('');
    try {
      const d = await downscale(file, 1280);
      setPiece(d); setSpec(null);
      try { const a = await api('analyze', { image: d }); setSpec(a.spec); setPlace(placeFor(a.spec && a.spec.piece_type)); } catch (e) {}
    } catch (e) { setErr('Could not read that image.'); }
  }

  async function bringPiece(url) {
    url = (url || '').trim();
    if (!/^https?:\/\//i.test(url)) { setErr('Paste a valid image URL.'); return; }
    setErr(''); setPiece(url); setSpec(null); setPieceUrlText('');
    try { const a = await api('analyze', { imageUrl: url }); setSpec(a.spec); setPlace(placeFor(a.spec && a.spec.piece_type)); } catch (e) {}
  }

  function tryOn() {
    if (!selfie || !piece || out === 'loading') return;
    setErr(''); setOut('loading'); setCap(null); setCopied(false);
    const payload = { selfie, place, spec: spec || {} };
    if (isData(piece)) payload.piece = piece; else payload.pieceUrl = absUrl(piece);
    api('tryon', payload)
      .then(j => setOut(j.dataUrl))
      .catch(e => { setOut('idle'); setErr(e.message || 'Try-on failed — try a clearer, front-facing photo.'); });
  }

  function loadCaption() {
    setCap('loading'); setCopied(false);
    api('caption', { spec: spec || {} }).then(j => setCap(j)).catch(e => { setCap(null); setErr(e.message || 'Could not write a caption.'); });
  }
  function capFull(c) { return (c.caption || '') + '\n\n' + (c.hashtags || []).map(h => '#' + String(h).replace(/^#/, '').replace(/\s+/g, '')).join(' '); }
  function copyCap(c) { const t = capFull(c); const done = () => { setCopied(true); setTimeout(() => setCopied(false), 1800); };
    try { navigator.clipboard.writeText(t).then(done, done); } catch (e) { done(); } }

  const ready = selfie && piece;

  return (
    <main className="ti">
      <header className="ti-head">
        <a className="ti-logo" href="/">Studio<span> 76</span></a>
        <span className="ti-headlinks"><a href="/blueprint.html">Bench</a><a href="/imaginarium.html">Imaginarium</a><a href="/stylist.html">Stylist</a><span className="ti-eyebrow">✦ Try It On</span></span>
      </header>

      <section className="ti-hero">
        <h1 className="ti-title">See it <span className="ti-italic">on you.</span></h1>
        <p className="ti-sub">Add a clear, front-facing photo and the piece you love — we place the real piece on you,
          true to its actual size, and read a <span className="ti-italic">palette</span> made for your skin.</p>
      </section>

      {err && <p className="ti-err">{err}</p>}

      <div className="ti-stage">
        {/* left: inputs */}
        <div className="ti-col">
          <div className="ti-card">
            <span className="ti-k">1 · Your photo</span>
            {selfie
              ? <div className="ti-thumb"><img src={selfie} alt="You" /><button className="ti-redo" onClick={() => { setSelfie(null); setAdv(null); setOut('idle'); }}>Change</button></div>
              : <Drop label="Drop a portrait, or" hint="A front-facing, well-lit photo works best." onFile={onSelfie} />}
          </div>

          {adv === 'loading' && <div className="ti-adv"><span className="ti-spin sm" style={{display:'inline-block',verticalAlign:'middle',marginRight:8}}></span>Reading your palette…</div>}
          {adv && adv !== 'loading' && (
            <div className="ti-adv">
              <b>Your palette · {adv.undertone} undertone</b>
              <div className="ti-adv-row">Metals that flatter you: {(adv.metals || []).map(m => <span key={m}>{m}</span>)}</div>
              <div className="ti-adv-row">Stones to love: {(adv.stones || []).map(s => <span key={s}>{s}</span>)}</div>
              {adv.note && <p className="ti-adv-note">“{adv.note}”</p>}
            </div>
          )}

          <div className="ti-card">
            <span className="ti-k">2 · The piece</span>
            {piece
              ? <div className="ti-thumb piece"><img src={piece} alt="Piece" /><button className="ti-redo" onClick={() => { setPiece(null); setSpec(null); }}>Change</button></div>
              : <React.Fragment>
                  <Drop label="Drop the jewellery photo, or" hint="A clean shot of the piece on its own." onFile={onPieceFile} />
                  <div className="ti-paste">
                    <input className="ti-input" value={pieceUrlText} placeholder="…or paste an image URL"
                      onChange={e => setPieceUrlText(e.target.value)} onKeyDown={e => { if (e.key === 'Enter') bringPiece(pieceUrlText); }} />
                    <button className="ti-chip" disabled={!pieceUrlText.trim()} onClick={() => bringPiece(pieceUrlText)}>Bring it in</button>
                  </div>
                </React.Fragment>}
          </div>

          <div className="ti-card">
            <span className="ti-k">3 · Where to wear it</span>
            <div className="ti-chips">
              {PLACES.map(p => <button key={p.k} className={'ti-chip' + (place === p.k ? ' on' : '')} onClick={() => setPlace(p.k)}>{p.label}</button>)}
            </div>
          </div>

          <button className="ti-go" disabled={!ready || out === 'loading'} onClick={tryOn}>
            {out === 'loading' ? 'Placing it on you…' : '✨ Try it on me'}
          </button>
        </div>

        {/* right: result */}
        <div className="ti-col">
          <div className="ti-result">
            {out === 'loading'
              ? <div className="ti-load"><span className="ti-spin"></span><span>Placing the piece on you…</span></div>
              : isData(out)
                ? <img src={out} alt="You wearing the piece" />
                : <div className="ph">{ready ? 'Tap “Try it on me” to see it worn.' : 'Add your photo and a piece to begin.'}</div>}
          </div>

          {isData(out) && (
            <React.Fragment>
              <div className="ti-resfoot">
                <a className="ti-btn" href={out} download="studio76-tryon.png">Download</a>
                <button className="ti-btn ghost" onClick={tryOn}>Regenerate</button>
                {!cap && <button className="ti-link" onClick={loadCaption}>{cap === 'loading' ? 'Writing…' : 'Write an Instagram caption'}</button>}
              </div>
              {cap === 'loading' && <p className="ti-adv-note"><span className="ti-spin sm" style={{display:'inline-block',verticalAlign:'middle',marginRight:8}}></span>Writing a caption…</p>}
              {cap && cap !== 'loading' && (
                <div className="ti-card">
                  <span className="ti-k">✦ Post to Instagram</span>
                  <textarea className="ti-ig-text" readOnly value={capFull(cap)} onClick={e => e.target.select()} />
                  <div className="ti-resfoot" style={{marginTop:0}}>
                    <button className="ti-btn" onClick={() => copyCap(cap)}>{copied ? 'Copied ✓' : 'Copy caption'}</button>
                    <a className="ti-btn ghost" href={out} download="studio76-tryon.png">Download image</a>
                    <button className="ti-link" onClick={loadCaption}>rewrite</button>
                  </div>
                </div>
              )}
            </React.Fragment>
          )}
        </div>
      </div>
    </main>
  );
}

ReactDOM.createRoot(document.getElementById('root')).render(<TryOn />);
