/**
 * End-to-end check of in-game reactions against a live deployment.
 * Creates two throwaway accounts, puts them in a real match, exchanges
 * reactions both ways, and cleans up.
 *   node tools/test-reactions.mjs [--base <url>]
 */
const args=process.argv.slice(2);
const argOf=(n,d)=>{const i=args.indexOf(n);return i>=0?args[i+1]:d;};
const B=argOf('--base','https://el3ab-player.caprover.al-arcade.com')+'/api';
const SB='https://safe-supabase-kong.caprover.al-arcade.com';
const SK='eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoic2VydmljZV9yb2xlIiwiaXNzIjoic3VwYWJhc2UiLCJpYXQiOjE3MzU2ODk2MDAsImV4cCI6MTg5MzQ1NjAwMH0.wNfmuJNkX-bZwD7RbjxOChlRf_3Xm4I7bswEYTcDCg4';
const fails=[]; const users=[]; let matchId=null;
const check=(l,c,d='')=>{ if(c) console.log('  ok    '+l); else {fails.push(l);console.log('  FAIL  '+l+(d?' — '+d:''));} };
const api=async(ep,body,tok,method='POST')=>{
  const o={method,headers:{'Content-Type':'application/json'}};
  if(tok)o.headers.Authorization='Bearer '+tok;
  if(method==='POST')o.body=JSON.stringify(body);
  const r=await fetch(`${B}/${ep}`,o); const t=await r.text();
  try{return{status:r.status,data:JSON.parse(t)};}catch{return{status:r.status,data:{_raw:t.slice(0,200)}};}
};
const get=(ep,p,tok)=>api(`${ep}?${new URLSearchParams(p)}`,null,tok,'GET');
const sb=async(path,init={})=>{const r=await fetch(`${SB}/rest/v1/${path}`,{...init,headers:{apikey:SK,Authorization:'Bearer '+SK,'Content-Type':'application/json',Prefer:'return=representation'}});const t=await r.text();try{return JSON.parse(t)}catch{return t}};

try{
  for(let i=0;i<3;i++){
    const g=await(await fetch(`${B}/auth.php`,{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({action:'guest'})})).json();
    if(!g.access_token)break;
    users.push({id:g.profile.id,token:g.access_token});
    await sb(`profiles?id=eq.${g.profile.id}`,{method:'PATCH',body:JSON.stringify({display_name:`ZZZ-RX-${i+1}`})});
  }
  check('three throwaway accounts',users.length===3,`${users.length}`);
  const [A,Bp,C]=users;

  await sb('matchmaking_queue?player_id=eq.'+A.id,{method:'DELETE'});
  await api('matchmaking.php',{action:'queue',game_key:'chess',time_control:'blitz_5_0'},A.token);
  const m=(await api('matchmaking.php',{action:'queue',game_key:'chess',time_control:'blitz_5_0'},Bp.token)).data;
  matchId=m.match_id;
  check('a real match exists',!!matchId,JSON.stringify(m));

  console.log('\n=== sending ===');
  let r=await api('match-chat.php',{action:'send',match_id:matchId,game_key:'chess',kind:'emote',key:'gg'},A.token);
  check('player A sends an emote',r.data.ok===true,JSON.stringify(r.data));

  r=await api('match-chat.php',{action:'send',match_id:matchId,game_key:'chess',kind:'emote',key:'wow'},A.token);
  check('the server enforces its own cooldown',r.data.cooldown===true,JSON.stringify(r.data));

  r=await api('match-chat.php',{action:'send',match_id:matchId,game_key:'chess',kind:'phrase',key:'good_luck'},Bp.token);
  check('player B sends a phrase in the same window',r.data.ok===true,JSON.stringify(r.data));

  r=await api('match-chat.php',{action:'send',match_id:matchId,game_key:'chess',kind:'emote',key:'not_a_real_key'},Bp.token);
  check('an unknown emote key is rejected',r.status===400,`status ${r.status}`);

  r=await api('match-chat.php',{action:'send',match_id:matchId,game_key:'chess',kind:'emote',key:'gg'},C.token);
  check('a non-participant cannot post into the match',r.status===403,`status ${r.status}`);

  console.log('\n=== receiving ===');
  const pa=(await get('match-chat.php',{action:'poll',match_id:matchId,game_key:'chess'},A.token)).data;
  check('A sees both reactions',(pa.messages||[]).length===2,JSON.stringify((pa.messages||[]).map(x=>x.key)));
  const mine=(pa.messages||[]).filter(x=>x.mine);
  check('A\'s own reaction is flagged as theirs',mine.length===1&&mine[0].key==='gg',JSON.stringify(mine.map(x=>x.key)));
  const theirs=(pa.messages||[]).find(x=>!x.mine);
  check('the other reaction carries the sender id',theirs?.sender_id===Bp.id,String(theirs?.sender_id));
  check('…and the sender NAME, so you can tell who spoke',!!theirs?.name,String(theirs?.name));
  check('an emote carries its emoji',(pa.messages||[]).find(x=>x.key==='gg')?.emoji==='🤝');

  const pc=await get('match-chat.php',{action:'poll',match_id:matchId,game_key:'chess'},C.token);
  check('a non-participant cannot read the match chat',pc.status===403,`status ${pc.status}`);

  const inc=(await get('match-chat.php',{action:'poll',match_id:matchId,game_key:'chess',after:pa.now},A.token)).data;
  check('incremental poll returns nothing new',(inc.messages||[]).length===0,JSON.stringify(inc.messages));

  console.log('\n=== isolation from game state ===');
  const mrow=(await sb(`matches?id=eq.${matchId}&select=game_state,current_fen,move_count,status`))[0];
  check('the match game_state was NOT touched by reactions',
    JSON.stringify(mrow.game_state||{}).indexOf('emote')===-1 && JSON.stringify(mrow.game_state||{}).indexOf('react')===-1,
    JSON.stringify(mrow.game_state));
  check('the board is untouched',mrow.move_count===0&&mrow.status==='in_progress',JSON.stringify({mc:mrow.move_count,s:mrow.status}));
}catch(e){fails.push('threw: '+e.message);console.log('ERROR',e.message);}
finally{
  console.log('\n=== teardown ===');
  if(matchId){await sb(`chat_messages?channel_id=eq.${matchId}`,{method:'DELETE'});await sb(`mp_log?match_id=eq.${matchId}`,{method:'DELETE'});await sb(`matches?id=eq.${matchId}`,{method:'DELETE'});}
  for(const u of users){
    for(const p of [`chat_messages?sender_id=eq.${u.id}`,`matchmaking_queue?player_id=eq.${u.id}`,`mp_log?player_id=eq.${u.id}`,`rating_history?player_id=eq.${u.id}`,`matches?white_player_id=eq.${u.id}`,`matches?black_player_id=eq.${u.id}`]) await sb(p,{method:'DELETE'});
    await sb(`profiles?id=eq.${u.id}`,{method:'DELETE'});
    await fetch(`${SB}/auth/v1/admin/users/${u.id}`,{method:'DELETE',headers:{apikey:SK,Authorization:'Bearer '+SK}});
  }
  console.log(`  cleaned ${users.length} accounts`);
}
console.log('');
if(fails.length){console.log(`${fails.length} FAILURE(S)`);fails.forEach(f=>console.log('  - '+f));process.exit(1);}
console.log('REACTIONS OK');
