import puppeteer from 'puppeteer';
import { mkdir } from 'fs/promises';

const BASE_URL = 'https://el3ab-player.caprover.al-arcade.com';
const AUTH_URL = 'https://safe-supabase-kong.caprover.al-arcade.com/auth/v1';
const API_URL = `${BASE_URL}/api`;
const ANON_KEY = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYW5vbiIsImlzcyI6InN1cGFiYXNlIiwiaWF0IjoxNzM1Njg5NjAwLCJleHAiOjE4OTM0NTYwMDB9.31PF6PvP-pSrvRuQwLFptQoejR0W1A7o53lZhEbnz84';

const PLAYER1 = { email: 'testplayer1@el3ab.com', password: 'ChessTest1!', id: 'd14a27c6-2448-4319-a775-a9f94dd6de87', name: 'testplayer1', displayName: 'لاعب اختبار' };
const PLAYER2 = { email: 'test@el3ab.com', password: 'ChessTest2!', id: '37f947c0-e10b-4bef-88ec-c0aa0e8b8034', name: 'TestPlayer', displayName: 'TestPlayer' };

const wait = ms => new Promise(r => setTimeout(r, ms));
const SHOT_DIR = '/Users/mahmoudaglan/el3ab-player/screenshots/chess-sync';

async function getToken(email, password) {
  const res = await fetch(`${AUTH_URL}/token?grant_type=password`, {
    method: 'POST',
    headers: { 'apikey': ANON_KEY, 'Content-Type': 'application/json' },
    body: JSON.stringify({ email, password })
  });
  const data = await res.json();
  if (!data.access_token) throw new Error(`Login failed: ${JSON.stringify(data)}`);
  return { token: data.access_token, refreshToken: data.refresh_token };
}

async function apiCall(token, endpoint, body) {
  const res = await fetch(`${API_URL}/${endpoint}`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` },
    body: JSON.stringify(body)
  });
  return res.json();
}

async function setupPage(browser, player, auth) {
  const page = await browser.newPage();
  await page.setViewport({ width: 390, height: 844, deviceScaleFactor: 2 });
  page.on('console', msg => {
    const txt = msg.text();
    if (msg.type() === 'error' && !txt.includes('favicon') && !txt.includes('ERR_'))
      console.log(`  [${player.name} ERR] ${txt.slice(0, 150)}`);
  });

  await page.goto(BASE_URL, { waitUntil: 'networkidle2', timeout: 30000 });
  await page.evaluate((token, refreshToken, userId, displayName, username) => {
    localStorage.setItem('el3ab_state', JSON.stringify({
      auth: { token, refreshToken, userId },
      player: { id: userId, display_name: displayName, username, level: 5, coins: 1000, xp: 500 },
      activeWorld: 'play', audioEnabled: false, language: 'ar'
    }));
  }, auth.token, auth.refreshToken, player.id, player.displayName, player.name);
  await page.reload({ waitUntil: 'networkidle2', timeout: 30000 });
  await wait(2000);
  return page;
}

async function navigateToQueue(page, playerName) {
  console.log(`   [${playerName}] Clicking chess tile...`);
  await page.evaluate(() => document.querySelector('[data-game="chess"]').click());
  await wait(1000);
  console.log(`   [${playerName}] Clicking أونلاين...`);
  await page.evaluate(() => document.querySelector('#btn-multi').click());
  await wait(1000);
  console.log(`   [${playerName}] Clicking time control...`);
  await page.evaluate(() => {
    const allEls = document.querySelectorAll('button, [class*="btn"], [role="button"]');
    for (const el of allEls) {
      const t = el.textContent.trim();
      if (t.includes('10+0') || t.includes('10 + 0') || t.includes('سريعة') || t.includes('Rapid') || t.includes('10')) {
        el.click(); return t;
      }
    }
    const scene = document.querySelector('.scene');
    if (scene) {
      const btns = scene.querySelectorAll('button, [style*="cursor: pointer"]');
      for (const btn of btns) { if (btn.id !== 'menu-close') { btn.click(); return btn.textContent.slice(0,30); } }
    }
    return null;
  });
  await wait(500);
}

async function run() {
  await mkdir(SHOT_DIR, { recursive: true });
  console.log('=== Chess SYNC Test (Move Verification) ===\n');

  // 1. Auth
  console.log('1. Authenticating...');
  const p1Auth = await getToken(PLAYER1.email, PLAYER1.password);
  const p2Auth = await getToken(PLAYER2.email, PLAYER2.password);
  console.log('   ✓ Both authenticated');

  // 2. Clean any existing queue/matches
  console.log('\n2. Cleaning queue...');
  await apiCall(p1Auth.token, 'matchmaking.php', { action: 'dequeue' });
  await apiCall(p2Auth.token, 'matchmaking.php', { action: 'dequeue' });

  // 3. Launch browser
  console.log('\n3. Launching browser...');
  const browser = await puppeteer.launch({
    headless: true,
    args: ['--no-sandbox', '--disable-setuid-sandbox', '--ignore-certificate-errors']
  });

  const page1 = await setupPage(browser, PLAYER1, p1Auth);
  const page2 = await setupPage(browser, PLAYER2, p2Auth);
  console.log('   ✓ Both pages loaded');

  // 4. Navigate to queue
  console.log('\n4. Player 1 → queue...');
  await navigateToQueue(page1, PLAYER1.name);
  console.log('   Player 2 → queue...');
  await navigateToQueue(page2, PLAYER2.name);

  // 5. Wait for match
  console.log('\n5. Waiting for match (10s)...');
  await wait(10000);

  // Verify both in game
  const p1Board = await page1.$('canvas');
  const p2Board = await page2.$('canvas');
  if (!p1Board || !p2Board) {
    console.log('   ✗ NOT BOTH IN GAME');
    const p1Html = await page1.evaluate(() => document.body.innerText.slice(0, 200));
    const p2Html = await page2.evaluate(() => document.body.innerText.slice(0, 200));
    console.log(`   P1: ${p1Html.slice(0,100)}`);
    console.log(`   P2: ${p2Html.slice(0,100)}`);
    await browser.close();
    return;
  }
  console.log('   ✓ Both players in game with canvas boards');
  await page1.screenshot({ path: `${SHOT_DIR}/01-start-p1.png` });
  await page2.screenshot({ path: `${SHOT_DIR}/01-start-p2.png` });

  // 6. Figure out who is white
  // The move list at start shows just "1." — after a move it shows "1. e4"
  // Also check the opponent name to identify match_id
  const matchInfo = await page1.evaluate(() => {
    const state = JSON.parse(localStorage.getItem('el3ab_state') || '{}');
    const activeMatch = localStorage.getItem('el3ab_active_match');
    return { state: state?.auth?.userId, activeMatch };
  });
  console.log(`   P1 active match: ${matchInfo.activeMatch}`);

  const matchInfo2 = await page2.evaluate(() => {
    const activeMatch = localStorage.getItem('el3ab_active_match');
    return { activeMatch };
  });
  console.log(`   P2 active match: ${matchInfo2.activeMatch}`);

  // Get the match ID from localStorage
  let matchId = null;
  try {
    const parsed = JSON.parse(matchInfo.activeMatch || '{}');
    matchId = parsed.matchId;
  } catch(e) {}
  if (!matchId) {
    try {
      const parsed = JSON.parse(matchInfo2.activeMatch || '{}');
      matchId = parsed.matchId;
    } catch(e) {}
  }
  console.log(`   Match ID: ${matchId}`);

  if (!matchId) {
    console.log('   ✗ Could not find match ID');
    await browser.close();
    return;
  }

  // 7. Get match data to determine who is white
  console.log('\n6. Fetching match to determine colors...');
  const matchData = await apiCall(p1Auth.token, 'game.php', { action: 'get', match_id: matchId });
  console.log(`   White: ${matchData.white_player_id?.slice(0,8)}, Black: ${matchData.black_player_id?.slice(0,8)}`);
  console.log(`   P1 ID: ${PLAYER1.id.slice(0,8)}, P2 ID: ${PLAYER2.id.slice(0,8)}`);
  console.log(`   Current FEN: ${matchData.current_fen?.slice(0,30)}`);
  console.log(`   Move count: ${matchData.move_count}`);

  const p1IsWhite = matchData.white_player_id === PLAYER1.id;
  const whiteAuth = p1IsWhite ? p1Auth : p2Auth;
  const blackAuth = p1IsWhite ? p2Auth : p1Auth;
  const whitePage = p1IsWhite ? page1 : page2;
  const blackPage = p1IsWhite ? page2 : page1;
  const whiteName = p1IsWhite ? PLAYER1.name : PLAYER2.name;
  const blackName = p1IsWhite ? PLAYER2.name : PLAYER1.name;

  console.log(`   White player: ${whiteName}, Black player: ${blackName}`);

  // 8. Make a move as white via API (e2→e4)
  console.log('\n7. Making move e4 via API as white...');
  const moveResult = await apiCall(whiteAuth.token, 'game.php', {
    action: 'move',
    match_id: matchId,
    fen: 'rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1',
    move: JSON.stringify([{ from: 'e2', to: 'e4', san: 'e4', color: 'w' }]),
    move_count: 1,
    white_time_remaining_ms: 598000,
    black_time_remaining_ms: 600000,
    game_state: JSON.stringify({ last_move: { from: 'e2', to: 'e4', san: 'e4' } })
  });
  console.log(`   API response: ${JSON.stringify(moveResult)}`);

  if (moveResult.error) {
    console.log(`   ✗ MOVE FAILED: ${moveResult.error}`);
    await browser.close();
    return;
  }
  console.log('   ✓ Move sent to server');

  // Verify move is in DB
  const verifyMatch = await apiCall(blackAuth.token, 'game.php', { action: 'get', match_id: matchId });
  console.log(`   DB verify: move_count=${verifyMatch.move_count}, fen=${verifyMatch.current_fen?.slice(0,40)}`);

  // 9. Wait for black's poll to pick it up (polls every 2s, wait 6s to be safe)
  console.log('\n8. Waiting 6s for poll cycle...');
  await wait(6000);

  // 10. Check if black's board updated
  console.log('\n9. Checking if black received the move...');

  // Check move list on black's page
  const blackMoveList = await blackPage.evaluate(() => {
    const ml = document.querySelector('#move-list');
    return ml ? ml.textContent.trim() : 'NOT FOUND';
  });
  console.log(`   Black's move list: "${blackMoveList}"`);

  // Check if clock switched (black's clock should now be active if move synced)
  const blackClocks = await blackPage.evaluate(() => {
    const player = document.querySelector('#clock-player');
    const opponent = document.querySelector('#clock-opponent');
    return {
      playerText: player?.textContent,
      opponentText: opponent?.textContent,
      playerActive: player?.classList.contains('active'),
      opponentActive: opponent?.classList.contains('active')
    };
  });
  console.log(`   Black's clocks: player=${blackClocks.playerText} (active:${blackClocks.playerActive}), opponent=${blackClocks.opponentText} (active:${blackClocks.opponentActive})`);

  // Also check white's page to see their state
  const whiteMoveList = await whitePage.evaluate(() => {
    const ml = document.querySelector('#move-list');
    return ml ? ml.textContent.trim() : 'NOT FOUND';
  });
  console.log(`   White's move list: "${whiteMoveList}"`);

  // Take screenshots
  await whitePage.screenshot({ path: `${SHOT_DIR}/02-after-move-white.png` });
  await blackPage.screenshot({ path: `${SHOT_DIR}/02-after-move-black.png` });

  // 11. Determine if sync worked
  const moveAppeared = blackMoveList.includes('e4') || blackMoveList.includes('1.');
  const hasNewContent = blackMoveList !== '1.';

  if (hasNewContent && blackMoveList.includes('e4')) {
    console.log('\n   ✓✓✓ MOVE SYNCED! Black sees e4 in move list!');
  } else {
    console.log(`\n   ✗ MOVE DID NOT SYNC to black's UI`);
    console.log('   Debugging...');

    // Check console logs for errors
    const blackErrors = await blackPage.evaluate(() => {
      return window.__consoleErrors || [];
    });
    console.log(`   Black console errors: ${JSON.stringify(blackErrors).slice(0, 300)}`);

    // Check if polling is happening — look at network activity
    const blackNetState = await blackPage.evaluate(() => {
      const activeMatch = localStorage.getItem('el3ab_active_match');
      return { activeMatch };
    });
    console.log(`   Black's active match in localStorage: ${blackNetState.activeMatch}`);

    // Try to intercept a poll response
    console.log('   Intercepting next poll response...');
    const pollResponse = await new Promise(async (resolve) => {
      const timeout = setTimeout(() => resolve('TIMEOUT - no poll detected in 5s'), 5000);
      blackPage.on('response', async (response) => {
        const url = response.url();
        if (url.includes('game.php')) {
          clearTimeout(timeout);
          try {
            const body = await response.json();
            resolve(JSON.stringify(body).slice(0, 300));
          } catch(e) {
            resolve(`parse error: ${e.message}`);
          }
        }
      });
    });
    console.log(`   Poll response: ${pollResponse}`);
  }

  // 12. Now test resign sync
  console.log('\n10. Testing resign sync...');
  const resignResult = await apiCall(blackAuth.token, 'game.php', { action: 'resign', match_id: matchId });
  console.log(`   Resign response: ${JSON.stringify(resignResult)}`);

  await wait(4000);

  // Check white's page for game-over state
  const whiteAfterResign = await whitePage.evaluate(() => {
    // Check if result screen appeared or if there's a game-over indicator
    const body = document.body.innerText.slice(0, 300);
    const hasResult = body.includes('فوز') || body.includes('خسارة') || body.includes('win') || body.includes('نتيجة');
    return { hasResult, text: body.slice(0, 150) };
  });
  console.log(`   White sees result: ${whiteAfterResign.hasResult}`);
  console.log(`   White page text: ${whiteAfterResign.text.slice(0, 100)}`);

  await whitePage.screenshot({ path: `${SHOT_DIR}/03-after-resign-white.png` });
  await blackPage.screenshot({ path: `${SHOT_DIR}/03-after-resign-black.png` });

  await browser.close();
  console.log(`\n   Screenshots saved to: ${SHOT_DIR}/`);
  console.log('\n=== Done ===');
}

run().catch(err => {
  console.error('\n✗ FATAL:', err.message);
  process.exit(1);
});
