/* ============================================================
   CONSTELLATION — a calm cooperative star-alignment puzzle.
   Each player rotates a transparent layer of stars; align every
   layer (within tolerance) and the constellation ignites.
   • ConstellationMainView   — all layers stacked over a faint target
   • ConstellationPlayerOverlay — drag-to-rotate the layer(s) you own
   ============================================================ */
const { useState: useS_cn, useEffect: useE_cn, useRef: useR_cn } = React;

function cnRot(x, y, deg){
  const a = deg*Math.PI/180, cx=50, cy=50, dx=x-cx, dy=y-cy;
  return [ cx + dx*Math.cos(a) - dy*Math.sin(a), cy + dx*Math.sin(a) + dy*Math.cos(a) ];
}
const cnAligned = (rot, tol)=> Math.abs(angNorm(rot)) <= tol;

/* ============================================================
   MAIN SCREEN — the night sky (source of truth for the glow)
   ============================================================ */
function ConstellationMainView({ constellation }){
  const game = useGame();
  const c = constellation;
  const tol = c.tolerance;
  const complete = c.complete;
  const def = (window.CONSTELLATIONS||{})[c.target] || { name:'' };
  useGameEvents((ev)=>{
    if(ev.type==='constellation-complete'){ try{ audio.play('gateOpen'); }catch(_){} }
    else if(ev.type==='constellation-hint'){ try{ audio.play('beat'); }catch(_){} }
  });

  // each star's live position = its canonical point rotated by its layer's rot
  const layerAligned = c.layers.map(l=>cnAligned(l.rot, tol));
  const pts = c.stars.map(s=>{
    const rot = c.layers[s.layer] ? c.layers[s.layer].rot : 0;
    const [x,y] = cnRot(s.x, s.y, rot);
    return { x, y, layer:s.layer };
  });
  const alignedCount = layerAligned.filter(Boolean).length;

  return (
    <div className={`const-stage ${complete?'is-complete':''}`}>
      <div className="const-sky"></div>
      <div className="const-titlebar">
        <div className="const-title display">{def.name}</div>
        <div className="const-sub">{complete ? 'The stars connect — the way is lit' : 'Rotate every layer until the stars fall into the outline'}</div>
      </div>

      <div className="const-board">
        <svg viewBox="0 0 100 100" className="const-svg" preserveAspectRatio="xMidYMid meet">
          {/* faint target outline (canonical positions) */}
          {c.lines.map(([a,b],i)=>(
            <line key={'t'+i} x1={c.stars[a].x} y1={c.stars[a].y} x2={c.stars[b].x} y2={c.stars[b].y} className="const-target-line"/>
          ))}
          {c.stars.map((s,i)=>(
            <circle key={'tg'+i} cx={s.x} cy={s.y} r="0.9" className="const-target-star"/>
          ))}

          {/* live connecting lines — lit only when both endpoints' layers are aligned */}
          {c.lines.map(([a,b],i)=>{
            const live = layerAligned[c.stars[a].layer] && layerAligned[c.stars[b].layer];
            return <line key={'l'+i} x1={pts[a].x} y1={pts[a].y} x2={pts[b].x} y2={pts[b].y}
              className={`const-line ${live?'live':''}`}/>;
          })}

          {/* live stars, colored by layer, glowing when their layer is aligned */}
          {pts.map((p,i)=>{
            const col = c.layers[p.layer] ? c.layers[p.layer].color : '#fff';
            const al = layerAligned[p.layer];
            return <circle key={'s'+i} cx={p.x} cy={p.y} r={al?2:1.5} className={`const-star ${al?'lit':''}`} style={{ fill:col }}/>;
          })}
        </svg>
      </div>

      <div className="const-hud">
        {!complete ? (
          <div className="const-legend">
            {c.layers.map((l,i)=>{
              const owner = (game.players||[]).find(p=>p.id===l.owner);
              return (
                <div key={i} className={`const-leg ${layerAligned[i]?'lit':''}`} style={{ '--lc':l.color }}>
                  <span className="const-leg-dot"></span>
                  <span className="const-leg-name">Layer {i+1}</span>
                  <span className="const-leg-owner">{owner?owner.name.split(' ')[0]:'—'}</span>
                  <span className="const-leg-state">{layerAligned[i]?'✦ aligned':`${Math.round(Math.abs(angNorm(l.rot)))}° off`}</span>
                </div>
              );
            })}
          </div>
        ) : (
          <div className="const-done display">THE SKY IS LIT</div>
        )}
        {!complete && <div className="const-progress-text">{alignedCount}/{c.layers.length} layers aligned · look up and call your angle</div>}
      </div>
    </div>
  );
}
window.ConstellationMainView = ConstellationMainView;

/* ---------- one draggable layer (player handset) ---------- */
function ConstLayerControl({ layerIndex, layer, secondary }){
  const ref = useR_cn(null);
  const drag = useR_cn(null);
  // local rotation drives the dial at 60fps; store commits throttled to one/frame
  const [live, setLive] = useS_cn(layer.rot);
  const pending = useR_cn(null);
  const raf = useR_cn(0);
  const dragging = useR_cn(false);
  useE_cn(()=>{ if(!dragging.current) setLive(layer.rot); }, [layer.rot]);

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

  const onMove = (e)=>{
    if(!drag.current) return;
    const ang = Math.atan2(e.clientY-drag.current.cy, e.clientX-drag.current.cx);
    const deg = drag.current.startRot + (ang-drag.current.startAng)*180/Math.PI;
    setLive(deg); commit(deg);
  };
  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.moveLayer(layerIndex, pending.current); pending.current=null; }
    haptic([8]);
  };
  const onDown = (e)=>{
    const r = ref.current.getBoundingClientRect();
    const cx = r.left+r.width/2, cy = r.top+r.height/2;
    const p = e.touches ? e.touches[0] : e;
    drag.current = { startAng: Math.atan2(p.clientY-cy, p.clientX-cx), startRot: live, cx, cy }; dragging.current=true;
    window.addEventListener('pointermove', onMove);
    window.addEventListener('pointerup', onUp);
    e.preventDefault();
  };
  useE_cn(()=>()=>{ if(raf.current) cancelAnimationFrame(raf.current); window.removeEventListener('pointermove', onMove); window.removeEventListener('pointerup', onUp); }, []);
  const nudge = (d)=>{ const next=layer.rot+d; setLive(next); Game.moveLayer(layerIndex, next); haptic([6]); };

  // show only THIS layer's stars (the player can't judge alignment alone)
  const game = useGame();
  const c = game.constellation;
  const mine = c.stars.map((s,i)=>({s,i})).filter(x=>x.s.layer===layerIndex);

  return (
    <div className={`const-ctrl ${secondary?'secondary':''}`} style={{ '--lc':layer.color }}>
      <div className="const-ctrl-head">
        <span className="const-ctrl-eyebrow">{secondary?'Also turning':'Your layer'}</span>
        <span className="const-ctrl-name">Layer {layerIndex+1}</span>
      </div>
      <div className="const-ctrl-dial" ref={ref} onPointerDown={onDown}>
        <svg viewBox="0 0 100 100" className="const-ctrl-svg">
          <circle cx="50" cy="50" r="46" className="const-ctrl-ring"/>
          <g style={{ transform:`rotate(${live}deg)`, transformOrigin:'50px 50px' }}>
            {mine.map(({s,i})=>(<circle key={i} cx={s.x} cy={s.y} r="2.4" style={{ fill:layer.color }} className="const-ctrl-star"/>))}
            {mine.length>1 && mine.slice(1).map(({s},k)=>(
              <line key={'cl'+k} x1={mine[k].s.x} y1={mine[k].s.y} x2={s.x} y2={s.y} className="const-ctrl-line" style={{ stroke:layer.color }}/>
            ))}
            <line x1="50" y1="50" x2="50" y2="8" className="const-ctrl-needle"/>
          </g>
        </svg>
        <div className="const-ctrl-grab">drag to rotate</div>
      </div>
      <div className="const-nudge-row">
        <button className="const-nudge" onClick={()=>nudge(-3)}>‹ fine</button>
        <button className="const-nudge" onClick={()=>nudge(-15)}>↺</button>
        <button className="const-nudge" onClick={()=>nudge(15)}>↻</button>
        <button className="const-nudge" onClick={()=>nudge(3)}>fine ›</button>
      </div>
    </div>
  );
}

function ConstellationPlayerOverlay({ player }){
  const game = useGame();
  const c = game.constellation;
  useGameEvents((ev)=>{ if(ev.type==='constellation-complete') haptic(HAPTIC.premium); });
  if(!c.open) return null;
  const mine = c.layers.map((l,i)=>({l,i})).filter(x=>x.l.owner===player.id);
  const complete = c.complete;

  return (
    <div className={`const-overlay ${complete?'is-complete':''}`}>
      <div className="const-ov-sky"></div>
      <div className="const-ov-inner animate-fade-rise">
        {complete ? (
          <>
            <div className="const-ov-burst"></div>
            <h2 className="display gold">The constellation ignites</h2>
            <p className="muted" style={{textTransform:'none'}}>Every layer found its place. The way ahead is lit.</p>
          </>
        ) : mine.length===0 ? (
          <>
            <div className="const-ov-eyebrow">✦ A sky of scattered stars</div>
            <h2 className="display">No layer is yours</h2>
            <p className="muted" style={{textTransform:'none'}}>Watch the sky and help the others read their angles aloud.</p>
          </>
        ) : (
          <>
            <div className="const-ov-eyebrow">✦ Align the heavens</div>
            <h2 className="display">{mine.length>1?'Turn your layers':'Turn your layer'}</h2>
            <p className="muted const-ov-cue" style={{textTransform:'none'}}>
              You only see your own stars — <strong className="gold">watch the main sky</strong> to know when they line up. Call your angle to the table.
            </p>
            <div className="const-ctrl-stack">
              {mine.map((x,k)=>(<ConstLayerControl key={x.i} layerIndex={x.i} layer={x.l} secondary={k>0}/>))}
            </div>
          </>
        )}
      </div>
    </div>
  );
}
window.ConstellationPlayerOverlay = ConstellationPlayerOverlay;
