<?php
declare(strict_types=1);

require_once __DIR__ . '/bootstrap.php';
require_once __DIR__ . '/db.php';
require_once __DIR__ . '/blackjack_engine.php';
require_once __DIR__ . '/games_settings_helpers.php';
require_once __DIR__ . '/level_lib.php';

header('Content-Type: application/json; charset=utf-8');

$uid = isset($_SESSION['mocker_user_id']) ? (int) $_SESSION['mocker_user_id'] : 0;
$method = $_SERVER['REQUEST_METHOD'] ?? 'GET';

try {
    $pdo = mocker_db();
} catch (Throwable $e) {
    http_response_code(503);
    echo json_encode(['ok' => false, 'error' => 'db'], JSON_UNESCAPED_UNICODE);
    exit;
}

function bj_load_state(PDO $pdo, int $uid): ?array
{
    $st = $pdo->prepare('SELECT state_json FROM blackjack_state WHERE user_id = :id LIMIT 1');
    $st->execute([':id' => $uid]);
    $row = $st->fetch();
    if (!$row || !isset($row['state_json'])) {
        return null;
    }
    $j = json_decode((string) $row['state_json'], true);

    return is_array($j) ? $j : null;
}

function bj_save_state(PDO $pdo, int $uid, array $state): void
{
    $json = json_encode($state, JSON_UNESCAPED_UNICODE);
    if ($json === false) {
        throw new RuntimeException('state json');
    }
    $now = time();
    $up = $pdo->prepare('INSERT OR REPLACE INTO blackjack_state (user_id, state_json, updated_at) VALUES (:id, :js, :t)');
    $up->execute([':id' => $uid, ':js' => $json, ':t' => $now]);
}

function bj_clear_state(PDO $pdo, int $uid): void
{
    $pdo->prepare('DELETE FROM blackjack_state WHERE user_id = :id')->execute([':id' => $uid]);
}

function bj_public_state(array $s, bool $authenticated): array
{
    $out = [
        'phase' => $s['phase'] ?? 'bet',
        'bet' => (int) ($s['bet'] ?? 0),
        'doubled' => !empty($s['doubled']),
        'playerCards' => $s['player'] ?? [],
        'dealerCards' => $s['dealer'] ?? [],
        'dealerHoleHidden' => !empty($s['dealer_hole_hidden']),
        'outcome' => $s['outcome'] ?? null,
        'message' => (string) ($s['message'] ?? ''),
        'canHit' => ($s['phase'] ?? '') === 'play' && empty($s['doubled']) && bj_hand_value($s['player'] ?? [])['total'] < 21,
        'canStand' => ($s['phase'] ?? '') === 'play',
        'canDouble' => ($s['phase'] ?? '') === 'play'
            && empty($s['doubled'])
            && isset($s['player'])
            && count($s['player']) === 2
            && bj_hand_value($s['player'])['total'] <= 21,
    ];
    if (!$authenticated) {
        $out['playerCards'] = [];
        $out['dealerCards'] = [];
    }

    return $out;
}

function bj_compare_hands(array $player, array $dealer): array
{
    $pv = bj_hand_value($player)['total'];
    $dv = bj_hand_value($dealer)['total'];
    if ($pv > 21) {
        return ['outcome' => 'lose', 'message' => 'Bust oldun.'];
    }
    if ($dv > 21) {
        return ['outcome' => 'win', 'message' => 'Krupiye bust — kazandın!'];
    }
    if ($pv > $dv) {
        return ['outcome' => 'win', 'message' => 'Elin krupiyeden büyük.'];
    }
    if ($pv < $dv) {
        return ['outcome' => 'lose', 'message' => 'Krupiye kazandı.'];
    }

    return ['outcome' => 'push', 'message' => 'Berabere (push).'];
}

function bj_finish_round(PDO $pdo, int $uid, array &$state, string $outcome, string $message): void
{
    $bet = (int) ($state['bet'] ?? 0);
    $doubled = !empty($state['doubled']);
    $totalIn = $doubled ? 2 * $bet : $bet;

    $payout = 0;
    if ($outcome === 'blackjack') {
        $payout = (int) floor($bet * 2.5);
        $message = 'Blackjack! 3:2 ödeme.';
    } elseif ($outcome === 'win') {
        $payout = 2 * $totalIn;
    } elseif ($outcome === 'push') {
        $payout = $totalIn;
    }

    $st = $pdo->prepare('SELECT coins FROM users WHERE id = :id LIMIT 1');
    $st->execute([':id' => $uid]);
    $coins = (int) ($st->fetch()['coins'] ?? 0);

    $coins += $payout;

    $up = $pdo->prepare('UPDATE users SET coins = :c WHERE id = :id');
    $up->execute([':c' => $coins, ':id' => $uid]);

    try {
        $roundId = 0;
        $ins = $pdo->prepare(
            'INSERT INTO blackjack_rounds (user_id, created_at, bet, doubled, outcome, stake, payout)
             VALUES (:uid, :t, :bet, :dbl, :oc, :stake, :pay)'
        );
        $ins->execute([
            ':uid' => $uid,
            ':t' => time(),
            ':bet' => $bet,
            ':dbl' => $doubled ? 1 : 0,
            ':oc' => $outcome,
            ':stake' => $totalIn,
            ':pay' => $payout,
        ]);
        $roundId = (int) $pdo->lastInsertId();
        if ($roundId > 0) {
            mocker_level_award_game_round($pdo, $uid, 'blackjack', $roundId);
        }
    } catch (Throwable $e) {
        error_log('blackjack_rounds: ' . $e->getMessage());
    }

    $state['phase'] = 'done';
    $state['outcome'] = $outcome;
    $state['message'] = $message;
    $state['dealer_hole_hidden'] = false;
}

if ($method === 'GET') {
    if ($uid <= 0) {
        echo json_encode(
            [
                'ok' => true,
                'authenticated' => false,
                'minBet' => BJ_MIN_BET,
                'maxBet' => BJ_MAX_BET,
            ],
            JSON_UNESCAPED_UNICODE
        );
        exit;
    }
    $st = $pdo->prepare('SELECT coins FROM users WHERE id = :id LIMIT 1');
    $st->execute([':id' => $uid]);
    $row = $st->fetch();
    if (!$row) {
        http_response_code(404);
        echo json_encode(['ok' => false, 'error' => 'user'], JSON_UNESCAPED_UNICODE);
        exit;
    }
    $coins = (int) $row['coins'];
    $state = bj_load_state($pdo, $uid);
    if ($state === null) {
        $state = ['phase' => 'bet', 'message' => 'Bahis seç ve dağıt.'];
    }
    echo json_encode(
        [
            'ok' => true,
            'authenticated' => true,
            'coins' => $coins,
            'minBet' => BJ_MIN_BET,
            'maxBet' => BJ_MAX_BET,
            'game' => bj_public_state($state, true),
        ],
        JSON_UNESCAPED_UNICODE
    );
    exit;
}

if ($method !== 'POST') {
    http_response_code(405);
    echo json_encode(['ok' => false, 'error' => 'method'], JSON_UNESCAPED_UNICODE);
    exit;
}

mocker_require_csrf_post();

if ($uid <= 0) {
    http_response_code(401);
    echo json_encode(['ok' => false, 'error' => 'auth'], JSON_UNESCAPED_UNICODE);
    exit;
}

$input = json_decode((string) file_get_contents('php://input'), true) ?: [];
$action = strtolower(trim((string) ($input['action'] ?? '')));

try {
    $pdo->beginTransaction();

    $stUser = $pdo->prepare('SELECT coins FROM users WHERE id = :id LIMIT 1');
    $stUser->execute([':id' => $uid]);
    $urow = $stUser->fetch();
    if (!$urow) {
        $pdo->rollBack();
        http_response_code(404);
        echo json_encode(['ok' => false, 'error' => 'user'], JSON_UNESCAPED_UNICODE);
        exit;
    }
    $coins = (int) $urow['coins'];

    $state = bj_load_state($pdo, $uid);
    if ($state === null) {
        $state = ['phase' => 'bet', 'message' => ''];
    }

    if ($action === 'deal' || $action === 'new_hand') {
        if (($state['phase'] ?? '') === 'play') {
            $pdo->rollBack();
            echo json_encode(['ok' => false, 'error' => 'in_progress', 'message' => 'Önce bu eli bitir (dur / çek).'], JSON_UNESCAPED_UNICODE);
            exit;
        }

        $bet = (int) ($input['bet'] ?? 0);
        if ($bet < BJ_MIN_BET || $bet > BJ_MAX_BET) {
            $pdo->rollBack();
            echo json_encode(['ok' => false, 'error' => 'bet_range', 'min' => BJ_MIN_BET, 'max' => BJ_MAX_BET], JSON_UNESCAPED_UNICODE);
            exit;
        }
        if ($coins < $bet) {
            $pdo->rollBack();
            echo json_encode(['ok' => false, 'error' => 'coins'], JSON_UNESCAPED_UNICODE);
            exit;
        }

        $deck = bj_new_shoe();
        bj_shuffle($deck);
        $p1 = bj_draw($deck);
        $d1 = bj_draw($deck);
        $p2 = bj_draw($deck);
        $d2 = bj_draw($deck);

        $upd = $pdo->prepare('UPDATE users SET coins = coins - :b WHERE id = :id AND coins >= :b');
        $upd->execute([':b' => $bet, ':id' => $uid]);
        if ($upd->rowCount() !== 1) {
            $pdo->rollBack();
            echo json_encode(['ok' => false, 'error' => 'coins'], JSON_UNESCAPED_UNICODE);
            exit;
        }

        $player = [$p1, $p2];
        $dealer = [$d1, $d2];
        $pBJ = bj_is_blackjack($player);
        $dBJ = bj_is_blackjack($dealer);

        $state = [
            'phase' => 'play',
            'deck' => $deck,
            'player' => $player,
            'dealer' => $dealer,
            'bet' => $bet,
            'doubled' => false,
            'dealer_hole_hidden' => true,
            'outcome' => null,
            'message' => '',
        ];

        if ($pBJ && $dBJ) {
            bj_finish_round($pdo, $uid, $state, 'push', 'İkiniz de blackjack — berabere.');
        } elseif ($pBJ && !$dBJ) {
            bj_finish_round($pdo, $uid, $state, 'blackjack', 'Blackjack!');
        } elseif (!$pBJ && $dBJ) {
            bj_finish_round($pdo, $uid, $state, 'lose', 'Krupiye blackjack — kaybettin.');
        } else {
            $state['phase'] = 'play';
            $state['message'] = 'Sıra sende: çek veya dur.';
        }

        bj_save_state($pdo, $uid, $state);
        $pdo->commit();

        $st2 = $pdo->prepare('SELECT coins FROM users WHERE id = :id LIMIT 1');
        $st2->execute([':id' => $uid]);
        $coinsAfter = (int) ($st2->fetch()['coins'] ?? 0);

        echo json_encode(
            [
                'ok' => true,
                'coins' => $coinsAfter,
                'game' => bj_public_state($state, true),
            ],
            JSON_UNESCAPED_UNICODE
        );
        exit;
    }

    if (($state['phase'] ?? '') !== 'play') {
        $pdo->rollBack();
        echo json_encode(['ok' => false, 'error' => 'phase', 'message' => 'Önce yeni el başlat.'], JSON_UNESCAPED_UNICODE);
        exit;
    }

    $deck = $state['deck'] ?? [];
    $player = $state['player'] ?? [];
    $dealer = $state['dealer'] ?? [];
    $bet = (int) ($state['bet'] ?? 0);

    if ($action === 'hit') {
        if (!empty($state['doubled'])) {
            $pdo->rollBack();
            echo json_encode(['ok' => false, 'error' => 'phase'], JSON_UNESCAPED_UNICODE);
            exit;
        }
        $player[] = bj_draw($deck);
        $state['player'] = $player;
        $state['deck'] = $deck;

        $pv = bj_hand_value($player)['total'];
        if ($pv > 21) {
            bj_finish_round($pdo, $uid, $state, 'lose', 'Bust (' . $pv . ').');
        } elseif ($pv === 21) {

            $state['dealer_hole_hidden'] = false;
            while (bj_dealer_should_hit($dealer)) {
                $dealer[] = bj_draw($deck);
            }
            $state['dealer'] = $dealer;
            $state['deck'] = $deck;
            $cmp = bj_compare_hands($player, $dealer);
            bj_finish_round($pdo, $uid, $state, $cmp['outcome'], $cmp['message']);
        } else {
            $state['message'] = 'Devam edebilir veya durabilirsin.';
        }

        bj_save_state($pdo, $uid, $state);
        $pdo->commit();

        $st2 = $pdo->prepare('SELECT coins FROM users WHERE id = :id LIMIT 1');
        $st2->execute([':id' => $uid]);
        $coinsAfter = (int) ($st2->fetch()['coins'] ?? 0);

        echo json_encode(
            [
                'ok' => true,
                'coins' => $coinsAfter,
                'game' => bj_public_state($state, true),
            ],
            JSON_UNESCAPED_UNICODE
        );
        exit;
    }

    if ($action === 'double') {
        if (!empty($state['doubled']) || count($player) !== 2) {
            $pdo->rollBack();
            echo json_encode(['ok' => false, 'error' => 'double'], JSON_UNESCAPED_UNICODE);
            exit;
        }
        if ($coins < $bet) {
            $pdo->rollBack();
            echo json_encode(['ok' => false, 'error' => 'coins'], JSON_UNESCAPED_UNICODE);
            exit;
        }
        $upd = $pdo->prepare('UPDATE users SET coins = coins - :b WHERE id = :id AND coins >= :b');
        $upd->execute([':b' => $bet, ':id' => $uid]);
        if ($upd->rowCount() !== 1) {
            $pdo->rollBack();
            echo json_encode(['ok' => false, 'error' => 'coins'], JSON_UNESCAPED_UNICODE);
            exit;
        }
        $state['doubled'] = true;
        $player[] = bj_draw($deck);
        $state['player'] = $player;
        $state['deck'] = $deck;
        $state['dealer_hole_hidden'] = false;

        $pv = bj_hand_value($player)['total'];
        if ($pv > 21) {
            bj_finish_round($pdo, $uid, $state, 'lose', 'Çift — bust.');
        } else {
            while (bj_dealer_should_hit($dealer)) {
                $dealer[] = bj_draw($deck);
            }
            $state['dealer'] = $dealer;
            $state['deck'] = $deck;
            $cmp = bj_compare_hands($player, $dealer);
            $msg = $cmp['message'];
            if ($cmp['outcome'] === 'win') {
                $msg = 'Çift — kazandın!';
            } elseif ($cmp['outcome'] === 'push') {
                $msg = 'Çift — berabere.';
            } elseif ($cmp['outcome'] === 'lose') {
                $msg = 'Çift — kaybettin.';
            }
            bj_finish_round($pdo, $uid, $state, $cmp['outcome'], $msg);
        }

        bj_save_state($pdo, $uid, $state);
        $pdo->commit();

        $st2 = $pdo->prepare('SELECT coins FROM users WHERE id = :id LIMIT 1');
        $st2->execute([':id' => $uid]);
        $coinsAfter = (int) ($st2->fetch()['coins'] ?? 0);

        echo json_encode(
            [
                'ok' => true,
                'coins' => $coinsAfter,
                'game' => bj_public_state($state, true),
            ],
            JSON_UNESCAPED_UNICODE
        );
        exit;
    }

    if ($action === 'stand') {
        $state['dealer_hole_hidden'] = false;
        while (bj_dealer_should_hit($dealer)) {
            $dealer[] = bj_draw($deck);
        }
        $state['dealer'] = $dealer;
        $state['deck'] = $deck;

        $cmp = bj_compare_hands($player, $dealer);
        bj_finish_round($pdo, $uid, $state, $cmp['outcome'], $cmp['message']);

        bj_save_state($pdo, $uid, $state);
        $pdo->commit();

        $st2 = $pdo->prepare('SELECT coins FROM users WHERE id = :id LIMIT 1');
        $st2->execute([':id' => $uid]);
        $coinsAfter = (int) ($st2->fetch()['coins'] ?? 0);

        echo json_encode(
            [
                'ok' => true,
                'coins' => $coinsAfter,
                'game' => bj_public_state($state, true),
            ],
            JSON_UNESCAPED_UNICODE
        );
        exit;
    }

    if ($action === 'clear') {
        bj_clear_state($pdo, $uid);
        $pdo->commit();
        $st2 = $pdo->prepare('SELECT coins FROM users WHERE id = :id LIMIT 1');
        $st2->execute([':id' => $uid]);
        $coinsAfter = (int) ($st2->fetch()['coins'] ?? 0);
        echo json_encode(
            [
                'ok' => true,
                'coins' => $coinsAfter,
                'game' => bj_public_state(['phase' => 'bet', 'message' => ''], true),
            ],
            JSON_UNESCAPED_UNICODE
        );
        exit;
    }

    $pdo->rollBack();
    echo json_encode(['ok' => false, 'error' => 'action'], JSON_UNESCAPED_UNICODE);
} catch (Throwable $e) {
    if ($pdo->inTransaction()) {
        $pdo->rollBack();
    }
    error_log('game_blackjack: ' . $e->getMessage());
    http_response_code(500);
    echo json_encode(['ok' => false, 'error' => 'server'], JSON_UNESCAPED_UNICODE);
}
