#!/usr/bin/env node
const puppeteer = require('puppeteer');

async function checkRoomStatus(roomCode) {
  try {
    const response = await fetch(`https://ecast.jackboxgames.com/api/v2/rooms/${roomCode}`);
    if (response.ok) {
      const data = await response.json();
      const roomData = data.body || data;
      
      if (process.env.DEBUG) {
        console.error('[API] Room data:', JSON.stringify(roomData, null, 2));
      }
      return {
        exists: true,
        locked: roomData.locked || false,
        full: roomData.full || false,
        maxPlayers: roomData.maxPlayers || 8,
        minPlayers: roomData.minPlayers || 0
      };
    }
    return { exists: false };
  } catch (e) {
    if (process.env.DEBUG) {
      console.error('[API] Error checking room:', e.message);
    }
    return { exists: false };
  }
}

async function getPlayerCountFromAudience(roomCode) {
  const browser = await puppeteer.launch({ 
    headless: 'new',
    args: ['--no-sandbox', '--disable-setuid-sandbox']
  });
  
  const page = await browser.newPage();
  await page.setUserAgent('Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36');
  
  let playerCount = null;
  
  // Enable CDP and listen for WebSocket frames BEFORE navigating
  const client = await page.target().createCDPSession();
  await client.send('Network.enable');
  
  client.on('Network.webSocketFrameReceived', ({ response }) => {
    if (response.payloadData && playerCount === null) {
      try {
        const data = JSON.parse(response.payloadData);
        
        // Check for bc:room with player count data
        let roomVal = null;
        
        if (data.opcode === 'client/welcome' && data.result?.entities?.['bc:room']) {
          roomVal = data.result.entities['bc:room'][1]?.val;
        }
        
        if (data.opcode === 'object' && data.result?.key === 'bc:room') {
          roomVal = data.result.val;
        }
        
        if (roomVal) {
          // Strategy 1: Game ended - use gameResults
          if (roomVal.gameResults?.players) {
            playerCount = roomVal.gameResults.players.length;
            if (process.env.DEBUG) {
              console.error('[SUCCESS] Found', playerCount, 'players from gameResults');
            }
          }
          
          // Strategy 2: Game in progress - use analytics
          if (playerCount === null && roomVal.analytics) {
            const startAnalytic = roomVal.analytics.find(a => a.action === 'start');
            if (startAnalytic?.value) {
              playerCount = startAnalytic.value;
              if (process.env.DEBUG) {
                console.error('[SUCCESS] Found', playerCount, 'players from analytics');
              }
            }
          }
        }
      } catch (e) {
        // Ignore parse errors
      }
    }
  });

  try {
    if (process.env.DEBUG) console.error('[2] Navigating to jackbox.tv...');
    await page.goto('https://jackbox.tv/', { waitUntil: 'networkidle2', timeout: 30000 });
    
    if (process.env.DEBUG) console.error('[3] Waiting for form...');
    await page.waitForSelector('input#roomcode', { timeout: 10000 });
    
    await page.evaluate(() => {
      localStorage.clear();
      sessionStorage.clear();
    });
    
    if (process.env.DEBUG) console.error('[4] Typing room code:', roomCode);
    const roomInput = await page.$('input#roomcode');
    await roomInput.type(roomCode.toUpperCase(), { delay: 50 });
    
    await new Promise(resolve => setTimeout(resolve, 2000));
    
    if (process.env.DEBUG) console.error('[5] Typing name...');
    const nameInput = await page.$('input#username');
    await nameInput.type('CountBot', { delay: 30 });
    
    if (process.env.DEBUG) console.error('[6] Waiting for JOIN AUDIENCE button...');
    await page.waitForFunction(() => {
      const buttons = Array.from(document.querySelectorAll('button'));
      return buttons.some(b => b.textContent.toUpperCase().includes('JOIN AUDIENCE') && !b.disabled);
    }, { timeout: 10000 });
    
    if (process.env.DEBUG) console.error('[7] Clicking JOIN AUDIENCE...');
    await page.evaluate(() => {
      const buttons = Array.from(document.querySelectorAll('button'));
      const btn = buttons.find(b => b.textContent.toUpperCase().includes('JOIN AUDIENCE') && !b.disabled);
      if (btn) btn.click();
    });
    
    // Wait for WebSocket messages
    if (process.env.DEBUG) console.error('[8] Waiting for player count...');
    for (let i = 0; i < 20 && playerCount === null; i++) {
      await new Promise(resolve => setTimeout(resolve, 300));
    }
    
  } finally {
    await browser.close();
  }

  return playerCount;
}

async function getPlayerCount(roomCode) {
  if (process.env.DEBUG) console.error('[1] Checking room status via API...');
  const roomStatus = await checkRoomStatus(roomCode);
  
  if (!roomStatus.exists) {
    if (process.env.DEBUG) console.error('[ERROR] Room does not exist');
    return 0;
  }
  
  // If full, return maxPlayers
  if (roomStatus.full) {
    if (process.env.DEBUG) console.error('[1] Room is FULL - returning maxPlayers:', roomStatus.maxPlayers);
    return roomStatus.maxPlayers;
  }
  
  // If locked (game in progress), join as audience to get count
  if (roomStatus.locked) {
    if (process.env.DEBUG) console.error('[1] Room is LOCKED - joining as audience...');
    
    try {
      const count = await getPlayerCountFromAudience(roomCode);
      if (count !== null) {
        return count;
      }
    } catch (e) {
      if (process.env.DEBUG) console.error('[ERROR] Failed to get count:', e.message);
    }
    
    // Fallback to maxPlayers if we couldn't get exact count
    if (process.env.DEBUG) console.error('[1] Could not get exact count, returning maxPlayers:', roomStatus.maxPlayers);
    return roomStatus.maxPlayers;
  }
  
  // Not locked (lobby open) - don't join, return minPlayers
  if (process.env.DEBUG) console.error('[1] Room is NOT locked (lobby) - returning minPlayers:', roomStatus.minPlayers);
  return roomStatus.minPlayers;
}

// Main
const roomCode = process.argv[2];
if (!roomCode) {
  console.error('Usage: node jackbox-count.js <ROOM_CODE>');
  process.exit(1);
}

getPlayerCount(roomCode.toUpperCase())
  .then(count => {
    console.log(count);
    process.exit(0);
  })
  .catch(err => {
    if (process.env.DEBUG) console.error('Error:', err.message);
    console.log(0);
    process.exit(0);
  });
