<?php
/**
 * ajax/processa_premios.php
 *
 * Processa e distribui os prêmios de uma sala que foi fechada por bingo.
 *
 * POST JSON { sala_id }
 *
 * Lógica:
 *   1. Busca sala com status = 'bingo_fechado' (FOR UPDATE)
 *   2. Para cada cartela da sala calcula:
 *        - Quadra  (4 marcações em linha/coluna/diagonal) → premio_quadra
 *        - Quina   (5 marcações em linha/coluna/diagonal) → premio_quina
 *        - Cartela cheia (25 marcações)                   → premio_cartela_cheia
 *   3. Credita saldo (FOR UPDATE no bet_usuarios)
 *   4. Registra transações
 *   5. Marca sala como 'finalizado'
 *
 * Resposta:
 *   { status: "success", saldo, saldo_float, premio_ganho }
 *     premio_ganho é o prêmio do usuário que fez a requisição (se tiver ganhou)
 */

if (session_status() === PHP_SESSION_NONE) session_start();

// ─── AUTH ─────────────────────────────────────────────────────
if (!isset($_SESSION['usuario_id'])) {
    require_once '../../../includes/db.php';
    if (isset($_COOKIE['auth_token'])) {
        $stmt = $pdo->prepare("SELECT id, bet_status FROM bet_usuarios WHERE bet_token = ?");
        $stmt->execute([$_COOKIE['auth_token']]);
        $u = $stmt->fetch(PDO::FETCH_ASSOC);
        if ($u && $u['bet_status'] == 1) $_SESSION['usuario_id'] = $u['id'];
    }
    if (!isset($_SESSION['usuario_id'])) {
        http_response_code(401);
        exit(json_encode(['status' => 'erro', 'message' => 'Não autenticado']));
    }
}

require_once '../../../includes/db.php';

// ─── LOG ──────────────────────────────────────────────────────
$logDir = __DIR__ . '/../logs';
if (!is_dir($logDir)) @mkdir($logDir, 0775, true);
function logPremio(string $msg): void {
    global $logDir;
    error_log("[".date('Y-m-d H:i:s')."] $msg\n", 3, $logDir.'/bingo_premios.log');
}

// ─── ENTRADA ──────────────────────────────────────────────────
$input   = json_decode(file_get_contents('php://input'), true) ?: [];
$sala_id = (int)($input['sala_id'] ?? 0);
if ($sala_id <= 0) {
    exit(json_encode(['status' => 'erro', 'message' => 'sala_id inválido']));
}

// ─── PADRÕES DE VITÓRIA ───────────────────────────────────────
/**
 * Cartela = array de 25 números, lido na ordem:
 *   Linha 0: índices  0– 4
 *   Linha 1: índices  5– 9
 *   Linha 2: índices 10–14
 *   Linha 3: índices 15–19
 *   Linha 4: índices 20–24
 *
 * Coluna 0: [0,5,10,15,20]
 * Coluna 1: [1,6,11,16,21] …
 * Diagonal principal: [0,6,12,18,24]
 * Diagonal secundária:[4,8,12,16,20]
 */
function getPatterns(): array {
    $patterns = [];
    // 5 linhas
    for ($i = 0; $i < 5; $i++) {
        $patterns[] = ['id' => "L{$i}", 'indices' => [$i*5, $i*5+1, $i*5+2, $i*5+3, $i*5+4]];
    }
    // 5 colunas
    for ($i = 0; $i < 5; $i++) {
        $patterns[] = ['id' => "C{$i}", 'indices' => [$i, $i+5, $i+10, $i+15, $i+20]];
    }
    // diagonais
    $patterns[] = ['id' => 'D0', 'indices' => [0,6,12,18,24]];
    $patterns[] = ['id' => 'D1', 'indices' => [4,8,12,16,20]];
    return $patterns;
}

/**
 * Analisa uma cartela e retorna os prêmios devidos.
 * Retorna array com 'quadra', 'quina', 'cartela_cheia' booleans.
 *
 * Regras:
 *   - Cartela cheia: todos os 25 números marcados
 *   - Quina: exatamente 5 marcações em um padrão (linha/coluna/diagonal)
 *   - Quadra: exatamente 4 marcações em um padrão
 *   - Um mesmo padrão não gera Quadra E Quina ao mesmo tempo
 *   - Cada padrão gera no máximo um prêmio (o maior)
 *   - Cartela cheia > Quina > Quadra (não se acumulam dentro da mesma cartela)
 */
function analyzeCartela(array $numeros, array $sorteados): array {
    $set = array_flip($sorteados); // O(1) lookup
    $result = ['quadra' => false, 'quina' => false, 'cartela_cheia' => false];

    // Verifica cartela cheia
    $marcados = 0;
    foreach ($numeros as $n) {
        if (isset($set[$n])) $marcados++;
    }
    if ($marcados >= 25) {
        $result['cartela_cheia'] = true;
        return $result; // Cartela cheia inclui tudo
    }

    $patterns = getPatterns();
    foreach ($patterns as $p) {
        $hits = 0;
        foreach ($p['indices'] as $idx) {
            if (isset($set[$numeros[$idx]])) $hits++;
        }
        if ($hits === 5 && !$result['quina']) {
            $result['quina'] = true;
        } elseif ($hits === 4 && !$result['quina'] && !$result['quadra']) {
            $result['quadra'] = true;
        }
    }
    return $result;
}

// ─── TRANSAÇÃO PRINCIPAL ──────────────────────────────────────
try {
    $pdo->beginTransaction();

    // Lock da sala
    $stmt = $pdo->prepare("SELECT * FROM salas_bingo WHERE id = ? FOR UPDATE");
    $stmt->execute([$sala_id]);
    $sala = $stmt->fetch(PDO::FETCH_ASSOC);

    if (!$sala) {
        $pdo->rollBack();
        exit(json_encode(['status' => 'erro', 'message' => 'Sala não encontrada']));
    }

    // Apenas processa se estiver em bingo_fechado ou em_andamento com 75 bolas
    $numeros_sorteados = json_decode($sala['numeros_sorteados'], true) ?: [];

    if ($sala['status'] === 'finalizado') {
        // Já processado — retorna saldo atual do usuário
        $pdo->rollBack();
        $stmt = $pdo->prepare("SELECT bet_saldo FROM bet_usuarios WHERE id = ?");
        $stmt->execute([$_SESSION['usuario_id']]);
        $saldo = (float)$stmt->fetchColumn();

        // Busca prêmio do usuário nesta sala
        $stmt = $pdo->prepare("SELECT COALESCE(SUM(valor),0) FROM transacoes WHERE usuario_id = ? AND sala_id = ? AND tipo = 'premio_bingo'");
        $stmt->execute([$_SESSION['usuario_id'], $sala_id]);
        $premio = (float)$stmt->fetchColumn();

        exit(json_encode([
            'status'       => 'success',
            'saldo'        => number_format($saldo, 2, ',', '.'),
            'saldo_float'  => $saldo,
            'premio_ganho' => $premio > 0 ? number_format($premio, 2, ',', '.') : null,
            'saldo_atual'  => number_format($saldo, 2, ',', '.')
        ]));
    }

    if ($sala['status'] !== 'bingo_fechado' && count($numeros_sorteados) < 75) {
        $pdo->rollBack();
        exit(json_encode(['status' => 'erro', 'message' => 'Sala ainda não está pronta para processar prêmios']));
    }

    logPremio("Iniciando processamento de prêmios — sala #{$sala_id}, bolas sorteadas: " . count($numeros_sorteados));

    // ─── BUSCA TODAS AS CARTELAS DA SALA ────────────────────────
    $stmt = $pdo->prepare("SELECT * FROM cartelas_compradas WHERE sala_id = ?");
    $stmt->execute([$sala_id]);
    $cartelas = $stmt->fetchAll(PDO::FETCH_ASSOC);

    logPremio("Total de cartelas na sala: " . count($cartelas));

    // ─── ANALISA CADA CARTELA ───────────────────────────────────
    // Agrupa prêmios por usuário para crédito em um único lock
    $premios_por_usuario = []; // usuario_id => { total, detalhes[] }

    foreach ($cartelas as $cartela) {
        $numeros = json_decode($cartela['numeros'], true);
        if (!$numeros || count($numeros) < 25) continue;

        $resultado = analyzeCartela($numeros, $numeros_sorteados);

        $premio_valor = 0.0;
        $descricao    = '';

        if ($resultado['cartela_cheia']) {
            $premio_valor = (float)$sala['premio_cartela_cheia'];
            $descricao    = "Cartela cheia (Bingo!) — Cartela #{$cartela['id']}";
        } elseif ($resultado['quina']) {
            $premio_valor = (float)$sala['premio_quina'];
            $descricao    = "Quina — Cartela #{$cartela['id']}";
        } elseif ($resultado['quadra']) {
            $premio_valor = (float)$sala['premio_quadra'];
            $descricao    = "Quadra — Cartela #{$cartela['id']}";
        }

        if ($premio_valor > 0) {
            $uid = $cartela['usuario_id'];
            if (!isset($premios_por_usuario[$uid])) {
                $premios_por_usuario[$uid] = ['total' => 0.0, 'detalhes' => []];
            }
            $premios_por_usuario[$uid]['total'] += $premio_valor;
            $premios_por_usuario[$uid]['detalhes'][] = [
                'valor'     => $premio_valor,
                'descricao' => $descricao,
                'cartela_id'=> $cartela['id']
            ];
            logPremio("  → Prêmio encontrado: {$descricao} = R$ " . number_format($premio_valor, 2, ',', '.'));
        }
    }

    // ─── CREDITA SALDOS ─────────────────────────────────────────
    foreach ($premios_por_usuario as $uid => $dados) {
        // Lock do usuário
        $stmt = $pdo->prepare("SELECT bet_saldo FROM bet_usuarios WHERE id = ? FOR UPDATE");
        $stmt->execute([$uid]);
        $saldo_atual = (float)$stmt->fetchColumn();

        $novo_saldo = $saldo_atual + $dados['total'];

        // Atualiza saldo
        $pdo->prepare("UPDATE bet_usuarios SET bet_saldo = ? WHERE id = ?")
            ->execute([$novo_saldo, $uid]);

        // Insere transação por cada prêmio individual
        foreach ($dados['detalhes'] as $det) {
            $saldo_antes = $saldo_atual;
            $pdo->prepare("INSERT INTO transacoes (usuario_id, tipo, valor, saldo_anterior, saldo_atual, descricao, sala_id) VALUES (?, 'premio_bingo', ?, ?, ?, ?, ?)")
                ->execute([$uid, $det['valor'], $saldo_antes, $saldo_antes + $det['valor'], $det['descricao'], $sala_id]);
            $saldo_atual += $det['valor']; // atualiza para a próxima transação
        }

        logPremio("  Usuário #{$uid}: saldo {$saldo_antes} → {$novo_saldo} (prêmio total: R$ " . number_format($dados['total'], 2, ',', '.') . ")");
    }

    // ─── MARCA SALA COMO FINALIZADO ─────────────────────────────
    $pdo->prepare("UPDATE salas_bingo SET status = 'finalizado', fim_jogo = NOW() WHERE id = ?")
        ->execute([$sala_id]);

    logPremio("Sala #{$sala_id} finalizada com sucesso.");

    $pdo->commit();

    // ─── RETORNA DADOS DO USUÁRIO ATUAL ─────────────────────────
    $stmt = $pdo->prepare("SELECT bet_saldo FROM bet_usuarios WHERE id = ?");
    $stmt->execute([$_SESSION['usuario_id']]);
    $meu_saldo = (float)$stmt->fetchColumn();

    $meu_premio = 0.0;
    if (isset($premios_por_usuario[$_SESSION['usuario_id']])) {
        $meu_premio = $premios_por_usuario[$_SESSION['usuario_id']]['total'];
    }

    exit(json_encode([
        'status'       => 'success',
        'saldo'        => number_format($meu_saldo, 2, ',', '.'),
        'saldo_float'  => $meu_saldo,
        'premio_ganho' => $meu_premio > 0 ? number_format($meu_premio, 2, ',', '.') : null,
        'saldo_atual'  => number_format($meu_saldo, 2, ',', '.')
    ]));

} catch (Throwable $e) {
    if ($pdo->inTransaction()) $pdo->rollBack();
    logPremio("ERRO: " . $e->getMessage());
    exit(json_encode(['status' => 'erro', 'message' => 'Erro interno ao processar prêmios']));
}
