import puppeteer from 'puppeteer';

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

const PLAYER1 = { email: 'testplayer1@el3ab.com', password: 'ChessTest1!', id: 'd14a27c6-2448-4319-a775-a9f94dd6de87', name: 'Player1' };
const PLAYER2 = { email: 'test@el3ab.com', password: 'ChessTest2!', id: '37f947c0-e10b-4bef-88ec-c0aa0e8b8034', name: 'Player2' };

const wait = ms => new Promise(r => setTimeout(r, ms));

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 for ${email}: ${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 run() {
  console.log('=== Chess Multiplayer E2E Test ===\n');

  // Step 1: Get fresh tokens
  console.log('1. Authenticating players...');
  const p1Auth = await getToken(PLAYER1.email, PLAYER1.password);
  const p2Auth = await getToken(PLAYER2.email, PLAYER2.password);
  console.log(`   ✓ ${PLAYER1.name} authenticated (${PLAYER1.id.slice(0,8)})`);
  console.log(`   ✓ ${PLAYER2.name} authenticated (${PLAYER2.id.slice(0,8)})`);

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

  // Step 3: Player 1 queues
  console.log('\n3. Player 1 queues for chess (rapid_10_0)...');
  const q1 = await apiCall(p1Auth.token, 'matchmaking.php', { action: 'queue', game_key: 'chess', time_control: 'rapid_10_0' });
  console.log(`   Response: ${JSON.stringify(q1)}`);
  if (q1.match_id) {
    console.log('   ✗ ERROR: Player 1 got instant match (should be queued)');
    return;
  }
  if (!q1.queued) {
    console.log(`   ✗ ERROR: Expected queued=true, got: ${JSON.stringify(q1)}`);
    return;
  }
  console.log('   ✓ Player 1 is waiting in queue');

  // Step 4: Player 2 queues — should match with Player 1
  console.log('\n4. Player 2 queues for chess (rapid_10_0)...');
  const q2 = await apiCall(p2Auth.token, 'matchmaking.php', { action: 'queue', game_key: 'chess', time_control: 'rapid_10_0' });
  console.log(`   Response: ${JSON.stringify(q2)}`);
  if (!q2.match_id) {
    console.log('   ✗ ERROR: Player 2 should have matched with Player 1');
    return;
  }
  console.log(`   ✓ Match created: ${q2.match_id}`);
  console.log(`   ✓ Player 2 color: ${q2.color}, opponent: ${q2.opponent_id?.slice(0,8)}`);

  const matchId = q2.match_id;

  // Step 5: Player 1 polls for match
  console.log('\n5. Player 1 checks status...');
  const s1 = await apiCall(p1Auth.token, 'matchmaking.php', { action: 'status' });
  console.log(`   Response: ${JSON.stringify(s1)}`);
  if (!s1.match_id) {
    console.log('   ✗ ERROR: Player 1 should see the match');
    return;
  }
  console.log(`   ✓ Player 1 found match: ${s1.match_id}, color: ${s1.color}`);

  // Step 6: Both players GET the match
  console.log('\n6. Both players fetch match state...');
  const g1 = await apiCall(p1Auth.token, 'game.php', { action: 'get', match_id: matchId });
  const g2 = await apiCall(p2Auth.token, 'game.php', { action: 'get', match_id: matchId });
  console.log(`   P1 sees: status=${g1.status}, move_count=${g1.move_count}, fen=${g1.current_fen?.slice(0,20)}...`);
  console.log(`   P2 sees: status=${g2.status}, move_count=${g2.move_count}, fen=${g2.current_fen?.slice(0,20)}...`);
  if (g1.status !== 'in_progress' || g2.status !== 'in_progress') {
    console.log('   ✗ ERROR: Match should be in_progress');
    return;
  }
  console.log('   ✓ Both players see the match in_progress');

  // Determine who is white
  const whitePlayer = g1.white_player_id === PLAYER1.id ? { auth: p1Auth, name: PLAYER1.name } : { auth: p2Auth, name: PLAYER2.name };
  const blackPlayer = g1.white_player_id === PLAYER1.id ? { auth: p2Auth, name: PLAYER2.name } : { auth: p1Auth, name: PLAYER1.name };
  console.log(`   White: ${whitePlayer.name}, Black: ${blackPlayer.name}`);

  // Step 7: White makes move e2-e4
  console.log('\n7. White plays e2-e4...');
  const m1 = await apiCall(whitePlayer.auth.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(`   Move response: ${JSON.stringify(m1)}`);
  if (m1.error) {
    console.log(`   ✗ ERROR: Move failed: ${m1.error}`);
    return;
  }
  console.log('   ✓ Move sent successfully');

  // Step 8: Black polls and sees the move
  console.log('\n8. Black polls for opponent move...');
  await wait(500);
  const poll1 = await apiCall(blackPlayer.auth.token, 'game.php', { action: 'get', match_id: matchId });
  console.log(`   Black sees: move_count=${poll1.move_count}, fen=${poll1.current_fen?.slice(0,40)}`);
  if (poll1.move_count !== 1) {
    console.log(`   ✗ ERROR: Expected move_count=1, got ${poll1.move_count}`);
    console.log(`   Full response: ${JSON.stringify(poll1).slice(0,300)}`);
    return;
  }
  const gs1 = typeof poll1.game_state === 'string' ? JSON.parse(poll1.game_state) : poll1.game_state;
  console.log(`   game_state.last_move: ${JSON.stringify(gs1?.last_move)}`);
  console.log('   ✓ Black sees White\'s move synced!');

  // Step 9: Black responds with e7-e5
  console.log('\n9. Black plays e7-e5...');
  const m2 = await apiCall(blackPlayer.auth.token, 'game.php', {
    action: 'move',
    match_id: matchId,
    fen: 'rnbqkbnr/pppp1ppp/8/4p3/4P3/8/PPPP1PPP/RNBQKBNR w KQkq e6 0 2',
    move: JSON.stringify([
      { from: 'e2', to: 'e4', san: 'e4', color: 'w' },
      { from: 'e7', to: 'e5', san: 'e5', color: 'b' }
    ]),
    move_count: 2,
    white_time_remaining_ms: 598000,
    black_time_remaining_ms: 597000,
    game_state: JSON.stringify({ last_move: { from: 'e7', to: 'e5', san: 'e5' } })
  });
  console.log(`   Move response: ${JSON.stringify(m2)}`);
  if (m2.error) {
    console.log(`   ✗ ERROR: Move failed: ${m2.error}`);
    return;
  }
  console.log('   ✓ Black move sent successfully');

  // Step 10: White polls and sees Black's move
  console.log('\n10. White polls for opponent move...');
  await wait(500);
  const poll2 = await apiCall(whitePlayer.auth.token, 'game.php', { action: 'get', match_id: matchId });
  console.log(`   White sees: move_count=${poll2.move_count}, fen=${poll2.current_fen?.slice(0,50)}`);
  if (poll2.move_count !== 2) {
    console.log(`   ✗ ERROR: Expected move_count=2, got ${poll2.move_count}`);
    return;
  }
  console.log('   ✓ White sees Black\'s move synced!');

  // Step 11: Black resigns
  console.log('\n11. Black resigns...');
  const resign = await apiCall(blackPlayer.auth.token, 'game.php', { action: 'resign', match_id: matchId });
  console.log(`   Resign response: ${JSON.stringify(resign)}`);
  if (resign.error) {
    console.log(`   ✗ ERROR: Resign failed: ${resign.error}`);
    return;
  }
  console.log(`   ✓ Resignation accepted: ${resign.result}`);

  // Step 12: White polls and sees resign
  console.log('\n12. White polls and sees game ended...');
  await wait(500);
  const poll3 = await apiCall(whitePlayer.auth.token, 'game.php', { action: 'get', match_id: matchId });
  console.log(`   White sees: status=${poll3.status}, result=${poll3.result}`);
  if (poll3.status !== 'completed') {
    console.log(`   ✗ ERROR: Expected status=completed, got ${poll3.status}`);
    return;
  }
  if (poll3.result !== 'white_wins') {
    console.log(`   ✗ ERROR: Expected result=white_wins, got ${poll3.result}`);
    return;
  }
  console.log('   ✓ White sees victory from resignation!');

  // Step 13: Test self-match prevention
  console.log('\n13. Testing self-match prevention...');
  // Player 1 queues, dequeues, queues again quickly
  await apiCall(p1Auth.token, 'matchmaking.php', { action: 'queue', game_key: 'chess', time_control: 'rapid_10_0' });
  await apiCall(p1Auth.token, 'matchmaking.php', { action: 'dequeue' });
  const requeueResult = await apiCall(p1Auth.token, 'matchmaking.php', { action: 'queue', game_key: 'chess', time_control: 'rapid_10_0' });
  console.log(`   Re-queue result: ${JSON.stringify(requeueResult)}`);
  if (requeueResult.match_id && requeueResult.opponent_id === PLAYER1.id) {
    console.log('   ✗ ERROR: Self-matched!');
    return;
  }
  console.log('   ✓ No self-match');
  await apiCall(p1Auth.token, 'matchmaking.php', { action: 'dequeue' });

  // Step 14: Test ghost entry prevention
  console.log('\n14. Testing ghost entry prevention...');
  // Player 1 queues (simulating a session that crashes without dequeue)
  await apiCall(p1Auth.token, 'matchmaking.php', { action: 'queue', game_key: 'chess', time_control: 'rapid_10_0' });
  // Player 1 queues again (new session) — old entry should be cleaned
  const ghostTest = await apiCall(p1Auth.token, 'matchmaking.php', { action: 'queue', game_key: 'chess', time_control: 'rapid_10_0' });
  console.log(`   Result after double-queue: ${JSON.stringify(ghostTest)}`);
  if (ghostTest.queued) {
    console.log('   ✓ No ghost duplicate — clean re-queue');
  } else if (ghostTest.match_id && ghostTest.opponent_id === PLAYER1.id) {
    console.log('   ✗ ERROR: Matched with self from ghost entry');
    return;
  }
  await apiCall(p1Auth.token, 'matchmaking.php', { action: 'dequeue' });

  console.log('\n========================================');
  console.log('  ✓ ALL TESTS PASSED — Chess multiplayer works!');
  console.log('========================================\n');
}

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