/* LuckZoo Bot Runtime v5 — winner/bet-anchor fix
 * ONLY fixes:
 * 1) Update the existing #roundBet directly — never create a second Total Bet number
 * 2) Keep candidate bot bet amounts + landed chips visible after BETTING closes
 * 3) Flying stops outside BETTING
 * 4) Clear old round only when the NEXT BETTING phase begins
 *
 * No board/layout/CSS geometry is modified.
 */
(()=>{
'use strict';

const DESIGN_BOARD_WIDTH=1180;
function uiScale(){
  const board=document.getElementById('board');
  if(!board)return 1;
  const w=board.getBoundingClientRect().width||DESIGN_BOARD_WIDTH;
  return Math.max(.42,Math.min(1.15,w/DESIGN_BOARD_WIDTH));
}


const API='/api/bot_display_feed.php';
const AREAS=['monkey','rabbit','lion','panda','swallow','pigeon','peacock','eagle','shark','frog','bird_group','beast_group'];

let lastId=0;
let lastRound=0;
let inBetting=false;
let busy=false;

/* UI totals are monotonic inside one visible betting round.
   They freeze at BETTING CLOSE and reset only at the next BETTING phase. */
let lockedTotal=0;
let lockedCandidates=Object.create(null);

const clean=s=>String(s||'').trim().toLowerCase().replace(/\s+/g,' ');
const fmt=n=>Number(n||0).toLocaleString(undefined,{maximumFractionDigits:0});

function phase(){
  for(const el of document.querySelectorAll('div,span,strong,b,h1,h2,h3')){
    if(el.offsetParent===null)continue;
    const t=clean(el.textContent);

    let m=t.match(/^betting\s+(\d+)$/);
    if(m)return {name:'BETTING',seconds:+m[1]};
    if(t==='betting')return {name:'BETTING',seconds:15};

    if(t==='betting close'||t==='betting closed'||/^betting close\s+\d+$/.test(t)||/^betting closed\s+\d+$/.test(t))
      return {name:'CLOSE',seconds:0};

    if(t==='drawing'||/^drawing\s+\d+$/.test(t))
      return {name:'DRAWING',seconds:0};

    if(t==='prizing'||/^prizing\s+\d+$/.test(t))
      return {name:'PRIZING',seconds:0};
  }
  return {name:'UNKNOWN',seconds:0};
}

function playerSource(){
  return document.querySelector('#players,#playerCount,#roomPlayers,[data-role="players"],.players-count,.room-players,#room');
}

/* Do not change destination logic that is already working for the current layout. */
function target(area){
  /*
   * LOCKED BOARD TARGET:
   * Bet amounts/chips belong ONLY to the original center betting controls.
   * Never re-detect by winner text, history text or the 28-box track.
   *
   * Current locked index has:
   *   #board .inner [data-area="monkey" ...]
   *   #board .inner [data-area="rabbit" ...]
   *   ...
   */
  return document.querySelector(`#board .inner [data-area="${CSS.escape(area)}"]`);
}

/* One overlay root; it never changes the underlying board layout. */
function overlay(){
  let x=document.getElementById('lz-bot-overlay');
  if(!x){
    x=document.createElement('div');
    x.id='lz-bot-overlay';
    x.style.cssText='position:fixed;inset:0;pointer-events:none;z-index:2147483000;overflow:visible';
    document.body.appendChild(x);
  }
  return x;
}

function removeFlyingOnly(){
  document.querySelectorAll('#lz-bot-overlay .lz-flying-chip').forEach(x=>x.remove());
}

/* Clear ONLY when a new visible BETTING round begins. */
function clearPreviousRoundVisuals(){
  removeFlyingOnly();
  document.querySelectorAll(
    '#lz-bot-overlay .lz-bet-badge,'+
    '#lz-bot-overlay .lz-landed-chip'
  ).forEach(x=>x.remove());
}

/* Candidate amount overlay — persists through CLOSE/DRAWING/PRIZING. */
function badge(area,value){
  const dst=target(area);
  if(!dst)return;

  const r=dst.getBoundingClientRect();
  const id='lz-badge-'+area;
  let b=document.getElementById(id);

  if(!b){
    b=document.createElement('div');
    b.id=id;
    b.className='lz-bet-badge';
    b.style.cssText=
      'position:fixed;pointer-events:none;background:rgba(0,0,0,.80);'+
      'border:1px solid #ffd44a;border-radius:8px;padding:1px 4px;'+
      'color:#ffd44a;font:900 8px Arial;box-shadow:0 0 7px #c78d1a;z-index:2;transform-origin:100% 0';
    overlay().appendChild(b);
  }

  b.textContent=fmt(value);
  const sc=uiScale();
  b.style.left=(r.right-(8*sc))+'px';
  b.style.top=(r.top+(8*sc))+'px';
  b.style.transform=`translateX(-100%) scale(${sc})`;
}

/* Keep a small landed chip on candidates after the flight.
   Limited to 3 per candidate so it stays clean. */
function addLandedChip(area,amount){
  const dst=target(area);
  if(!dst)return;

  const existing=[...document.querySelectorAll(`#lz-bot-overlay .lz-landed-chip[data-area="${area}"]`)];
  if(existing.length>=3)existing[0].remove();

  const r=dst.getBoundingClientRect();
  const index=Math.min(existing.length,2);

  const c=document.createElement('div');
  c.className='lz-landed-chip';
  c.dataset.area=area;
  c.textContent=fmt(amount);
  const sc=uiScale();
  c.style.cssText=
    `position:fixed;width:${28*sc}px;height:${28*sc}px;border-radius:50%;`+
    'display:flex;align-items:center;justify-content:center;pointer-events:none;'+
    'color:#fff7bf;font:900 6px Arial;'+
    'background:radial-gradient(circle at 30% 25%,#fff3a0 0 8%,#d92b2b 9% 43%,#780d0d 44% 62%,#f3ca45 63% 74%,#72500b 75%);'+
    'border:2px dashed #ffefa0;box-shadow:0 0 9px #e3b62e;z-index:2';

  c.style.left=(r.left+(16*sc)+(index*17*sc))+'px';
  c.style.top=(r.bottom-(38*sc)-(index*3*sc))+'px';
  overlay().appendChild(c);
}

/* Exact existing Total Bet value from the uploaded index.
   Do NOT create an overlay or a second number. */
function setTotal(value){
  const e=document.getElementById('roundBet');
  if(!e)return;
  e.textContent=fmt(value);
}

/* Moving chip only; it disappears after landing but adds a persistent landed chip. */
function fly(area,amount,delay){
  const src=playerSource(),dst=target(area);
  if(!src||!dst)return;

  setTimeout(()=>{
    if(phase().name!=='BETTING')return;

    const s=src.getBoundingClientRect(),d=dst.getBoundingClientRect();
    const x1=s.left+s.width/2,y1=s.top+s.height/2;
    const x2=d.left+d.width/2,y2=d.top+d.height/2;

    const sc=uiScale();
    const c=document.createElement('div');
    c.className='lz-flying-chip';
    c.textContent=fmt(amount);
    c.style.cssText=
      `position:fixed;width:${36*sc}px;height:${36*sc}px;margin:${-18*sc}px 0 0 ${-18*sc}px;border-radius:50%;`+
      'display:flex;align-items:center;justify-content:center;color:#fff7bf;font:900 9px Arial;'+
      'background:radial-gradient(circle at 30% 25%,#fff3a0 0 8%,#d92b2b 9% 43%,#780d0d 44% 62%,#f3ca45 63% 74%,#72500b 75%);'+
      'border:2px dashed #ffefa0;box-shadow:0 0 14px #e3b62e;'+
      'transition:transform .65s cubic-bezier(.2,.72,.22,1);z-index:3';

    c.style.left=x1+'px';
    c.style.top=y1+'px';
    overlay().appendChild(c);

    c.getBoundingClientRect();
    requestAnimationFrame(()=>{
      c.style.transform=`translate3d(${x2-x1}px,${y2-y1}px,0) scale(.82)`;
    });

    setTimeout(()=>{
      c.remove();

      // The flight may have started just before BETTING CLOSED.
      // Never create a landed bot chip after the lock.
      if(phase().name==='BETTING'){
        addLandedChip(area,amount);
      }
    },720);
  },delay);
}

function refreshPositions(){
  /* Keep persistent overlays attached to the same boxes after resize. */
  const runtime=window.LuckZooBotRuntimeState;
  if(!runtime)return;

  const totals=runtime.candidate_totals||{};
  AREAS.forEach(a=>badge(a,totals[a]||0));
  setTotal(runtime.total_bet||0);
}

async function poll(){
  if(busy)return;

  const p=phase();

  /*
   * IMPORTANT:
   * Outside BETTING we STOP NEW BETS/FLIGHTS only.
   * We DO NOT clear candidate amounts, landed chips or Total Bet.
   */
  if(p.name!=='BETTING'){
    if(inBetting){
      inBetting=false;
    }

    // Betting is locked: remove ALL bot chip graphics immediately.
    // Candidate total badges and Total Bet remain visible.
    document.querySelectorAll(
      '#lz-bot-overlay .lz-flying-chip,'+
      '#lz-bot-overlay .lz-landed-chip'
    ).forEach(x=>x.remove());
    refreshPositions();
    return;
  }

  /*
   * New visible BETTING phase = now clear previous round.
   * This is the ONLY normal place where old bet visuals are removed.
   */
  if(!inBetting){
    clearPreviousRoundVisuals();
    lastId=0;
    lastRound=0;
    lockedTotal=0;
    lockedCandidates=Object.create(null);
    inBetting=true;
  }

  busy=true;

  try{
    const r=await fetch(
      `${API}?room_id=1&after_id=${lastId}&ui_betting=1&ui_seconds=${p.seconds||15}&_=${Date.now()}`,
      {cache:'no-store',credentials:'same-origin'}
    );

    const j=await r.json();
    if(!j.ok||!j.betting)return;

    /*
     * The request may have started during BETTING but return after the UI has
     * already entered BETTING CLOSE. Never let that late response overwrite
     * the frozen final totals.
     */
    if(phase().name!=='BETTING' || !inBetting)return;

    const rid=Number(j.round?.id||0);

    /*
     * Critical round lock:
     * once this visible BETTING phase has accepted a backend round id, ignore
     * any newer backend round until the NEXT visible BETTING phase.
     * The cron can advance the server round before DRAWING/PRIZING finishes.
     */
    if(lastRound===0){
      lastRound=rid;
    }else if(rid!==lastRound){
      return;
    }

    const pe=playerSource();
    if(pe&&j.room?.players_text)pe.textContent=j.room.players_text;

    const incoming=j.display?.candidate_totals||{};

    /*
     * Bet totals cannot decrease inside a round.
     * Use monotonic values as an extra guard against stale/out-of-order HTTP
     * responses. The next visible BETTING phase resets these locks to zero.
     */
    AREAS.forEach(a=>{
      const v=Number(incoming[a]||0);
      lockedCandidates[a]=Math.max(Number(lockedCandidates[a]||0),v);
      badge(a,lockedCandidates[a]);
    });

    lockedTotal=Math.max(lockedTotal,Number(j.display?.total_bet||0));
    setTotal(lockedTotal);

    const events=Array.isArray(j.bot_events)?j.bot_events:[];
    events.forEach((e,i)=>fly(e.area,e.amount,i*95));

    lastId=Math.max(lastId,Number(j.last_event_id||0));

    window.LuckZooBotRuntime=j.diagnostic||{};
    window.LuckZooBotRuntimeState={
      candidate_totals:{...lockedCandidates},
      total_bet:lockedTotal,
      round_id:lastRound
    };

  }catch(e){
    console.warn('LuckZoo bot runtime',e);
  }finally{
    busy=false;
  }
}

function start(){
  poll();
  setInterval(poll,700);
  addEventListener('resize',refreshPositions);
}

if(document.readyState==='loading'){
  document.addEventListener('DOMContentLoaded',start,{once:true});
}else{
  start();
}
})();
