<?php

header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization');

if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; }

require_once __DIR__ . '/../includes/supabase.php';
require_once __DIR__ . '/../includes/auth.php';

$token = requireAuth();
$userId = getUserId($token);
$input = getInput();
$action = $input['action'] ?? '';
$db = supabase($token);

switch ($action) {
    case 'queue':
        handleQueue($db, $userId, $input);
        break;
    case 'dequeue':
        handleDequeue($db, $userId, $input);
        break;
    case 'status':
        handleStatus($db, $userId, $input);
        break;
    default:
        jsonError('Invalid action');
}

function handleQueue($db, string $userId, array $input): void {
    $gameKey = $input['game_key'] ?? 'chess';
    $timeControl = $input['time_control'] ?? 'rapid_10_0';

    $sdb = supabaseService();

    // Anti-abuse: check if player can queue
    $canQueue = supabaseRpc('can_player_queue', ['p_player_id' => $userId]);
    if (is_array($canQueue) && isset($canQueue['allowed']) && !$canQueue['allowed']) {
        jsonResponse(['error' => 'cooldown', 'seconds_remaining' => $canQueue['seconds_remaining'] ?? 60]);
        return;
    }

    // STEP 1: Remove ALL stale/existing entries for this player (prevents ghost entries)
    $sdb->delete('matchmaking_queue', ['player_id' => 'eq.' . $userId]);

    // STEP 2: Clean stale entries from other players (older than 90 seconds)
    $staleTime = gmdate('c', time() - 90);
    $sdb->delete('matchmaking_queue', [
        'status' => 'eq.waiting',
        'queued_at' => 'lt.' . $staleTime
    ]);

    // STEP 3: Get player rating
    $profiles = $sdb->get('profiles', ['id' => 'eq.' . $userId, 'select' => 'elo_rapid,elo_blitz,elo_bullet', 'limit' => 1]);
    $profile = is_array($profiles) && !empty($profiles) ? $profiles[0] : [];
    $rating = $profile['elo_rapid'] ?? $profile['elo_blitz'] ?? 1200;

    // STEP 4: Get block list
    $blockedIds = [];
    $blocks = $sdb->get('player_blocks', [
        'or' => "(player_id.eq.{$userId},blocked_id.eq.{$userId})",
        'type' => 'eq.block',
        'select' => 'player_id,blocked_id'
    ]);
    if (is_array($blocks) && !isset($blocks['error'])) {
        foreach ($blocks as $b) {
            $blockedIds[] = ($b['player_id'] === $userId) ? $b['blocked_id'] : $b['player_id'];
        }
    }

    // STEP 5: Search for available opponent
    $excludeIds = array_merge([$userId], $blockedIds);
    $searchUrl = SUPABASE_REST . '/matchmaking_queue'
        . '?game_key=eq.' . urlencode($gameKey)
        . '&time_control=eq.' . urlencode($timeControl)
        . '&status=eq.waiting'
        . '&player_id=not.in.(' . implode(',', $excludeIds) . ')'
        . '&select=id,player_id,rating'
        . '&order=queued_at.asc'
        . '&limit=1';

    $ch = curl_init($searchUrl);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_HTTPHEADER, [
        'apikey: ' . SUPABASE_SERVICE_KEY,
        'Authorization: Bearer ' . SUPABASE_SERVICE_KEY,
        'Content-Type: application/json'
    ]);
    curl_setopt($ch, CURLOPT_TIMEOUT, 10);
    $searchResult = curl_exec($ch);
    curl_close($ch);
    $opponents = json_decode($searchResult, true);

    if (!empty($opponents) && !isset($opponents['error']) && isset($opponents[0])) {
        $opponent = $opponents[0];

        // STEP 6: Atomically claim opponent — mark them as matched FIRST
        // Use a conditional update: only succeeds if still 'waiting'
        $claimResult = $sdb->update('matchmaking_queue', [
            'status' => 'matched',
            'matched_with' => $userId
        ], [
            'id' => 'eq.' . $opponent['id'],
            'status' => 'eq.waiting'
        ]);

        // If claim failed (empty result = no rows matched), opponent was already taken
        if (empty($claimResult) || isset($claimResult['error'])) {
            // Opponent was grabbed by someone else — add self to queue and wait
            $sdb->insert('matchmaking_queue', [
                'player_id' => $userId,
                'game_key' => $gameKey,
                'time_control' => $timeControl,
                'rating' => $rating,
                'status' => 'waiting'
            ]);
            jsonResponse(['queued' => true]);
            return;
        }

        // STEP 7: Create match
        $isWhite = rand(0, 1) === 0;
        $whiteId = $isWhite ? $userId : $opponent['player_id'];
        $blackId = $isWhite ? $opponent['player_id'] : $userId;

        $initialTime = 600000;
        if (strpos($timeControl, 'bullet') !== false) $initialTime = 60000;
        elseif (strpos($timeControl, 'blitz') !== false) $initialTime = 300000;
        elseif (strpos($timeControl, 'classical') !== false) $initialTime = 3600000;

        $match = $sdb->insert('matches', [
            'game_key' => $gameKey,
            'match_type' => 'rated',
            'white_player_id' => $whiteId,
            'black_player_id' => $blackId,
            'status' => 'in_progress',
            'time_control' => $timeControl,
            'initial_time_ms' => $initialTime,
            'white_time_remaining_ms' => $initialTime,
            'black_time_remaining_ms' => $initialTime,
            'current_fen' => 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1',
            'moves' => [],
            'move_count' => 0,
            'game_state' => (object)[],
            'is_rated' => true,
            'started_at' => date('c')
        ]);
        $matchId = $match[0]['id'] ?? $match['id'] ?? null;

        if ($matchId) {
            // Update opponent's queue entry with match_id
            $sdb->update('matchmaking_queue', [
                'match_id' => $matchId
            ], ['id' => 'eq.' . $opponent['id']]);

            mpLog($matchId, $gameKey, $userId, 'match_created', [
                'white' => $whiteId, 'black' => $blackId, 'time_control' => $timeControl
            ]);

            $myColor = $isWhite ? 'w' : 'b';
            jsonResponse(['match_id' => $matchId, 'color' => $myColor, 'opponent_id' => $opponent['player_id']]);
            return;
        }
    }

    // No opponent found — add self to queue
    $sdb->insert('matchmaking_queue', [
        'player_id' => $userId,
        'game_key' => $gameKey,
        'time_control' => $timeControl,
        'rating' => $rating,
        'status' => 'waiting'
    ]);
    jsonResponse(['queued' => true]);
}


function handleStatus($db, string $userId, array $input): void {
    $sdb = supabaseService();

    $entry = $sdb->get('matchmaking_queue', [
        'player_id' => 'eq.' . $userId,
        'status' => 'eq.matched',
        'select' => 'match_id,matched_with',
        'limit' => 1
    ]);

    if (!empty($entry) && !isset($entry['error']) && isset($entry[0]['match_id'])) {
        $matchId = $entry[0]['match_id'];
        $match = $sdb->get('matches', ['id' => 'eq.' . $matchId, 'select' => 'white_player_id,black_player_id', 'limit' => 1]);
        $color = 'b';
        if (!empty($match) && !isset($match['error'])) {
            $color = ($match[0]['white_player_id'] === $userId) ? 'w' : 'b';
        }

        // Clean up queue entry
        $sdb->delete('matchmaking_queue', ['player_id' => 'eq.' . $userId]);

        jsonResponse(['match_id' => $matchId, 'color' => $color]);
        return;
    }

    jsonResponse(['waiting' => true]);
}

function handleDequeue($db, string $userId, array $input): void {
    $sdb = supabaseService();
    // Remove from chess matchmaking queue
    $sdb->delete('matchmaking_queue', ['player_id' => 'eq.' . $userId]);
    jsonResponse(['success' => true]);
}

function mpLog(string $matchId, string $gameKey, string $playerId, string $event, $payload = []): void {
    supabaseRpc('log_mp_event', [
        'p_match_id' => $matchId,
        'p_game_key' => $gameKey,
        'p_player_id' => $playerId,
        'p_event' => $event,
        'p_payload' => is_array($payload) ? $payload : []
    ]);
}
