/* ============================================================
   CODEX — the shared Pokédex-style reveal used on BOTH the Main
   screen and player handsets. Portrait animates on the left over a
   bed of moving light; the name, kind and description sit on the
   right. One component, two sizes (variant: 'main' | 'player').
   ============================================================ */

const KIND_ACCENT = {
  npc:       '#52b07a',
  enemy:     '#d9663f',
  boss:      '#c0392b',
  knowledge: '#c79a3a',
};
window.KIND_ACCENT = KIND_ACCENT;

/* Fullscreen image viewer with real direct-manipulation:
   pinch-to-zoom (touch), wheel-zoom (desktop), drag-to-pan, double-tap to
   toggle zoom, +/−/Fit buttons. Fits the screen by default and clamps panning
   so the image can't be flung off-screen. Same API: { src, name, onClose }. */
function ImageZoom({ src, name, onClose }){
  const MIN = 1, MAX = 6;
  const wrapRef = React.useRef(null);
  const imgRef  = React.useRef(null);
  const [pct, setPct] = React.useState(100);
  const tf       = React.useRef({ s:1, x:0, y:0 });   // live transform
  const pointers = React.useRef(new Map());
  const pinch    = React.useRef(null);
  const lastTap  = React.useRef(0);
  const moved    = React.useRef(false);
  const D = (a,b)=> Math.hypot(a.x-b.x, a.y-b.y);

  const apply = (animate)=>{
    const img = imgRef.current; if(!img) return;
    img.style.transition = animate ? 'transform .16s ease' : 'none';
    img.style.transform  = `translate(${tf.current.x}px,${tf.current.y}px) scale(${tf.current.s})`;
  };
  const clampPan = ()=>{
    const img = imgRef.current; if(!img) return;
    const s = tf.current.s;
    const ox = Math.max(0, (img.offsetWidth  * s - window.innerWidth ) / 2);
    const oy = Math.max(0, (img.offsetHeight * s - window.innerHeight) / 2);
    tf.current.x = Math.max(-ox, Math.min(ox, tf.current.x));
    tf.current.y = Math.max(-oy, Math.min(oy, tf.current.y));
  };
  // zoom to `ns`, keeping the content under the focal point (fx,fy) fixed
  const zoomTo = (ns, fx, fy, animate)=>{
    const s0 = tf.current.s;
    const s1 = Math.max(MIN, Math.min(MAX, ns));
    if(Math.abs(s1-s0) < 0.001) return;
    const dx = (fx==null?0:fx-window.innerWidth/2), dy = (fy==null?0:fy-window.innerHeight/2);
    const k = s1/s0;
    tf.current.x = dx - (dx - tf.current.x)*k;
    tf.current.y = dy - (dy - tf.current.y)*k;
    tf.current.s = s1;
    if(s1<=MIN){ tf.current.x=0; tf.current.y=0; }
    clampPan(); apply(animate); setPct(Math.round(s1*100));
  };

  const onDown = (e)=>{
    pointers.current.set(e.pointerId, { x:e.clientX, y:e.clientY });
    moved.current = false;
    try{ wrapRef.current.setPointerCapture(e.pointerId); }catch(_){}
    if(pointers.current.size===2){
      const p=[...pointers.current.values()];
      pinch.current = { dist:D(p[0],p[1]), s:tf.current.s };
    }
  };
  const onMove = (e)=>{
    if(!pointers.current.has(e.pointerId)) return;
    const prev = pointers.current.get(e.pointerId);
    pointers.current.set(e.pointerId, { x:e.clientX, y:e.clientY });
    const p=[...pointers.current.values()];
    if(p.length===2 && pinch.current){
      const d=D(p[0],p[1]), cx=(p[0].x+p[1].x)/2, cy=(p[0].y+p[1].y)/2;
      zoomTo(pinch.current.s*(d/pinch.current.dist), cx, cy, false); moved.current=true;
    } else if(p.length===1 && tf.current.s>1){
      tf.current.x += e.clientX-prev.x; tf.current.y += e.clientY-prev.y;
      clampPan(); apply(false); moved.current=true;
    } else if(Math.abs(e.clientX-prev.x)+Math.abs(e.clientY-prev.y) > 4){ moved.current=true; }
  };
  const onUp = (e)=>{
    pointers.current.delete(e.pointerId);
    if(pointers.current.size<2) pinch.current=null;
    if(pointers.current.size===0 && !moved.current){
      const now=Date.now();
      if(now-lastTap.current < 300){ lastTap.current=0; tf.current.s>1 ? zoomTo(MIN,null,null,true) : zoomTo(2.6, e.clientX, e.clientY, true); }
      else lastTap.current = now;
    }
  };
  const step = (d)=> zoomTo(tf.current.s+d, window.innerWidth/2, window.innerHeight/2, true);
  const fit  = ()=>{ tf.current={s:1,x:0,y:0}; apply(true); setPct(100); };
  const onBackdrop = ()=>{ if(!moved.current && tf.current.s<=MIN) onClose(); };

  React.useEffect(()=>{
    const el = wrapRef.current; if(!el) return;
    const onWheel=(e)=>{ e.preventDefault(); zoomTo(tf.current.s*(e.deltaY<0?1.18:1/1.18), e.clientX, e.clientY, false); };
    const onKey=(e)=>{ if(e.key==='Escape') onClose(); };
    el.addEventListener('wheel', onWheel, {passive:false});
    window.addEventListener('keydown', onKey);
    return ()=>{ el.removeEventListener('wheel', onWheel); window.removeEventListener('keydown', onKey); };
  }, []);

  return (
    <div className="img-zoom" onClick={onBackdrop}>
      <div className="img-zoom-frame" ref={wrapRef}
           onPointerDown={onDown} onPointerMove={onMove} onPointerUp={onUp} onPointerCancel={onUp}
           onClick={e=>e.stopPropagation()}>
        <img ref={imgRef} src={src} alt={name||''} draggable={false}/>
      </div>
      <div className="img-zoom-bar" onClick={e=>e.stopPropagation()}>
        <button className="glass-btn" onClick={()=>step(-0.6)}>−</button>
        <span className="iz-pct">{pct}%</span>
        <button className="glass-btn" onClick={()=>step(0.6)}>+</button>
        <button className="glass-btn" onClick={fit}>Fit</button>
      </div>
      {name && <span className="img-zoom-name">{name}</span>}
      <span className="img-zoom-x glass-btn" onClick={onClose}>✕</span>
    </div>
  );
}
window.ImageZoom = ImageZoom;

function CodexCard({ entry, variant='main', onClose }){
  const [zoom, setZoom] = useState(false);
  if(!entry) return null;
  const accent = KIND_ACCENT[entry.kind] || '#c79a3a';
  const kindLabel = (window.KIND_META && KIND_META[entry.kind]) ? KIND_META[entry.kind].label : (entry.kind||'').toUpperCase();
  const hasImg = !!entry.src;
  const hasDesc = !!(entry.desc && entry.desc.trim());
  const canZoom = hasImg && variant==='player';
  return (
    <div className={`codex-card variant-${variant}`} style={{'--accent':accent}}>
      <div className="codex-aura"></div>
      <div className="codex-rings">
        <span></span><span></span><span></span>
      </div>
      {hasImg ? (
        <div className={`codex-portrait ${canZoom?'zoomable':''}`} onClick={canZoom?()=>setZoom(true):undefined}>
          <div className="codex-portrait-glow"></div>
          <ArtImg className="codex-portrait-img" src={entry.src} alt={entry.name}>
            <div className="codex-portrait-fallback"><Icon name={entry.kind==='knowledge'?'book':'skull'} size={48}/></div>
          </ArtImg>
          {canZoom && <span className="codex-zoom-hint">⤢ tap to enlarge</span>}
        </div>
      ) : (
        <div className="codex-portrait no-img">
          <div className="codex-portrait-fallback"><Icon name={entry.kind==='knowledge'?'book':'skull'} size={48}/></div>
        </div>
      )}
      <div className="codex-body">
        <div className="codex-kind" style={{color:accent}}>{kindLabel}</div>
        <div className="codex-name display">{entry.name}</div>
        <div className="codex-rule" style={{background:accent}}></div>
        {hasDesc
          ? <div className="codex-desc">{entry.desc}</div>
          : <div className="codex-desc muted-desc">No further records.</div>}
      </div>
      {onClose && <button className="codex-x glass-btn" onClick={onClose}>✕</button>}
      {zoom && <ImageZoom src={entry.src} name={entry.name} onClose={()=>setZoom(false)}/>}
    </div>
  );
}
window.CodexCard = CodexCard;

/* ---- Main screen: NPC portrait on the LEFT (no text box) ---- */
function MainNpcLayer({ npc }){
  if(!npc) return null;
  return (
    <div className="main-npc-layer">
      <div className="main-npc-glow"></div>
      <ArtImg className="main-npc-img" src={npc.src} alt={npc.name}>
        <div className="main-npc-fallback"><Icon name="book" size={40}/><span>{npc.name}</span></div>
      </ArtImg>
    </div>
  );
}
window.MainNpcLayer = MainNpcLayer;

/* ---- Main screen: enemy/boss figures across the stage, with count badges ---- */
function MainFiguresLayer({ figures }){
  if(!figures || !figures.length) return null;
  return (
    <div className={`main-figures-row n${figures.length}`}>
      {figures.map(f=>{
        const accent = KIND_ACCENT[f.kind] || '#c0392b';
        return (
          <div key={f.id} className="main-figure" style={{'--accent':accent}}>
            {f.count>1 && <div className="main-figure-count">×{f.count}</div>}
            <div className="main-figure-aura"></div>
            <ArtImg className="main-figure-img" src={f.src} alt={f.name}>
              <div className="main-figure-fallback"><Icon name="skull" size={56}/></div>
            </ArtImg>
            <div className="main-figure-name">{f.name}</div>
          </div>
        );
      })}
    </div>
  );
}
window.MainFiguresLayer = MainFiguresLayer;

/* ---- rising red danger embers (enemy/boss reveals) ---- */
function DangerParticles({ count=26 }){
  const motes = React.useMemo(()=> Array.from({length:count}, ()=>({
    left: Math.random()*100,
    size: 2 + Math.random()*5,
    dur: 4 + Math.random()*6, delay: -Math.random()*8,
    drift: (Math.random()*2-1)*40, op: 0.3 + Math.random()*0.5,
  })), [count]);
  return (
    <div className="danger-particles" aria-hidden="true">
      {motes.map((m,i)=>(
        <span key={i} className="danger-mote" style={{
          left:m.left+'%', width:m.size+'px', height:m.size+'px',
          '--dur':m.dur+'s', '--delay':m.delay+'s', '--drift':m.drift+'px', '--op':m.op }}/>
      ))}
    </div>
  );
}
window.DangerParticles = DangerParticles;

/* ---- Main screen: full Pokédex reveal overlay ---- */
function MainCodexOverlay({ entry }){
  if(!entry) return null;
  const danger = entry.kind==='enemy' || entry.kind==='boss';
  return (
    <div className={`main-codex-overlay ${danger?'danger':''}`}>
      {danger ? <DangerParticles count={30}/> : <Embers count={20}/>}
      {danger && <div className="danger-vignette"></div>}
      <CodexCard entry={entry} variant="main"/>
      <button className="main-codex-close glass-btn" onClick={()=>Game.clearMainCodex()}>Close ✕</button>
    </div>
  );
}
window.MainCodexOverlay = MainCodexOverlay;
