/* ============================================================
   COMBAT-EVENT LAYERS — ride on top of battle/scene (no takeover).
   2 · Possessed Ally · 5 · Breath Meter · 6 · Spectral Guide · 7 · Bonds
   MainEventLayer mounts once on the Main screen; PlayerEventLayer on
   the handset. Each sub-piece self-hides when its slice is inactive.
   ============================================================ */
const { useState: useS_ev, useEffect: useE_ev, useRef: useR_ev } = React;

/* =================== MAIN SCREEN AGGREGATE =================== */
function MainEventLayer(){
  const game = useGame();
  return (
    <>
      <CharmMainLayer game={game}/>
      <BreathMainLayer game={game}/>
      <SpectralMainLayer game={game}/>
      <BondsMainLayer game={game}/>
    </>
  );
}
window.MainEventLayer = MainEventLayer;

/* ---------------- 2 · POSSESSED ALLY (main aura + cleanse ring) ---------------- */
function CharmMainLayer({ game }){
  const c = game.charm;
  const [pct, setPct] = useS_ev(0);
  useGameEvents((ev)=>{ if(ev.type==='charm-break'){ try{ audio.play('revive'); }catch(_){} } else if(ev.type==='charm-lash'){ try{ audio.play('damage'); }catch(_){} } });
  useE_ev(()=>{
    if(!c.active){ return; }
    const tick=()=>{ const left=c.endsAt-Date.now(); const p=Math.max(0,Math.min(100,(left/c.duration)*100)); setPct(p);
      if(left<=0){ Game.onCharmExpire(c.victim); }
      // possessed lash every ~4s
    };
    tick(); const id=setInterval(tick, 150); return ()=>clearInterval(id);
  }, [c.active, c.endsAt, c.duration]);
  // periodic lash
  useE_ev(()=>{ if(!c.active) return; const id=setInterval(()=>Game.possessedLash(), 4200); return ()=>clearInterval(id); }, [c.active]);
  if(!c.active) return null;
  const victim = game.players.find(p=>p.id===c.victim);
  const cleansePct = Math.min(100, (c.cleanse/c.threshold)*100);

  return (
    <div className="charm-main-layer">
      <div className="charm-banner">
        <div className="charm-aura-ring">
          <svg viewBox="0 0 80 80" className="charm-ring-svg">
            <circle cx="40" cy="40" r="34" className="charm-ring-bg"/>
            <circle cx="40" cy="40" r="34" className="charm-ring-time" style={{ strokeDashoffset: 214*(1-pct/100) }}/>
          </svg>
          <div className="charm-eye">👁</div>
        </div>
        <div className="charm-banner-text">
          <div className="charm-banner-name display">{victim?victim.name.split(' ')[0]:'A hero'} is possessed</div>
          <div className="charm-cleanse-meter"><div className="fill" style={{ width:cleansePct+'%' }}></div></div>
          <div className="charm-banner-sub">Break the curse — {Math.round(cleansePct)}%</div>
        </div>
      </div>
    </div>
  );
}

/* ---------------- 5 · BREATH METER (main bars) ---------------- */
function BreathMainLayer({ game }){
  const b = game.breath;
  useGameEvents(()=>{});
  useE_ev(()=>{
    if(!b.active) return;
    const id=setInterval(()=>Game.breathTick(), 400); return ()=>clearInterval(id);
  }, [b.active]);
  if(!b.active) return null;
  const pocketP = game.players.find(p=>p.id===b.pocket);

  return (
    <div className="breath-main-layer">
      <div className="breath-head">
        <span className="breath-title">🫧 {b.objective}</span>
        <span className="breath-pocket">{pocketP?`${pocketP.name.split(' ')[0]} is breathing`:'Air pocket free'}</span>
      </div>
      <div className="breath-bars">
        {game.players.filter(p=>!p.dead).map(p=>{
          const v = b.bars[p.id]==null?100:b.bars[p.id];
          const crit = v<25;
          const breathing = b.pocket===p.id;
          return (
            <div key={p.id} className={`breath-row ${crit?'critical':''} ${breathing?'breathing':''}`}>
              <span className="breath-name">{p.name.split(' ')[0]}</span>
              <div className="breath-bar"><div className="fill" style={{ width:v+'%' }}></div></div>
              {breathing && <span className="breath-air">⬆ air</span>}
            </div>
          );
        })}
      </div>
    </div>
  );
}

/* ---------------- 6 · SPECTRAL GUIDE (drifting whispers) ---------------- */
function SpectralMainLayer({ game }){
  const sp = game.spectral;
  useGameEvents((ev)=>{ if(ev.type==='whisper'){ try{ audio.play('intel'); }catch(_){} } });
  if(!sp.enabled || !sp.whispers.length) return null;
  return (
    <div className="spectral-main-layer">
      {sp.whispers.map((w,i)=>(
        <div key={w.id} className="whisper" style={{ left:(14 + (i*17)%70)+'%', bottom:(20+(i%4)*9)+'%' }}>
          {w.word}
          <span className="whisper-from">— {w.fromName}</span>
        </div>
      ))}
    </div>
  );
}

/* ---------------- 7 · BONDS (threads between party cards) ---------------- */
function BondsMainLayer({ game }){
  const bonds = game.bonds.list;
  const [lines, setLines] = useS_ev([]);
  useE_ev(()=>{
    const measure = ()=>{
      const out = [];
      bonds.forEach(bd=>{
        const ea = document.querySelector(`[data-healthbar="${bd.a}"]`);
        const eb = document.querySelector(`[data-healthbar="${bd.b}"]`);
        if(ea&&eb){
          const ra=ea.getBoundingClientRect(), rb=eb.getBoundingClientRect();
          out.push({ id:bd.id, active:bd.active, x1:ra.left+ra.width/2, y1:ra.bottom, x2:rb.left+rb.width/2, y2:rb.bottom });
        }
      });
      setLines(out);
    };
    measure();
    const id=setInterval(measure, 600); window.addEventListener('resize', measure);
    return ()=>{ clearInterval(id); window.removeEventListener('resize', measure); };
  }, [bonds]);
  if(!bonds.length) return null;
  return (
    <svg className="bonds-layer" width="100%" height="100%">
      {lines.map(l=>{
        const my = Math.min(l.y1,l.y2) - 26;
        return <path key={l.id} className={`bond-thread ${l.active?'active':''}`}
          d={`M ${l.x1} ${l.y1} Q ${(l.x1+l.x2)/2} ${my} ${l.x2} ${l.y2}`}/>;
      })}
    </svg>
  );
}

/* =================== PLAYER HANDSET AGGREGATE =================== */
function PlayerEventLayer({ player }){
  const game = useGame();
  return (
    <>
      <CharmPlayerLayer player={player} game={game}/>
      <BreathPlayerLayer player={player} game={game}/>
      <SpectralPlayerLayer player={player} game={game}/>
      <BondPlayerBadge player={player} game={game}/>
    </>
  );
}
window.PlayerEventLayer = PlayerEventLayer;

/* possessed: hijacked overlay + cleanse minigame; others: a Help button */
function CharmPlayerLayer({ player, game }){
  const c = game.charm;
  const [taps, setTaps] = useS_ev(0);
  useGameEvents((ev)=>{ if(ev.type==='charm-break') haptic(HAPTIC.premium); else if(ev.type==='charm-start') haptic(HAPTIC.damage); });
  if(!c.active) return null;
  const isVictim = c.victim===player.id;
  const cleansePct = Math.min(100, (c.cleanse/c.threshold)*100);
  const cleanse = (amt)=>{ Game.contributeCleanse(player.id, amt); setTaps(t=>t+1); haptic([10]); };

  if(isVictim){
    return (
      <div className="charm-overlay possessed">
        <div className="charm-ov-glitch"></div>
        <div className="charm-ov-inner">
          <div className="charm-ov-eyebrow">👁 YOU ARE POSSESSED</div>
          <h2 className="display charm-ov-title">Fight the charm</h2>
          <p className="charm-ov-cue">Your strikes turn on an ally until you break free. Mash to throw it off — your party is helping too.</p>
          <div className="charm-cleanse-big"><div className="fill" style={{ width:cleansePct+'%' }}></div></div>
          <button className="charm-mash glass-btn" onPointerDown={()=>cleanse(4)}>BREAK FREE</button>
          <div className="charm-ov-sub">{Math.round(cleansePct)}% cleansed</div>
        </div>
      </div>
    );
  }
  // ally helper
  return (
    <div className="charm-help-dock">
      <div className="charm-help-cleanse"><div className="fill" style={{ width:cleansePct+'%' }}></div></div>
      <button className="charm-help-btn glass-btn" onPointerDown={()=>cleanse(3)}>
        Help free {(game.players.find(p=>p.id===c.victim)||{name:'them'}).name.split(' ')[0]}
      </button>
    </div>
  );
}

/* breath: surface/breathe button + own bar */
function BreathPlayerLayer({ player, game }){
  const b = game.breath;
  if(!b.active) return null;
  const v = b.bars[player.id]==null?100:b.bars[player.id];
  const breathing = b.pocket===player.id;
  const queued = b.queue.includes(player.id);
  const crit = v<25;
  return (
    <div className={`breath-dock ${crit?'critical':''}`}>
      <div className="breath-dock-bar"><div className="fill" style={{ width:v+'%' }}></div></div>
      <div className="breath-dock-row">
        <span className="breath-dock-pct">{Math.round(v)}% air</span>
        {breathing
          ? <button className="breath-btn breathing glass-btn" onClick={()=>{ Game.releaseAirPocket(player.id); haptic([8]); }}>Stop — let others breathe</button>
          : <button className="breath-btn glass-btn" onClick={()=>{ Game.claimAirPocket(player.id); haptic([10]); }}>{queued?'Queued for air…':'Surface / Breathe'}</button>}
      </div>
      {breathing && <div className="breath-dock-note">You can't act while breathing</div>}
    </div>
  );
}

/* spectral: dead players get a one-word whisper input */
function SpectralPlayerLayer({ player, game }){
  const sp = game.spectral;
  const [word, setWord] = useS_ev('');
  const [cd, setCd] = useS_ev(0);
  useE_ev(()=>{
    const id=setInterval(()=>{ const last=store.getState().spectral.lastSent[player.id]||0; setCd(Math.max(0, sp.cooldownMs-(Date.now()-last))); }, 250);
    return ()=>clearInterval(id);
  }, [sp.cooldownMs, player.id]);
  if(!sp.enabled || !player.dead) return null;
  const muted = sp.muted[player.id];
  const send = (w)=>{ if(Game.sendWhisper(player.id, w)){ setWord(''); haptic([10]); } };

  return (
    <div className="spectral-overlay">
      <div className="spectral-ov-inner spectral-ui">
        <div className="spectral-ov-eyebrow">☽ You drift between worlds</div>
        <h2 className="display">Whisper one word</h2>
        <p className="spectral-ov-cue">The living might catch a single word from you — make it count. {muted?'(The Keeper has hushed you.)':''}</p>
        {sp.useBank ? (
          <div className="spectral-bank">
            {sp.bank.map(w=>(<button key={w} className="spectral-word" disabled={cd>0||muted} onClick={()=>send(w)}>{w}</button>))}
          </div>
        ) : (
          <div className="spectral-input-row">
            <input className="tinput spectral-input" maxLength={12} value={word} placeholder="one word…"
              onChange={e=>setWord(e.target.value.replace(/\s/g,''))} onKeyDown={e=>{ if(e.key==='Enter') send(word); }}/>
            <button className="spectral-send glass-btn" disabled={!word.trim()||cd>0||muted} onClick={()=>send(word)}>Whisper</button>
          </div>
        )}
        <div className="spectral-cd">{muted?'Hushed by the Keeper':cd>0?`Gather your strength… ${Math.ceil(cd/1000)}s`:'Ready to whisper'}</div>
      </div>
    </div>
  );
}

/* bond: a small partner indicator on the handset */
function BondPlayerBadge({ player, game }){
  const bond = game.bonds.list.find(b=>b.a===player.id||b.b===player.id);
  if(!bond) return null;
  const partnerId = bond.a===player.id?bond.b:bond.a;
  const partner = game.players.find(p=>p.id===partnerId);
  return (
    <div className={`bond-badge ${bond.active?'active':''}`}>
      <span className="bond-badge-thread">🜲</span>
      <span className="bond-badge-text">Bonded · {partner?partner.name.split(' ')[0]:'—'}</span>
      <span className="bond-badge-state">{bond.active?'buff active':'stay close'}</span>
    </div>
  );
}
