/* LuckZoo Part 3B9 — exact central betting boxes only
 * No DOM guessing. No image/text matching. No perimeter targeting.
 *
 * Betting destinations are ONLY:
 *   #board .area[data-area="..."]
 *
 * The 28 winner-track boxes (.slot) are NEVER touched.
 */
(()=>{
'use strict';

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

let lastEventId=0;
let lastRoundId=0;
let wasBetting=false;
let requestBusy=false;

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

function headers(){
 const token=localStorage.getItem('zoo_token')||'';
 const mode=localStorage.getItem('zoo_auth_mode')||'';
 const h={'Accept':'application/json'};
 if(mode==='guest') h['X-Guest-Session']=token;
 else if(token) h['Authorization']='Bearer '+token;
 return h;
}

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

/* EXACT DESTINATION — nothing else is allowed */
function areaBox(area){
 return document.querySelector(`#board .area[data-area="${CSS.escape(area)}"]`);
}

function clearLegacyWrongBadges(){
 /* Remove all badges created by previous patches, including any on .slot. */
 document.querySelectorAll('.lz-live-bet').forEach(x=>x.remove());
}

/* Put one UI-only amount on each exact central .area box */
function ensureBadge(area){
 const box=areaBox(area);
 if(!box) return null;

 let badge=box.querySelector(':scope > .lz-live-bet');
 if(!badge){
   badge=document.createElement('span');
   badge.className='lz-live-bet';
   badge.dataset.lzArea=area;
   badge.textContent='0';
   box.appendChild(badge);
 }
 return badge;
}

function totalValueEl(){
 /* Prefer an already-existing explicit total value. */
 const exact=document.querySelector(
   '#totalBetValue,#total-bet-value,[data-role="total-bet-value"],.total-bet-value'
 );
 if(exact) return exact;

 /* Otherwise use/create ONE value in the center Total Bet bar. */
 let value=document.getElementById('lz-display-total-bet');
 if(value) return value;

 const candidates=[...document.querySelectorAll(
   '#totalBet,#total-bet,[data-role="total-bet"],.total-bet,.totalBet,.total-bet-bar,div,section'
 )];

 const bar=candidates.find(el=>{
   if(el.offsetParent===null) return false;
   const t=norm(el.textContent);
   return t==='total bet' || t.startsWith('total bet ');
 });

 if(!bar) return null;

 value=document.createElement('span');
 value.id='lz-display-total-bet';
 value.textContent='0';
 bar.appendChild(value);
 return value;
}

function resetDisplayedBets(){
 AREAS.forEach(a=>{
   const b=ensureBadge(a);
   if(b) b.textContent='0';
 });
 const t=totalValueEl();
 if(t) t.textContent='0';
 lastEventId=0;
 stopFlyingChips();
}

function applyTotals(j){
 const totals=j?.display?.candidate_totals||{};

 AREAS.forEach(area=>{
   const badge=ensureBadge(area);
   if(badge) badge.textContent=fmt(totals[area]||0);
 });

 const total=totalValueEl();
 if(total) total.textContent=fmt(j?.display?.total_bet||0);
}

function phase(){
 const els=[...document.querySelectorAll('div,span,strong,b,h1,h2,h3')];

 for(const el of els){
   if(el.offsetParent===null) continue;
   const t=norm(el.textContent);

   let m=t.match(/^betting\s+(\d+)$/);
   if(m) return {name:'BETTING',seconds:Number(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:'BETTING_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 fxLayer(){
 let layer=document.getElementById('lz-bet-fx-layer');
 if(!layer){
   layer=document.createElement('div');
   layer.id='lz-bet-fx-layer';
   document.body.appendChild(layer);
 }
 return layer;
}

function stopFlyingChips(){
 document.querySelectorAll('#lz-bet-fx-layer .lz-flying-chip').forEach(x=>x.remove());
}

function flyChip(area,amount,delay=0){
 const src=playersEl();
 const dst=areaBox(area);

 /* Never fall back to .slot or another element. */
 if(!src || !dst) return;

 setTimeout(()=>{
   /* Re-check phase at animation time. */
   if(phase().name!=='BETTING') return;

   const s=src.getBoundingClientRect();
   const d=dst.getBoundingClientRect();
   if(!s.width || !s.height || !d.width || !d.height) return;

   const chip=document.createElement('div');
   chip.className='lz-flying-chip';
   chip.textContent=fmt(amount);

   const x1=s.left+s.width/2;
   const y1=s.top+s.height/2;
   const x2=d.left+d.width/2;
   const y2=d.top+d.height/2;

   chip.style.left=x1+'px';
   chip.style.top=y1+'px';
   fxLayer().appendChild(chip);

   /* Force initial paint, then fly. */
   chip.getBoundingClientRect();
   requestAnimationFrame(()=>{
     chip.style.transform=`translate3d(${x2-x1}px,${y2-y1}px,0) scale(.82)`;
   });

   setTimeout(()=>{
     if(dst){
       dst.classList.add('lz-bet-hit');
       setTimeout(()=>dst.classList.remove('lz-bet-hit'),220);
     }
     chip.remove();
   },760);
 },delay);
}

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

 const token=localStorage.getItem('zoo_token');
 if(!token) return;

 const p=phase();

 /* Hard UI gate: absolutely nothing outside BETTING. */
 if(p.name!=='BETTING'){
   wasBetting=false;
   stopFlyingChips();
   return;
 }

 /* Visible new round starts clean. */
 if(!wasBetting){
   resetDisplayedBets();
   wasBetting=true;
 }

 requestBusy=true;
 try{
   const url=
     `${ENDPOINT}?after_id=${lastEventId}`+
     `&ui_betting=1&ui_seconds=${encodeURIComponent(p.seconds||15)}`+
     `&_=${Date.now()}`;

   const r=await fetch(url,{headers:headers(),cache:'no-store'});
   const j=await r.json();
   if(!j.ok) return;

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

   if(lastRoundId && rid!==lastRoundId){
     /* Server round changed: clear previous totals exactly once. */
     resetDisplayedBets();
   }
   lastRoundId=rid;

   const pe=playersEl();
   if(pe) pe.textContent=j.room?.players_text||'👤 30 Players';

   const events=Array.isArray(j.bot_events)?j.bot_events:[];

   /*
    * Animate EVERY newly returned event.
    * Destination is the exact central .area[data-area].
    */
   events.forEach((e,i)=>{
     if(AREAS.includes(e.area)){
       flyChip(e.area,Number(e.amount||0),i*115);
     }
   });

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

   /* Server totals are authoritative. */
   applyTotals(j);

   window.LuckZooBotDiagnostic={
     ...(j.diagnostic||{}),
     round_id:rid,
     events_received:events.length,
     last_event_id:lastEventId
   };
 }catch(e){
   console.warn('LuckZoo bot UI:',e);
 }finally{
   requestBusy=false;
 }
}

function verifyExactTargets(){
 const map={};
 AREAS.forEach(a=>{
   const el=areaBox(a);
   map[a]=!!el;
 });
 window.LuckZooExactBetTargets=map;
 console.log('LuckZoo exact central betting targets:',map);
}

function init(){
 clearLegacyWrongBadges();

 /* Never add badges to .slot. */
 document.querySelectorAll('#ring .lz-live-bet,.slot .lz-live-bet')
   .forEach(x=>x.remove());

 AREAS.forEach(ensureBadge);
 verifyExactTargets();

 poll();
 setInterval(poll,700);
}

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