<?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 'start':
        handleStart($db, $userId, $input);
        break;
    case 'move':
        handleGameMove($db, $userId, $input);
        break;
    case 'resign':
        handleResign($db, $userId, $input);
        break;
    case 'complete':
        handleComplete($db, $userId, $input);
        break;
    case 'get':
        handleGet($db, $userId, $input);
        break;
    default:
        jsonError('Invalid action');
}

function handleGet($db, string $userId, array $input): void {
    $matchId = $_GET['match_id'] ?? ($input['match_id'] ?? '');
    if (!$matchId) jsonError('match_id required');
    $sdb = supabaseService();
    $matches = $sdb->get('matches', ['id' => 'eq.' . $matchId, 'select' => '*', 'limit' => 1]);
    $match = is_array($matches) && !empty($matches) && !isset($matches['error']) ? $matches[0] : null;
    if (!$match) jsonError('Match not found', 404);

    // Auto-close: if match in_progress but no activity for 10s from BOTH players, close it
    if ($match['status'] === 'in_progress' && !empty($match['game_state'])) {
        $gs = json_decode($match['game_state'], true);
        if ($gs && isset($gs['ping'])) {
            $lastPing = $gs['t'] ?? 0;
            $updatedAt = strtotime($match['updated_at'] ?? '2000-01-01');
            $now = time();
            // If match hasn't been updated in 10+ seconds AND no recent ping
            if (($now - $updatedAt) > 10 && ($now * 1000 - $lastPing) > 10000) {
                // Check if THIS player is the only one active — don't close if we're here
                // Only close if updated_at is stale (means nobody is writing)
                if (($now - $updatedAt) > 30) {
                    // Both players inactive for 30s — close match as abandoned
                    $sdb->update('matches', ['status' => 'completed', 'result' => 'aborted'], ['id' => 'eq.' . $matchId]);
                    $match['status'] = 'completed';
                    $match['result'] = 'aborted';
                }
            }
        }
    }

    jsonResponse($match);
}

function handleStart($db, string $userId, array $input): void {
    $gameKey = $input['game_key'] ?? 'chess';
    $mode = $input['mode'] ?? 'bot';
    $timeControl = $input['time_control'] ?? 'rapid_10_0';
    $opponentId = $input['opponent_id'] ?? null;
    $botId = $input['bot_id'] ?? null;

    $data = [
        'game_key' => $gameKey,
        'white_player_id' => $userId,
        'black_player_id' => $opponentId,
        'status' => 'in_progress',
        'time_control' => $timeControl,
        'current_fen' => 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1',
        'moves' => '[]',
        'metadata' => json_encode(['mode' => $mode, 'bot_id' => $botId])
    ];

    $result = $db->insert('matches', $data);
    if (isset($result['error'])) jsonError($result['error']);
    jsonResponse($result[0] ?? $result);
}

function handleGameMove($db, string $userId, array $input): void {
    $matchId = $input['match_id'] ?? '';
    if (!$matchId) jsonError('match_id required');

    $update = ['updated_at' => date('c')];

    if (!empty($input['fen'])) $update['current_fen'] = $input['fen'];
    if (!empty($input['move'])) $update['moves'] = $input['move'];
    if (isset($input['move_count'])) $update['move_count'] = intval($input['move_count']);
    if (isset($input['white_time_remaining_ms'])) $update['white_time_remaining_ms'] = intval($input['white_time_remaining_ms']);
    if (isset($input['black_time_remaining_ms'])) $update['black_time_remaining_ms'] = intval($input['black_time_remaining_ms']);

    // Merge game_state instead of overwriting — preserves emotes, draw offers, etc.
    if (!empty($input['game_state'])) {
        $newState = json_decode($input['game_state'], true) ?: [];
        $sdb = supabaseService();
        $matches = $sdb->get('matches', ['id' => 'eq.' . $matchId, 'select' => 'game_state', 'limit' => 1]);
        $existing = [];
        if (is_array($matches) && !empty($matches) && !isset($matches['error'])) {
            $raw = $matches[0]['game_state'] ?? null;
            if ($raw) $existing = is_array($raw) ? $raw : (json_decode($raw, true) ?: []);
        }
        $merged = array_merge($existing, $newState);
        $update['game_state'] = json_encode($merged);
    }

    $result = $db->update('matches', $update, ['id' => 'eq.' . $matchId]);

    if (isset($result['error'])) jsonError($result['error']);
    jsonResponse(['success' => true]);
}

function handleResign($db, string $userId, array $input): void {
    $matchId = $input['match_id'] ?? '';
    if (!$matchId) jsonError('match_id required');

    $match = $db->getOne('matches', ['id' => 'eq.' . $matchId]);
    if (!$match) jsonError('Match not found', 404);

    $isWhite = $match['white_player_id'] === $userId;
    $result = $isWhite ? 'black_wins' : 'white_wins';

    $db->update('matches', [
        'status' => 'completed',
        'result' => $result,
        'ended_at' => date('c')
    ], ['id' => 'eq.' . $matchId]);

    jsonResponse(['result' => $result]);
}

function handleComplete($db, string $userId, array $input): void {
    $matchId = $input['match_id'] ?? '';
    $result = $input['result'] ?? '';
    $fen = $input['fen'] ?? '';
    $pgn = $input['pgn'] ?? '';
    $opponentRating = intval($input['opponent_rating'] ?? 1200);
    $timeControl = $input['time_control'] ?? 'rapid_10_0';

    if (!$matchId || !$result) {
        jsonError('match_id and result are required');
    }

    $db->update('matches', [
        'status' => 'completed',
        'result' => $result,
        'current_fen' => $fen,
        'pgn' => $pgn,
        'ended_at' => date('c')
    ], ['id' => 'eq.' . $matchId]);

    // Calculate Elo rating change
    $ratingCol = getRatingColumn($timeControl);
    $profiles = $db->get('profiles', ['id' => 'eq.' . $userId, 'select' => $ratingCol . ',games_played,total_wins,total_draws,total_losses,coins,xp,level', 'limit' => 1]);
    $profile = is_array($profiles) && !empty($profiles) ? $profiles[0] : null;

    if ($profile) {
        $playerRating = $profile[$ratingCol] ?? 1200;
        $score = ($result === 'win') ? 1.0 : (($result === 'draw') ? 0.5 : 0.0);
        $newRating = calculateElo($playerRating, $opponentRating, $score);
        $ratingChange = $newRating - $playerRating;

        $updates = [$ratingCol => $newRating, 'games_played' => ($profile['games_played'] ?? 0) + 1];
        if ($result === 'win') $updates['total_wins'] = ($profile['total_wins'] ?? 0) + 1;
        elseif ($result === 'draw') $updates['total_draws'] = ($profile['total_draws'] ?? 0) + 1;
        else $updates['total_losses'] = ($profile['total_losses'] ?? 0) + 1;

        $db->update('profiles', $updates, ['id' => 'eq.' . $userId]);

        // Record rating history
        $sdb = supabaseService();
        $sdb->insert('rating_history', [
            'player_id' => $userId,
            'game_key' => 'chess',
            'time_control_type' => getTimeControlType($timeControl),
            'rating_before' => $playerRating,
            'rating_after' => $newRating,
            'rating_change' => $ratingChange,
            'match_id' => $matchId,
            'result' => $result
        ]);

        // Grant coins from reward_config (admin-configurable)
        $rewardConfig = $sdb->get('reward_config', ['select' => 'key,value']);
        $rewards = [];
        if (is_array($rewardConfig) && !isset($rewardConfig['error'])) {
            foreach ($rewardConfig as $r) $rewards[$r['key']] = intval($r['value']);
        }
        $coins = ($result === 'win') ? ($rewards['chess_win_coins'] ?? 50) : (($result === 'draw') ? ($rewards['chess_draw_coins'] ?? 20) : ($rewards['chess_loss_coins'] ?? 10));

        // Use atomic DB function to prevent race conditions
        $sdb->rpc('award_coins', ['p_player_id' => $userId, 'p_amount' => $coins, 'p_reason' => 'Chess ' . $result]);

        // Legacy insert kept for compatibility
        $currentCoins = ($profile['coins'] ?? 0) + $coins;
        $sdb->insert('economy_transactions', [
            'player_id' => $userId,
            'type' => 'game_reward',
            'currency' => 'coins',
            'amount' => $coins,
            'balance_after' => $currentCoins + $coins,
            'reason' => 'Chess ' . $result
        ]);

        // Tournament result reporting hook
        reportTournamentResult($db, $matchId, $result, $userId);

        jsonResponse(['success' => true, 'result' => $result, 'rating_before' => $playerRating, 'rating_after' => $newRating, 'rating_change' => $ratingChange, 'coins_earned' => $coins]);
    }

    // Tournament result reporting hook (fallback when no profile)
    reportTournamentResult($db, $matchId, $result, $userId);

    jsonResponse(['success' => true, 'result' => $result]);
}

function calculateElo(int $playerRating, int $opponentRating, float $score): int {
    $k = 32;
    if ($playerRating > 2400) $k = 16;
    elseif ($playerRating > 2000) $k = 24;

    $expected = 1.0 / (1.0 + pow(10, ($opponentRating - $playerRating) / 400.0));
    $newRating = round($playerRating + $k * ($score - $expected));
    return max(100, $newRating);
}

function getRatingColumn(string $timeControl): string {
    if (strpos($timeControl, 'bullet') !== false) return 'elo_bullet';
    if (strpos($timeControl, 'blitz') !== false) return 'elo_blitz';
    if (strpos($timeControl, 'classical') !== false) return 'elo_classical';
    return 'elo_rapid';
}

function getTimeControlType(string $timeControl): string {
    if (strpos($timeControl, 'bullet') !== false) return 'bullet';
    if (strpos($timeControl, 'blitz') !== false) return 'blitz';
    if (strpos($timeControl, 'classical') !== false) return 'classical';
    return 'rapid';
}

function reportTournamentResult($db, string $matchId, string $result, string $userId): void {
    $sdb = supabaseService();
    $matches = $sdb->get('matches', ['id' => 'eq.' . $matchId, 'select' => 'tournament_id,metadata', 'limit' => 1]);
    $match = is_array($matches) && !empty($matches) && !isset($matches['error']) ? $matches[0] : null;

    if (!$match || empty($match['tournament_id'])) return;

    $metadata = json_decode($match['metadata'] ?? '{}', true);
    if (!empty($metadata['tournament_reported'])) return;

    // Delegate to tournament-match.php logic via internal call
    $payload = json_encode([
        'action' => 'report-result',
        'match_id' => $matchId,
        'tournament_id' => $match['tournament_id'],
        'result' => $result
    ]);

    // Use stream context for internal request
    $url = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? 'https' : 'http')
        . '://' . ($_SERVER['HTTP_HOST'] ?? 'localhost') . '/api/tournament-match.php';

    $ctx = stream_context_create(['http' => [
        'method' => 'POST',
        'header' => "Content-Type: application/json\r\nAuthorization: Bearer " . (getAuthToken() ?? '') . "\r\n",
        'content' => $payload,
        'timeout' => 5
    ]]);

    @file_get_contents($url, false, $ctx);
}
