/* ============================================================
   1 · THE LIGHT-BENDER — beam redirection puzzle (takeover).
   Each player rotates one mirror; the beam ray-traces live on the
   Main screen and must bounce off every mirror to reach the target.
   ============================================================ */
const { useState: useS_lb, useEffect: useE_lb, useRef: useR_lb } = React;

function LightBenderMainView({ lightbender }){
  const game = useGame();
  const lb = lightbender;
  const complete = lb.complete;
  useGameEvents((ev)=>{
    if(ev.type==='lb-complete'){ try{ audio.play('circuitComplete'); }catch(_){} }
  });
  // Turn sound follows the mirror actually moving on screen (state-driven) so the
  // click lands with the visual — not ahead of it via the faster lb-rotate event.
  const mirrorSig = lb.mirrors.map(m=>Math.round(m.angle)).join(',');
  const prevMirrorSig = useR_lb(mirrorSig);
  const lastTurn = useR_lb(0);
  useE_lb(()=>{
    if(prevMirrorSig.current === mirrorSig) return;
    prevMirrorSig.current = mirrorSig;
    const now = Date.now();
    if(now - lastTurn.current > 70){ lastTurn.current = now; try{ audio.play('gearClick'); }catch(_){} }
  }, [mirrorSig]);
  const trace = traceBeamPath(lb.emitter, lb.mirrors, lb.target, lb.tolerance||7);
  const fmt = (arr)=>arr.map(p=>`${p[0].toFixed(2)},${p[1].toFixed(2)}`).join(' ');
  // bright = beam up to (and reaching) the break mirror; stray = the dim-red wrong-way stub
  const brightPts = trace.breakAt>=0 ? trace.points.slice(0, trace.points.length-1) : trace.points;
  const strayPts  = trace.breakAt>=0 ? trace.points.slice(trace.points.length-2) : null;
  const litCount = (trace.used && trace.used.size) || 0;

  return (
    <div className={`lb-stage ${complete?'is-complete':''}`}>
      <Embers count={16}/>
      <div className="lb-titlebar">
        <div className="lb-title display">The Light-Bender</div>
        <div className="lb-sub">{complete ? 'The beam runs true — the chamber opens' : 'Angle every mirror so the beam threads through them all to the lens'}</div>
      </div>

      <div className="lb-board">
        <svg viewBox="0 0 100 100" className="lb-svg" preserveAspectRatio="xMidYMid meet">
          <defs>
            <radialGradient id="lb-target-grad" cx="50%" cy="50%" r="50%">
              <stop offset="0%" stopColor="#fff3d6"/><stop offset="60%" stopColor="hsl(var(--primary))"/><stop offset="100%" stopColor="transparent"/>
            </radialGradient>
          </defs>
          <rect x="0" y="0" width="100" height="100" className="lb-chamber"/>

          {/* the beam — bright relay path + dim-red stray stub at the first break */}
          <polyline points={fmt(brightPts)} className={`beam ${complete?'true':''}`}/>
          {strayPts && <polyline points={fmt(strayPts)} className="beam stray"/>}

          {/* emitter */}
          <g className="lb-emitter">
            <circle cx={lb.emitter.x} cy={lb.emitter.y} r="3.2" className="lb-emit-core"/>
            <circle cx={lb.emitter.x} cy={lb.emitter.y} r="5.5" className="lb-emit-halo"/>
          </g>

          {/* target receptacle */}
          <g className={`target ${trace.hit?'hit':''}`}>
            <circle cx={lb.target.x} cy={lb.target.y} r={lb.target.tol} className="lb-target-tol"/>
            <circle cx={lb.target.x} cy={lb.target.y} r="3.4" className="lb-target-core"/>
          </g>

          {/* mirrors */}
          {lb.mirrors.map((m,i)=>{
            const lit = trace.used && trace.used.has(i);
            const broken = trace.breakAt===i;
            const L = 9, a = m.angle*Math.PI/180;
            const ex = Math.cos(a)*L/2, ey = Math.sin(a)*L/2;
            const sa = (m.sol||0)*Math.PI/180, sx = Math.cos(sa)*L/2, sy = Math.sin(sa)*L/2;
            return (
              <g key={i} className={`mirror ${lit?'lit':''} ${broken?'break':''}`} style={{ color:m.color }}>
                <line x1={m.x-ex} y1={m.y-ey} x2={m.x+ex} y2={m.y+ey} className="lb-mirror-line"/>
                <circle cx={m.x} cy={m.y} r="1.6" className="lb-mirror-pivot"/>
                {lb.hintMirror===i && <line x1={m.x-sx} y1={m.y-sy} x2={m.x+sx} y2={m.y+sy} className="lb-mirror-hint"/>}
              </g>
            );
          })}
        </svg>
      </div>

      <div className="lb-hud">
        {!complete ? (
          <>
            <div className="lb-legend">
              {lb.mirrors.map((m,i)=>{
                const owner = game.players.find(p=>p.id===m.owner);
                const lit = trace.used && trace.used.has(i);
                const broken = trace.breakAt===i;
                return (
                  <div key={i} className={`lb-leg ${lit?'lit':''} ${broken?'break':''}`} style={{ '--mc':m.color }}>
                    <span className="lb-leg-dot"></span>
                    <span className="lb-leg-name">Mirror {i+1}</span>
                    <span className="lb-leg-owner">{owner?owner.name.split(' ')[0]:'—'}</span>
                  </div>
                );
              })}
            </div>
            <div className="lb-progress">
              {trace.breakAt>=0
                ? <>Beam breaks at <strong className="gold">Mirror {trace.breakAt+1}</strong> — {litCount}/{lb.mirrors.length} aligned · call your angle aloud</>
                : <>The beam threads every mirror — guiding it home…</>}
            </div>
          </>
        ) : <div className="lb-done display">THE WAY OPENS</div>}
      </div>
    </div>
  );
}
window.LightBenderMainView = LightBenderMainView;

/* ---- one mirror control (drag-to-rotate; local drag authority) ---- */
function MirrorControl({ mirrorIndex, mirror, secondary }){
  const ref = useR_lb(null);
  const drag = useR_lb(null);
  // local angle drives the dial so it tracks the finger at 60fps; commits to the
  // store are throttled to one per animation frame (no per-move network round-trip).
  const [live, setLive] = useS_lb(mirror.angle);
  const pending = useR_lb(null);
  const raf = useR_lb(0);
  const dragging = useR_lb(false);
  // when not dragging, follow the authoritative store value (e.g. nudges, host)
  useE_lb(()=>{ if(!dragging.current) setLive(mirror.angle); }, [mirror.angle]);

  const flush = ()=>{ raf.current=0; if(pending.current!=null){ Game.rotateMirror(mirrorIndex, pending.current, true); pending.current=null; } };
  const commit = (deg)=>{ pending.current = deg; if(!raf.current) raf.current = requestAnimationFrame(flush); };

  const onMove = (e)=>{
    if(!drag.current) return;
    const raw = Math.atan2(e.clientY-drag.current.cy, e.clientX-drag.current.cx)*180/Math.PI;
    const deg = ((raw%180)+180)%180;
    setLive(deg);          // instant visual
    commit(deg);           // throttled sync
  };
  const onUp = ()=>{
    drag.current=null; dragging.current=false;
    window.removeEventListener('pointermove', onMove); window.removeEventListener('pointerup', onUp);
    if(raf.current){ cancelAnimationFrame(raf.current); raf.current=0; }
    if(pending.current!=null){ Game.rotateMirror(mirrorIndex, pending.current, true); pending.current=null; }
    haptic([6]);
  };
  const onDown = (e)=>{
    const r = ref.current.getBoundingClientRect();
    drag.current = { cx:r.left+r.width/2, cy:r.top+r.height/2 }; dragging.current=true;
    window.addEventListener('pointermove', onMove); window.addEventListener('pointerup', onUp); e.preventDefault();
  };
  useE_lb(()=>()=>{ if(raf.current) cancelAnimationFrame(raf.current); window.removeEventListener('pointermove', onMove); window.removeEventListener('pointerup', onUp); }, []);
  const nudge = (d)=>{ const next=((mirror.angle+d)%180+180)%180; setLive(next); Game.rotateMirror(mirrorIndex, d); haptic([6]); };
  const a = live*Math.PI/180, L=34;
  const ex=Math.cos(a)*L, ey=Math.sin(a)*L;

  return (
    <div className={`lb-ctrl ${secondary?'secondary':''}`} style={{ '--mc':mirror.color }}>
      <div className="lb-ctrl-head">
        <span className="lb-ctrl-eyebrow">{secondary?'Also turning':'Your mirror'}</span>
        <span className="lb-ctrl-name">Mirror {mirrorIndex+1} · {Math.round(live)}°</span>
      </div>
      <div className="lb-ctrl-dial" ref={ref} onPointerDown={onDown}>
        <svg viewBox="0 0 100 100" className="lb-ctrl-svg">
          <circle cx="50" cy="50" r="44" className="lb-ctrl-ring"/>
          <line x1={50-ex} y1={50-ey} x2={50+ex} y2={50+ey} className="lb-ctrl-mirror" style={{ stroke:mirror.color }}/>
          <circle cx="50" cy="50" r="3" style={{ fill:mirror.color }}/>
        </svg>
        <div className="lb-ctrl-grab">drag to rotate</div>
      </div>
      <div className="lb-nudge-row">
        <button className="lb-nudge" onClick={()=>nudge(-9)}>◁◁</button>
        <button className="lb-nudge" onClick={()=>nudge(-2)}>◁</button>
        <button className="lb-nudge" onClick={()=>nudge(2)}>▷</button>
        <button className="lb-nudge" onClick={()=>nudge(9)}>▷▷</button>
      </div>
    </div>
  );
}

function LightBenderPlayerOverlay({ player }){
  const game = useGame();
  const lb = game.lightbender;
  useGameEvents((ev)=>{ if(ev.type==='lb-complete') haptic(HAPTIC.premium); });
  if(!lb.open) return null;
  const mine = lb.mirrors.map((m,i)=>({m,i})).filter(x=>x.m.owner===player.id);
  const complete = lb.complete;

  return (
    <div className={`lb-overlay ${complete?'is-complete':''}`}>
      <Embers count={10}/>
      <div className="lb-ov-inner animate-fade-rise">
        {complete ? (
          <>
            <div className="lb-ov-burst"></div>
            <h2 className="display gold">The beam strikes true</h2>
            <p className="muted" style={{textTransform:'none'}}>Your mirror found its angle. The chamber yields.</p>
          </>
        ) : mine.length===0 ? (
          <>
            <div className="lb-ov-eyebrow">✷ A chamber of light</div>
            <h2 className="display">No mirror is yours</h2>
            <p className="muted" style={{textTransform:'none'}}>Watch the chamber and help the others call their angles.</p>
          </>
        ) : (
          <>
            <div className="lb-ov-eyebrow">✷ Bend the light</div>
            <h2 className="display">{mine.length>1?'Turn your mirrors':'Turn your mirror'}</h2>
            <p className="muted lb-ov-cue" style={{textTransform:'none'}}>
              You can't see the whole path here — <strong className="gold">watch the chamber</strong> and adjust on the table's call.
            </p>
            <div className="lb-ctrl-stack">
              {mine.map((x,k)=>(<MirrorControl key={x.i} mirrorIndex={x.i} mirror={x.m} secondary={k>0}/>))}
            </div>
          </>
        )}
      </div>
    </div>
  );
}
window.LightBenderPlayerOverlay = LightBenderPlayerOverlay;
