/* ============================================================
   Composants UI — État des lieux Verlaine
   ============================================================ */
const { useState, useRef, useEffect, useCallback } = React;

/* ---------- Icônes (Feather/Lucide style) ---------- */
const IC = {
  back:   <path d="M19 12H5M12 19l-7-7 7-7"/>,
  arrow:  <path d="M5 12h14M13 6l6 6-6 6"/>,
  chevR:  <path d="M9 6l6 6-6 6"/>,
  camera: <><path d="M14.5 4l1.5 2.5h3.5A1.5 1.5 0 0 1 21 8v10.5A1.5 1.5 0 0 1 19.5 20h-15A1.5 1.5 0 0 1 3 18.5V8a1.5 1.5 0 0 1 1.5-1.5H8L9.5 4z"/><circle cx="12" cy="12.5" r="3.5"/></>,
  plus:   <path d="M12 5v14M5 12h14"/>,
  minus:  <path d="M5 12h14"/>,
  x:      <path d="M18 6 6 18M6 6l12 12"/>,
  check:  <path d="M20 6 9 17l-5-5"/>,
  skip:   <path d="M5 4l10 8-10 8zM19 5v14"/>,
  user:   <><circle cx="12" cy="8" r="4"/><path d="M4 21v-1a6 6 0 0 1 6-6h4a6 6 0 0 1 6 6v1"/></>,
  pin:    <><path d="M20 10c0 6-8 12-8 12s-8-6-8-12a8 8 0 0 1 16 0z"/><circle cx="12" cy="10" r="2.8"/></>,
  phone:  <path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72c.13.96.37 1.9.7 2.81a2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45c.91.33 1.85.57 2.81.7A2 2 0 0 1 22 16.92z"/>,
  mail:   <><rect x="3" y="5" width="18" height="14" rx="2"/><path d="M4 7l8 6 8-6"/></>,
  cal:    <><rect x="3" y="5" width="18" height="16" rx="2"/><path d="M16 3v4M8 3v4M3 10h18"/></>,
  box:    <><path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"/><path d="M3.3 7 12 12l8.7-5M12 22V12"/></>,
  window: <><rect x="4" y="3" width="16" height="18" rx="1.5"/><path d="M12 3v18M4 12h16"/></>,
  facade: <><path d="M3 21h18"/><path d="M5 21V6l7-3 7 3v15"/><path d="M9 9h.01M15 9h.01M9 13h.01M15 13h.01M9 17h.01M15 17h.01"/></>,
  door:   <><path d="M3 21h18"/><path d="M6 21V4a1 1 0 0 1 1-1h10a1 1 0 0 1 1 1v17"/><circle cx="14.5" cy="12" r="1"/></>,
  plug:   <><path d="M9 2v5M15 2v5"/><path d="M6 7h12v3a6 6 0 0 1-12 0z"/><path d="M12 16v6"/></>,
  tree:   <><path d="M12 22v-6"/><path d="M9.5 8.5a3 3 0 1 1 5.4-1.8A3 3 0 1 1 17 12a3 3 0 1 1-3.2 4 3.5 3.5 0 0 1-3.6 0A3 3 0 1 1 7 12a3 3 0 1 1 2.5-3.5z"/></>,
  card:   <><rect x="2" y="5" width="20" height="14" rx="2.5"/><path d="M2 10h20M6 15h4"/></>,
  file:   <><path d="M14 3H7a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V8z"/><path d="M14 3v5h5"/><path d="M9 13h6M9 17h4"/></>,
  trash:  <><path d="M3 6h18M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/><path d="M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6"/></>,
  alert:  <><path d="M10.3 3.9 1.8 18a2 2 0 0 0 1.7 3h17a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0z"/><path d="M12 9v4M12 17h.01"/></>,
  shield: <><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/><path d="M9 11.5l2 2 4-4"/></>,
  clipboard: <><rect x="8" y="3" width="8" height="4" rx="1.2"/><path d="M9 5H7a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2h-2"/><path d="M9 13l2 2 4-4"/></>,
  homeCheck: <><path d="M3 10.5 12 3l9 7.5"/><path d="M5 9.8V20a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V9.8"/><path d="M9.3 14l2 2 3.6-3.6"/></>,
  edit:   <><path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/><path d="M18.5 2.5a2.12 2.12 0 0 1 3 3L12 15l-4 1 1-4z"/></>,
  globe:  <><circle cx="12" cy="12" r="10"/><path d="M2 12h20"/><path d="M12 2a15 15 0 0 1 0 20 15 15 0 0 1 0-20z"/></>,
  wa:     <path fill="currentColor" stroke="none" d="M17.5 14.4c-.3-.15-1.7-.84-2-.93-.26-.1-.46-.15-.65.15-.2.29-.74.92-.9 1.11-.17.2-.34.22-.63.07-.3-.15-1.24-.46-2.36-1.46-.87-.78-1.46-1.74-1.63-2.03-.17-.3 0-.45.13-.6.13-.13.3-.34.44-.5.15-.18.2-.3.3-.5.1-.2.05-.37-.02-.52-.08-.15-.65-1.58-.9-2.16-.24-.56-.48-.48-.65-.49h-.56c-.2 0-.5.07-.77.36-.26.3-1 1-1 2.42s1.03 2.81 1.17 3.01c.14.2 2.02 3.08 4.9 4.32.68.3 1.22.47 1.63.6.69.22 1.31.19 1.8.11.55-.08 1.7-.69 1.94-1.36.24-.67.24-1.24.17-1.36-.07-.12-.27-.2-.56-.34zM12 2a10 10 0 0 0-8.6 15.06L2 22l5.06-1.33A10 10 0 1 0 12 2z"/>,
};
function Glyph({d, w=22, sw=2}){
  return (
    <svg viewBox="0 0 24 24" width={w} height={w} fill="none"
      stroke="currentColor" strokeWidth={sw} strokeLinecap="round" strokeLinejoin="round">
      {typeof d==='string' ? <path d={d}/> : d}
    </svg>
  );
}

/* ---------- Action bar ---------- */
function ActionBar({ onBack, onNext, nextLabel, nextIcon=true, stacked, children, nextDisabled }){
  return (
    <div className={'actionbar'+(stacked?' stacked':'')}>
      {children}
      {!children && <>
        {onBack && <button className="btn btn-ghost btn-back" onClick={onBack} aria-label="Précédent"><Glyph d={IC.back} w={20}/></button>}
        {onNext && <button className="btn btn-primary" onClick={onNext} disabled={nextDisabled}>
          <span>{nextLabel}</span>{nextIcon && <Glyph d={IC.arrow} w={20}/>}
        </button>}
      </>}
    </div>
  );
}

/* ---------- App bar ---------- */
function AppBar({ kicker, title, lang, onBack, progress }){
  return (
    <div>
      <div className="appbar">
        {onBack
          ? <button className="appbar-back" onClick={onBack} aria-label="Retour"><Glyph d={IC.back} w={20}/></button>
          : <img className="appbar-logo" src="assets/logo-verlaine-blanc.png" alt="Verlaine"/>}
        <div className="appbar-titles">
          {kicker && <div className="appbar-kicker">{kicker}</div>}
          {title && <div className="appbar-title">{title}</div>}
        </div>
        {lang && <span className="appbar-lang">{lang.toUpperCase()}</span>}
      </div>
      {typeof progress==='number' &&
        <div className="progress"><div className="progress-fill" style={{width:(progress*100)+'%'}}/></div>}
    </div>
  );
}

/* ---------- Photo helpers ---------- */
function _pid(){ return 'p'+Date.now()+Math.random().toString(36).slice(2,7); }
/* Normalise une photo : applique l'orientation EXIF (redresse les photos téléphone),
   limite la taille, ré-encode en JPEG. Résultat = image droite partout (app + PDF). */
async function _normalizePhoto(f){
  const MAX = 1600, Q = 0.85;
  try{
    let bmp;
    try{ bmp = await createImageBitmap(f, { imageOrientation:'from-image' }); }
    catch(_){ bmp = await createImageBitmap(f); }
    let w = bmp.width, h = bmp.height;
    if(Math.max(w,h) > MAX){ const r = MAX/Math.max(w,h); w = Math.round(w*r); h = Math.round(h*r); }
    const cv = document.createElement('canvas'); cv.width = w; cv.height = h;
    cv.getContext('2d').drawImage(bmp, 0, 0, w, h);
    if(bmp.close) bmp.close();
    return { id:_pid(), url: cv.toDataURL('image/jpeg', Q) };
  }catch(e){
    return await new Promise(res=>{ const r=new FileReader(); r.onload=ev=>res({ id:_pid(), url:ev.target.result }); r.readAsDataURL(f); });
  }
}
function filesToPhotos(fileList, cb){
  const files = Array.from(fileList||[]);
  if(!files.length) return;
  Promise.all(files.map(_normalizePhoto)).then(cb);
}

/* ---------- Photo grid (multi) ---------- */
function PhotoGrid({ photos=[], onChange, label, lang }){
  const inputRef = useRef(null);
  const add = e=>{ filesToPhotos(e.target.files, np=> onChange([...photos, ...np])); e.target.value=''; };
  const remove = id=> onChange(photos.filter(p=>p.id!==id));
  const cnt = photos.length;
  const word = cnt===0 ? t(lang,'photo.count_zero') : cnt===1 ? t(lang,'photo.count_one') : t(lang,'photo.count_other');
  return (
    <div className="photo-block">
      <input ref={inputRef} type="file" accept="image/*" capture="environment" multiple style={{display:'none'}} onChange={add}/>
      <div className="photogrid">
        <button className="photo-add" onClick={()=>inputRef.current.click()}>
          <Glyph d={IC.camera} w={26}/>
          <span>{label || t(lang,'photo.add')}</span>
        </button>
        {photos.map(p=>(
          <div className="photo-thumb" key={p.id}>
            <img src={p.url} alt=""/>
            <button className="rm" onClick={()=>remove(p.id)} aria-label="Supprimer"><Glyph d={IC.x} w={15}/></button>
          </div>
        ))}
      </div>
      <div className={'photo-count'+(cnt>0?' ok':'')}>
        {cnt>0 && <Glyph d={IC.check} w={15}/>}
        {cnt===0 ? word : (cnt+' '+word)}
      </div>
    </div>
  );
}

/* ---------- Single slot (PV page, chèque) ---------- */
function PhotoSlot({ photo, onChange, label, tag }){
  const inputRef = useRef(null);
  const add = e=>{ filesToPhotos(e.target.files, np=> onChange(np[0])); e.target.value=''; };
  return (
    <div className={'slot'+(photo?' filled':'')}>
      <input ref={inputRef} type="file" accept="image/*" capture="environment" style={{display:'none'}} onChange={add}/>
      {photo ? <>
        {tag && <span className="slot-tag">{tag}</span>}
        <img src={photo.url} alt=""/>
        <button className="slot-rm" onClick={()=>onChange(null)} aria-label="Supprimer"><Glyph d={IC.trash} w={16}/></button>
      </> : (
        <button onClick={()=>inputRef.current.click()} style={{display:'flex',flexDirection:'column',alignItems:'center',gap:8,width:'100%',height:'100%',minHeight:128,justifyContent:'center'}}>
          <Glyph d={IC.camera} w={30}/>
          <span>{label}</span>
        </button>
      )}
    </div>
  );
}

/* ---------- État block (bon / mauvais + défauts) ---------- */
const DEFAUTS = ['rayure','casse','autre'];
function EtatBlock({ data={}, onChange, lang }){
  const etat = data.etat || 'bon';
  const defauts = data.defauts || [];
  const photosByDefaut = data.photosByDefaut || {};
  const set = patch => onChange({ ...data, ...patch });
  const toggleDef = d => set({ defauts: defauts.includes(d) ? defauts.filter(x=>x!==d) : [...defauts, d] });
  return (
    <div className="photo-block">
      <p className="section-label">{t(lang,'etat.label')}</p>
      <div className="seg">
        <button className={etat==='bon'?'on-good':''} onClick={()=>set({etat:'bon'})}>
          <Glyph d={IC.check} w={18}/>{t(lang,'etat.good')}
        </button>
        <button className={etat==='mauvais'?'on-bad':''} onClick={()=>set({etat:'mauvais'})}>
          <Glyph d={IC.alert} w={18}/>{t(lang,'etat.bad')}
        </button>
      </div>
      {etat==='mauvais' &&
        <div className="req-box fade-in">
          <div className="rb-title"><Glyph d={IC.alert} w={17}/>{t(lang,'etat.defauts')}</div>
          <div className="chips" style={{marginBottom:16}}>
            {DEFAUTS.map(d=>(
              <button key={d} className={'chip'+(defauts.includes(d)?' on':'')} onClick={()=>toggleDef(d)}>
                {t(lang,'etat.'+d)}
              </button>
            ))}
          </div>
          {defauts.length>0 &&
            <div className="fade-in">
              <p className="section-label" style={{marginBottom:4}}>{t(lang,'etat.defautphoto.precise')} <span style={{color:'var(--red)'}}>*</span></p>
              {defauts.map(def=>(
                <div key={def} style={{marginTop:12}}>
                  <p className="section-label" style={{marginBottom:8,fontWeight:800,color:'var(--ink-2)',textTransform:'none',letterSpacing:0}}>
                    <Glyph d={IC.camera} w={15}/> {t(lang,'etat.'+def)}
                  </p>
                  <PhotoGrid photos={photosByDefaut[def]||[]} onChange={pd=>set({photosByDefaut:{...photosByDefaut,[def]:pd}})} lang={lang}/>
                </div>
              ))}
            </div>}
        </div>}
    </div>
  );
}

/* ---------- Counter ---------- */
function Counter({ value=0, onChange, min=0 }){
  return (
    <div className="counter">
      <button onClick={()=>onChange(Math.max(min, value-1))} disabled={value<=min}><Glyph d={IC.minus} w={20}/></button>
      <span className="cval">{value}</span>
      <button onClick={()=>onChange(value+1)}><Glyph d={IC.plus} w={20}/></button>
    </div>
  );
}

/* ---------- Signature pad ---------- */
function SignaturePad({ onChange, clearLabel='Effacer' }){
  const cv = useRef(null);
  const drawing = useRef(false);
  const last = useRef(null);
  const dirty = useRef(false);

  useEffect(()=>{
    const c = cv.current;
    const ratio = window.devicePixelRatio||1;
    const rect = c.getBoundingClientRect();
    c.width = rect.width*ratio; c.height = rect.height*ratio;
    const ctx = c.getContext('2d');
    ctx.scale(ratio,ratio);
    ctx.lineWidth=2.4; ctx.lineCap='round'; ctx.lineJoin='round'; ctx.strokeStyle='#0d1c4d';
  },[]);

  const pos = e=>{
    const r = cv.current.getBoundingClientRect();
    const pt = e.touches? e.touches[0] : e;
    return { x:pt.clientX-r.left, y:pt.clientY-r.top };
  };
  const start = e=>{ e.preventDefault(); drawing.current=true; last.current=pos(e); };
  const move = e=>{
    if(!drawing.current) return; e.preventDefault();
    const ctx = cv.current.getContext('2d'); const p = pos(e);
    ctx.beginPath(); ctx.moveTo(last.current.x,last.current.y); ctx.lineTo(p.x,p.y); ctx.stroke();
    last.current=p; if(!dirty.current){dirty.current=true;}
  };
  const end = ()=>{ if(drawing.current && dirty.current){ onChange(cv.current.toDataURL('image/png')); } drawing.current=false; };
  const clear = ()=>{
    const c=cv.current; const ctx=c.getContext('2d');
    ctx.clearRect(0,0,c.width,c.height); dirty.current=false; onChange(null);
  };
  return (
    <div className="sigpad-wrap">
      <canvas ref={cv} className="sigpad"
        onMouseDown={start} onMouseMove={move} onMouseUp={end} onMouseLeave={end}
        onTouchStart={start} onTouchMove={move} onTouchEnd={end}/>
      <div className="sigpad-bar">
        <span className="sb-hint"></span>
        <button className="sigpad-clear" onClick={clear}><Glyph d={IC.x} w={15}/><span>{clearLabel}</span></button>
      </div>
    </div>
  );
}

/* ---------- Toast ---------- */
function Toast({ msg }){
  if(!msg) return null;
  return <div className="toast"><Glyph d={IC.alert} w={17}/>{msg}</div>;
}

Object.assign(window, {
  IC, Glyph, ActionBar, AppBar, PhotoGrid, PhotoSlot, EtatBlock, Counter, SignaturePad, Toast, DEFAUTS, filesToPhotos
});
