<?php

header('Content-Type: application/json');
require_once __DIR__ . '/../includes/cors.php';

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);

$method = $_SERVER['REQUEST_METHOD'];

// Use service key for all friendship operations to bypass RLS issues
$sdb = supabaseService();

if ($method === 'GET') {
    $action = $_GET['action'] ?? 'list';

    if ($action === 'list') {
        $friends = $sdb->get('friendships', [
            'or' => "(requester_id.eq.{$userId},addressee_id.eq.{$userId})",
            'status' => 'eq.accepted',
            'select' => 'id,requester_id,addressee_id'
        ]);

        if (!is_array($friends) || isset($friends['error'])) {
            jsonResponse(['friends' => []]);
        }

        $friendIds = [];
        foreach ($friends as $f) {
            $friendIds[] = $f['requester_id'] === $userId ? $f['addressee_id'] : $f['requester_id'];
        }

        if (empty($friendIds)) {
            jsonResponse(['friends' => []]);
        }

        $idList = implode(',', $friendIds);
        $profiles = $sdb->get('profiles', [
            'id' => "in.({$idList})",
            'select' => 'id,username,display_name,avatar_url,is_online,level'
        ]);

        jsonResponse(['friends' => is_array($profiles) && !isset($profiles['error']) ? $profiles : []]);
    }

    if ($action === 'pending') {
        $pending = $sdb->get('friendships', [
            'addressee_id' => 'eq.' . $userId,
            'status' => 'eq.pending',
            'select' => 'id,requester_id,created_at'
        ]);
        jsonResponse(['pending' => is_array($pending) && !isset($pending['error']) ? $pending : []]);
    }

    if ($action === 'sent') {
        $sent = $sdb->get('friendships', [
            'requester_id' => 'eq.' . $userId,
            'status' => 'eq.pending',
            'select' => 'id,addressee_id,created_at'
        ]);
        jsonResponse(['sent' => is_array($sent) && !isset($sent['error']) ? $sent : []]);
    }

    if ($action === 'search') {
        $query = $_GET['query'] ?? '';
        if (strlen($query) < 2) jsonError('Query too short');

        // Sanitize PostgREST special characters to prevent filter injection
        $query = preg_replace('/[^a-zA-Z0-9\x{0600}-\x{06FF}\s_.-]/u', '', $query);
        if (strlen($query) < 2) jsonError('Query too short');

        $results = $sdb->get('profiles', [
            'or' => "(username.ilike.*{$query}*,display_name.ilike.*{$query}*)",
            'id' => 'neq.' . $userId,
            'select' => 'id,username,display_name,avatar_url,level,is_online',
            'limit' => 15
        ]);

        jsonResponse(['players' => is_array($results) && !isset($results['error']) ? $results : []]);
    }

    if ($action === 'profiles') {
        $ids = $_GET['ids'] ?? '';
        if (!$ids) jsonResponse(['profiles' => []]);
        // Validate each ID is a valid UUID to prevent filter injection
        $rawIds = array_map('trim', explode(',', $ids));
        $validIds = array_filter($rawIds, function($id) {
            return preg_match('/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i', $id);
        });
        if (empty($validIds)) jsonResponse(['profiles' => []]);
        $idList = implode(',', $validIds);
        $profiles = $sdb->get('profiles', [
            'id' => "in.({$idList})",
            'select' => 'id,username,display_name,avatar_url,level,is_online'
        ]);
        jsonResponse(['profiles' => is_array($profiles) && !isset($profiles['error']) ? $profiles : []]);
    }

    if ($action === 'blocked-list') {
        $blocks = $sdb->get('player_blocks', [
            'player_id' => 'eq.' . $userId,
            'select' => 'id,blocked_id,type,created_at',
            'order' => 'created_at.desc'
        ]);
        $items = is_array($blocks) && !isset($blocks['error']) ? $blocks : [];
        if (!empty($items)) {
            $blockedIds = implode(',', array_column($items, 'blocked_id'));
            $profiles = $sdb->get('profiles', [
                'id' => "in.({$blockedIds})",
                'select' => 'id,username,display_name,avatar_url'
            ]);
            $profileMap = [];
            if (is_array($profiles) && !isset($profiles['error'])) {
                foreach ($profiles as $p) $profileMap[$p['id']] = $p;
            }
            foreach ($items as &$item) {
                $item['profile'] = $profileMap[$item['blocked_id']] ?? null;
            }
        }
        jsonResponse(['blocked' => $items]);
    }

    jsonError('Invalid action');
}

if ($method === 'POST') {
    $input = getInput();
    $action = $input['action'] ?? '';

    if ($action === 'request') {
        $targetId = $input['target_id'] ?? '';
        if (!$targetId) jsonError('target_id required');
        if ($targetId === $userId) jsonError('Cannot add yourself');

        // Check if either user blocked the other
        $blocked = $sdb->get('player_blocks', [
            'or' => "(and(player_id.eq.{$userId},blocked_id.eq.{$targetId}),and(player_id.eq.{$targetId},blocked_id.eq.{$userId}))",
            'type' => 'eq.block',
            'limit' => 1
        ]);
        if (is_array($blocked) && !isset($blocked['error']) && !empty($blocked)) {
            jsonError('Cannot send request to this player');
        }

        // Check for existing friendship or pending request in EITHER direction
        $existing = $sdb->get('friendships', [
            'or' => "(and(requester_id.eq.{$userId},addressee_id.eq.{$targetId}),and(requester_id.eq.{$targetId},addressee_id.eq.{$userId}))",
            'select' => 'id,status',
            'limit' => 1
        ]);

        if (is_array($existing) && !isset($existing['error']) && !empty($existing)) {
            $status = $existing[0]['status'] ?? '';
            if ($status === 'accepted') jsonError('Already friends');
            if ($status === 'pending') jsonError('Request already pending');
        }

        $result = $sdb->insert('friendships', [
            'requester_id' => $userId,
            'addressee_id' => $targetId,
            'status' => 'pending'
        ]);
        if (isset($result['error'])) jsonError($result['error']);
        jsonResponse(['success' => true]);
    }

    if ($action === 'accept') {
        $friendshipId = $input['friendship_id'] ?? '';
        if (!$friendshipId) jsonError('friendship_id required');

        // Verify this request is addressed to the current user
        $friendship = $sdb->get('friendships', [
            'id' => 'eq.' . $friendshipId,
            'addressee_id' => 'eq.' . $userId,
            'status' => 'eq.pending',
            'select' => 'id,requester_id',
            'limit' => 1
        ]);

        if (!is_array($friendship) || isset($friendship['error']) || empty($friendship)) {
            jsonError('Friend request not found or already handled');
        }

        $result = $sdb->update('friendships', [
            'status' => 'accepted',
            'updated_at' => gmdate('c')
        ], ['id' => 'eq.' . $friendshipId]);

        if (isset($result['error'])) jsonError($result['error']);

        jsonResponse(['success' => true, 'friend_id' => $friendship[0]['requester_id']]);
    }

    if ($action === 'reject') {
        $friendshipId = $input['friendship_id'] ?? '';
        if (!$friendshipId) jsonError('friendship_id required');

        // Verify this request is addressed to the current user
        $friendship = $sdb->get('friendships', [
            'id' => 'eq.' . $friendshipId,
            'addressee_id' => 'eq.' . $userId,
            'status' => 'eq.pending',
            'limit' => 1
        ]);

        if (!is_array($friendship) || isset($friendship['error']) || empty($friendship)) {
            jsonError('Friend request not found');
        }

        $sdb->delete('friendships', ['id' => 'eq.' . $friendshipId]);
        jsonResponse(['success' => true]);
    }

    if ($action === 'remove') {
        $targetId = $input['target_id'] ?? '';
        if (!$targetId) jsonError('target_id required');

        $sdb->delete('friendships', [
            'or' => "(and(requester_id.eq.{$userId},addressee_id.eq.{$targetId}),and(requester_id.eq.{$targetId},addressee_id.eq.{$userId}))"
        ]);
        jsonResponse(['success' => true]);
    }

    if ($action === 'report') {
        $targetId = $input['target_id'] ?? '';
        $reason = $input['reason'] ?? 'other';
        if (!$targetId) jsonError('target_id required');
        $sdb->insert('cheat_reports', [
            'reported_player_id' => $targetId,
            'reported_by' => $userId,
            'reason' => $reason,
            'description' => $input['description'] ?? '',
            'status' => 'pending'
        ]);
        jsonResponse(['success' => true]);
    }

    if ($action === 'block') {
        $targetId = $input['target_id'] ?? '';
        if (!$targetId) jsonError('target_id required');
        if ($targetId === $userId) jsonError('Cannot block yourself');

        $sdb->insert('player_blocks', [
            'player_id' => $userId,
            'blocked_id' => $targetId,
            'type' => 'block'
        ]);
        // Remove friendship if exists
        $sdb->delete('friendships', [
            'or' => "(and(requester_id.eq.{$userId},addressee_id.eq.{$targetId}),and(requester_id.eq.{$targetId},addressee_id.eq.{$userId}))"
        ]);
        jsonResponse(['success' => true]);
    }

    if ($action === 'unblock') {
        $targetId = $input['target_id'] ?? '';
        if (!$targetId) jsonError('target_id required');
        $sdb->delete('player_blocks', [
            'player_id' => 'eq.' . $userId,
            'blocked_id' => 'eq.' . $targetId
        ]);
        jsonResponse(['success' => true]);
    }

    if ($action === 'mute') {
        $targetId = $input['target_id'] ?? '';
        if (!$targetId) jsonError('target_id required');
        if ($targetId === $userId) jsonError('Cannot mute yourself');

        // Upsert: change existing block to mute, or insert new mute
        $existing = $sdb->get('player_blocks', [
            'player_id' => 'eq.' . $userId,
            'blocked_id' => 'eq.' . $targetId,
            'limit' => 1
        ]);
        if (!empty($existing) && !isset($existing['error']) && !empty($existing[0])) {
            $sdb->update('player_blocks', ['type' => 'mute'], [
                'player_id' => 'eq.' . $userId,
                'blocked_id' => 'eq.' . $targetId
            ]);
        } else {
            $sdb->insert('player_blocks', [
                'player_id' => $userId,
                'blocked_id' => $targetId,
                'type' => 'mute'
            ]);
        }
        jsonResponse(['success' => true]);
    }

    if ($action === 'unmute') {
        $targetId = $input['target_id'] ?? '';
        if (!$targetId) jsonError('target_id required');
        $sdb->delete('player_blocks', [
            'player_id' => 'eq.' . $userId,
            'blocked_id' => 'eq.' . $targetId,
            'type' => 'eq.mute'
        ]);
        jsonResponse(['success' => true]);
    }

    if ($action === 'invite') {
        $targetId = $input['target_id'] ?? '';
        $gameKey = $input['game_key'] ?? 'chess';
        $timeControl = $input['time_control'] ?? 'rapid_10_0';
        if (!$targetId) jsonError('target_id required');

        // Check blocks
        $blocked = $sdb->get('player_blocks', [
            'or' => "(and(player_id.eq.{$userId},blocked_id.eq.{$targetId}),and(player_id.eq.{$targetId},blocked_id.eq.{$userId}))",
            'type' => 'eq.block',
            'limit' => 1
        ]);
        if (is_array($blocked) && !isset($blocked['error']) && !empty($blocked)) {
            jsonError('Cannot invite this player');
        }

        if ($gameKey === 'domino') {
            $players = [$userId, $targetId];
            $match = $sdb->insert('domino_matches', [
                'status' => 'waiting',
                'players' => json_encode($players),
                'current_turn' => 0,
                'board' => [],
                'hands' => (object)[],
                'boneyard' => [],
                'moves' => [],
                'scores' => ['0' => 0, '1' => 0],
                'game_state' => ['mode' => 'live', 'move_count' => 0, 'round' => 1, 'invite_from' => $userId, 'invite_to' => $targetId, 'invite_t' => time()],
                'host_id' => $userId,
                'created_by' => $userId
            ]);

            if (isset($match['error'])) jsonError($match['error']);
            $matchId = $match[0]['id'] ?? $match['id'] ?? null;

            jsonResponse([
                'match_id' => $matchId,
                'color' => 'player1',
                'game_key' => $gameKey,
                'time_control' => $timeControl
            ]);
        } elseif ($gameKey === 'ludo') {
            $players = [$userId, $targetId];
            $match = $sdb->insert('ludo_matches', [
                'status' => 'waiting',
                'players' => json_encode($players),
                'current_turn' => 0,
                'board_state' => '{}',
                'game_state' => ['mode' => 'live', 'invite_from' => $userId, 'invite_to' => $targetId, 'invite_t' => time()],
                'host_id' => $userId
            ]);

            if (isset($match['error'])) jsonError($match['error']);
            $matchId = $match[0]['id'] ?? $match['id'] ?? null;

            jsonResponse([
                'match_id' => $matchId,
                'color' => 'player1',
                'game_key' => $gameKey,
                'time_control' => $timeControl
            ]);
        } elseif ($gameKey === 'backgammon') {
            $variant = $input['variant'] ?? 'sheshbesh';
            $isWhite = rand(0, 1) === 0;
            $whiteId = $isWhite ? $userId : $targetId;
            $blackId = $isWhite ? $targetId : $userId;

            $match = $sdb->insert('backgammon_matches', [
                'status' => 'waiting',
                'white_player_id' => $whiteId,
                'black_player_id' => $blackId,
                'variant' => $variant,
                'game_state' => ['invite_from' => $userId, 'invite_to' => $targetId, 'invite_t' => time()],
                'current_turn' => 'white',
                'created_at' => gmdate('c')
            ]);

            if (isset($match['error'])) jsonError($match['error']);
            $matchId = $match[0]['id'] ?? $match['id'] ?? null;

            jsonResponse([
                'match_id' => $matchId,
                'color' => $isWhite ? 'w' : 'b',
                'game_key' => $gameKey,
                'time_control' => $timeControl
            ]);
        } else {
            // Chess
            $initialTime = 600000;
            if (strpos($timeControl, 'bullet') !== false) $initialTime = 60000;
            elseif (strpos($timeControl, 'blitz') !== false) $initialTime = 300000;
            elseif (strpos($timeControl, 'classical') !== false) $initialTime = 3600000;

            $isWhite = rand(0, 1) === 0;
            $whiteId = $isWhite ? $userId : $targetId;
            $blackId = $isWhite ? $targetId : $userId;

            $match = $sdb->insert('matches', [
                'game_key' => $gameKey,
                'match_type' => 'friendly',
                'white_player_id' => $whiteId,
                'black_player_id' => $blackId,
                'status' => 'waiting',
                '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' => ['invite_from' => $userId, 'invite_to' => $targetId, 'invite_t' => time()],
                'is_rated' => false,
                'created_at' => gmdate('c')
            ]);

            if (isset($match['error'])) jsonError($match['error']);
            $matchId = $match[0]['id'] ?? null;

            jsonResponse([
                'match_id' => $matchId,
                'color' => $isWhite ? 'w' : 'b',
                'game_key' => $gameKey,
                'time_control' => $timeControl
            ]);
        }
    }

    if ($action === 'check-invites') {
        $result = [];
        $now = time();

        // Get blocked user IDs to filter invites
        $blocksData = $sdb->get('player_blocks', [
            'player_id' => 'eq.' . $userId,
            'type' => 'eq.block',
            'select' => 'blocked_id'
        ]);
        $blockedIds = [];
        if (is_array($blocksData) && !isset($blocksData['error'])) {
            $blockedIds = array_column($blocksData, 'blocked_id');
        }

        // Check chess matches table
        $invites = $sdb->get('matches', [
            'or' => "(white_player_id.eq.{$userId},black_player_id.eq.{$userId})",
            'status' => 'eq.waiting',
            'match_type' => 'eq.friendly',
            'select' => 'id,game_key,time_control,white_player_id,black_player_id,game_state,created_at',
            'order' => 'created_at.desc',
            'limit' => 5
        ]);

        if (is_array($invites) && !isset($invites['error'])) {
            foreach ($invites as $inv) {
                $gs = is_array($inv['game_state']) ? $inv['game_state'] : json_decode($inv['game_state'] ?? '{}', true);
                $inviteTo = $gs['invite_to'] ?? null;
                $inviteT = $gs['invite_t'] ?? 0;
                if ($inviteTo !== $userId) continue;
                if ($now - $inviteT > 120) continue;
                $fromId = $gs['invite_from'] ?? null;
                if ($fromId && in_array($fromId, $blockedIds)) continue;
                $result[] = [
                    'match_id' => $inv['id'],
                    'game_key' => $inv['game_key'] ?? 'chess',
                    'time_control' => $inv['time_control'] ?? 'rapid_10_0',
                    'from_id' => $fromId,
                    'created_at' => $inv['created_at']
                ];
            }
        }

        // Check domino_matches table (filter by player at DB level)
        $dominoInvites = $sdb->get('domino_matches', [
            'status' => 'eq.waiting',
            'players' => 'cs.["' . $userId . '"]',
            'select' => 'id,players,game_state,created_at',
            'order' => 'created_at.desc',
            'limit' => 5
        ]);

        if (is_array($dominoInvites) && !isset($dominoInvites['error'])) {
            foreach ($dominoInvites as $inv) {
                $players = is_array($inv['players']) ? $inv['players'] : json_decode($inv['players'] ?? '[]', true);
                if (!in_array($userId, $players)) continue;
                $gs = is_array($inv['game_state']) ? $inv['game_state'] : json_decode($inv['game_state'] ?? '{}', true);
                $inviteTo = $gs['invite_to'] ?? null;
                $inviteT = $gs['invite_t'] ?? 0;
                if ($inviteTo !== $userId) continue;
                if ($now - $inviteT > 120) continue;
                $fromId = $gs['invite_from'] ?? null;
                if ($fromId && in_array($fromId, $blockedIds)) continue;
                $result[] = [
                    'match_id' => $inv['id'],
                    'game_key' => 'domino',
                    'time_control' => 'standard',
                    'from_id' => $fromId,
                    'created_at' => $inv['created_at']
                ];
            }
        }

        // Check ludo_matches table (filter by player at DB level)
        $ludoInvites = $sdb->get('ludo_matches', [
            'status' => 'eq.waiting',
            'players' => 'cs.["' . $userId . '"]',
            'select' => 'id,players,game_state,created_at',
            'order' => 'created_at.desc',
            'limit' => 5
        ]);

        if (is_array($ludoInvites) && !isset($ludoInvites['error'])) {
            foreach ($ludoInvites as $inv) {
                $players = is_array($inv['players']) ? $inv['players'] : json_decode($inv['players'] ?? '[]', true);
                if (!in_array($userId, $players)) continue;
                $gs = is_array($inv['game_state']) ? $inv['game_state'] : json_decode($inv['game_state'] ?? '{}', true);
                $inviteTo = $gs['invite_to'] ?? null;
                $inviteT = $gs['invite_t'] ?? 0;
                if ($inviteTo !== $userId) continue;
                if ($now - $inviteT > 120) continue;
                $fromId = $gs['invite_from'] ?? null;
                if ($fromId && in_array($fromId, $blockedIds)) continue;
                $result[] = [
                    'match_id' => $inv['id'],
                    'game_key' => 'ludo',
                    'time_control' => 'standard',
                    'from_id' => $fromId,
                    'created_at' => $inv['created_at']
                ];
            }
        }

        // Check backgammon_matches table
        $bgInvites = $sdb->get('backgammon_matches', [
            'or' => "(white_player_id.eq.{$userId},black_player_id.eq.{$userId})",
            'status' => 'eq.waiting',
            'select' => 'id,white_player_id,black_player_id,game_state,variant,created_at',
            'order' => 'created_at.desc',
            'limit' => 5
        ]);

        if (is_array($bgInvites) && !isset($bgInvites['error'])) {
            foreach ($bgInvites as $inv) {
                $gs = is_array($inv['game_state']) ? $inv['game_state'] : json_decode($inv['game_state'] ?? '{}', true);
                $inviteTo = $gs['invite_to'] ?? null;
                $inviteT = $gs['invite_t'] ?? 0;
                if ($inviteTo !== $userId) continue;
                if ($now - $inviteT > 120) continue;
                $fromId = $gs['invite_from'] ?? null;
                if ($fromId && in_array($fromId, $blockedIds)) continue;
                $result[] = [
                    'match_id' => $inv['id'],
                    'game_key' => 'backgammon',
                    'time_control' => 'standard',
                    'from_id' => $fromId,
                    'created_at' => $inv['created_at']
                ];
            }
        }

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

    if ($action === 'accept-invite') {
        $matchId = $input['match_id'] ?? '';
        $gameKey = $input['game_key'] ?? '';
        if (!$matchId) jsonError('match_id required');

        if ($gameKey === 'domino') {
            $matches = $sdb->get('domino_matches', [
                'id' => 'eq.' . $matchId,
                'status' => 'eq.waiting',
                'select' => 'id,players,game_state',
                'limit' => 1
            ]);
            if (!is_array($matches) || isset($matches['error']) || empty($matches)) {
                jsonError('Invite not found or expired');
            }
            // Verify current user is the invite target
            $gs = is_array($matches[0]['game_state']) ? $matches[0]['game_state'] : json_decode($matches[0]['game_state'] ?? '{}', true);
            if (($gs['invite_to'] ?? '') !== $userId) {
                jsonError('Not authorized to accept this invite', 403);
            }
            $sdb->update('domino_matches', [
                'status' => 'in_progress'
            ], ['id' => 'eq.' . $matchId]);
            $players = is_array($matches[0]['players']) ? $matches[0]['players'] : json_decode($matches[0]['players'] ?? '[]', true);
            $playerIndex = array_search($userId, $players);
            jsonResponse([
                'match_id' => $matchId,
                'color' => 'player' . ($playerIndex + 1),
                'player_index' => $playerIndex !== false ? $playerIndex : 1,
                'started' => true
            ]);
        } elseif ($gameKey === 'ludo') {
            $matches = $sdb->get('ludo_matches', [
                'id' => 'eq.' . $matchId,
                'status' => 'eq.waiting',
                'select' => 'id,players,game_state',
                'limit' => 1
            ]);
            if (!is_array($matches) || isset($matches['error']) || empty($matches)) {
                jsonError('Invite not found or expired');
            }
            $gs = is_array($matches[0]['game_state']) ? $matches[0]['game_state'] : json_decode($matches[0]['game_state'] ?? '{}', true);
            if (($gs['invite_to'] ?? '') !== $userId) {
                jsonError('Not authorized to accept this invite', 403);
            }
            $sdb->update('ludo_matches', [
                'status' => 'in_progress'
            ], ['id' => 'eq.' . $matchId]);
            $players = is_array($matches[0]['players']) ? $matches[0]['players'] : json_decode($matches[0]['players'] ?? '[]', true);
            $playerIndex = array_search($userId, $players);
            jsonResponse([
                'match_id' => $matchId,
                'color' => 'player' . ($playerIndex + 1),
                'player_index' => $playerIndex !== false ? $playerIndex : 1,
                'started' => true
            ]);
        } elseif ($gameKey === 'backgammon') {
            $matches = $sdb->get('backgammon_matches', [
                'id' => 'eq.' . $matchId,
                'status' => 'eq.waiting',
                'or' => "(white_player_id.eq.{$userId},black_player_id.eq.{$userId})",
                'select' => 'id,white_player_id,black_player_id,game_state',
                'limit' => 1
            ]);
            if (!is_array($matches) || isset($matches['error']) || empty($matches)) {
                jsonError('Invite not found or expired');
            }
            $gs = is_array($matches[0]['game_state']) ? $matches[0]['game_state'] : json_decode($matches[0]['game_state'] ?? '{}', true);
            if (($gs['invite_to'] ?? '') !== $userId) {
                jsonError('Not authorized to accept this invite', 403);
            }
            $sdb->update('backgammon_matches', [
                'status' => 'in_progress'
            ], ['id' => 'eq.' . $matchId]);
            $color = ($matches[0]['white_player_id'] === $userId) ? 'w' : 'b';
            jsonResponse([
                'match_id' => $matchId,
                'color' => $color,
                'started' => true
            ]);
        } else {
            // Chess (default)
            $matches = $sdb->get('matches', [
                'id' => 'eq.' . $matchId,
                'status' => 'eq.waiting',
                'or' => "(white_player_id.eq.{$userId},black_player_id.eq.{$userId})",
                'select' => 'id,white_player_id,black_player_id',
                'limit' => 1
            ]);

            if (!is_array($matches) || isset($matches['error']) || empty($matches)) {
                jsonError('Invite not found or expired');
            }

            $sdb->update('matches', [
                'status' => 'in_progress',
                'started_at' => gmdate('c')
            ], ['id' => 'eq.' . $matchId]);

            $match = $matches[0];
            $color = ($match['white_player_id'] === $userId) ? 'w' : 'b';

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

    if ($action === 'decline-invite') {
        $matchId = $input['match_id'] ?? '';
        $gameKey = $input['game_key'] ?? '';
        if (!$matchId) jsonError('match_id required');

        if ($gameKey === 'domino') {
            $matches = $sdb->get('domino_matches', [
                'id' => 'eq.' . $matchId,
                'status' => 'eq.waiting',
                'select' => 'id,game_state',
                'limit' => 1
            ]);
            if (!is_array($matches) || isset($matches['error']) || empty($matches)) {
                jsonError('Invite not found or expired');
            }
            $gs = is_array($matches[0]['game_state']) ? $matches[0]['game_state'] : json_decode($matches[0]['game_state'] ?? '{}', true);
            if (($gs['invite_to'] ?? '') !== $userId) {
                jsonError('Not authorized to decline this invite', 403);
            }
            $sdb->update('domino_matches', [
                'status' => 'completed',
                'result' => 'declined'
            ], ['id' => 'eq.' . $matchId, 'status' => 'eq.waiting']);
        } elseif ($gameKey === 'ludo') {
            $matches = $sdb->get('ludo_matches', [
                'id' => 'eq.' . $matchId,
                'status' => 'eq.waiting',
                'select' => 'id,game_state',
                'limit' => 1
            ]);
            if (!is_array($matches) || isset($matches['error']) || empty($matches)) {
                jsonError('Invite not found or expired');
            }
            $gs = is_array($matches[0]['game_state']) ? $matches[0]['game_state'] : json_decode($matches[0]['game_state'] ?? '{}', true);
            if (($gs['invite_to'] ?? '') !== $userId) {
                jsonError('Not authorized to decline this invite', 403);
            }
            $sdb->update('ludo_matches', [
                'status' => 'completed',
                'result' => 'declined'
            ], ['id' => 'eq.' . $matchId, 'status' => 'eq.waiting']);
        } elseif ($gameKey === 'backgammon') {
            $matches = $sdb->get('backgammon_matches', [
                'id' => 'eq.' . $matchId,
                'status' => 'eq.waiting',
                'select' => 'id,game_state',
                'limit' => 1
            ]);
            if (!is_array($matches) || isset($matches['error']) || empty($matches)) {
                jsonError('Invite not found or expired');
            }
            $gs = is_array($matches[0]['game_state']) ? $matches[0]['game_state'] : json_decode($matches[0]['game_state'] ?? '{}', true);
            if (($gs['invite_to'] ?? '') !== $userId) {
                jsonError('Not authorized to decline this invite', 403);
            }
            $sdb->update('backgammon_matches', [
                'status' => 'completed',
                'result' => 'declined'
            ], ['id' => 'eq.' . $matchId, 'status' => 'eq.waiting']);
        } else {
            $matches = $sdb->get('matches', [
                'id' => 'eq.' . $matchId,
                'status' => 'eq.waiting',
                'select' => 'id,game_state',
                'limit' => 1
            ]);
            if (!is_array($matches) || isset($matches['error']) || empty($matches)) {
                jsonError('Invite not found or expired');
            }
            $gs = is_array($matches[0]['game_state']) ? $matches[0]['game_state'] : json_decode($matches[0]['game_state'] ?? '{}', true);
            if (($gs['invite_to'] ?? '') !== $userId) {
                jsonError('Not authorized to decline this invite', 403);
            }
            $sdb->update('matches', [
                'status' => 'completed',
                'result' => 'declined'
            ], ['id' => 'eq.' . $matchId, 'status' => 'eq.waiting']);
        }

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

    jsonError('Invalid action');
}

if ($method === 'DELETE') {
    $input = getInput();
    $targetId = $input['target_id'] ?? '';
    if (!$targetId) jsonError('target_id required');

    $sdb->delete('friendships', [
        'or' => "(and(requester_id.eq.{$userId},addressee_id.eq.{$targetId}),and(requester_id.eq.{$targetId},addressee_id.eq.{$userId}))"
    ]);
    jsonResponse(['success' => true]);
}

jsonError('Invalid request', 400);
