<?php
session_start();
include 'cfg.php';
if (!isset($_SESSION['voucher_code']) || !isset($_SESSION['selected_circles'])) {
    if (isset($_SESSION['voucher_code'])) {
        $resumeStmt = $pdo->prepare("SELECT circle_count FROM game_state WHERE voucher_code = ?");
        $resumeStmt->execute([$_SESSION['voucher_code']]);
        $resumeState = $resumeStmt->fetch();
        if ($resumeState) {
            $_SESSION['selected_circles'] = (int) $resumeState['circle_count'];
        } else {
            header("Location: wheel.php");
            exit();
        }
    } else {
        header("Location: index.php");
        exit();
    }
}
$voucher_code = $_SESSION['voucher_code'];
$selected_circles = max((int) $_SESSION['selected_circles'], 3);
$stmt = $pdo->prepare("SELECT * FROM vouchers WHERE code = ?");
$stmt->execute([$voucher_code]);
$voucher = $stmt->fetch();
if (!$voucher) {
    header("Location: index.php");
    exit();
}
$is_winner = (int) $voucher['is_winner'];
$user_name = $voucher['used_by'] ?? 'User';
$circle_count = (int) $voucher['circle_count'];
$bomb_click = (int) $voucher['bomb_position'];
$selected_circles = max($circle_count, 3);
$gameStmt = $pdo->prepare("SELECT * FROM game_state WHERE voucher_code = ?");
$gameStmt->execute([$voucher_code]);
$gameState = $gameStmt->fetch();
if (!$gameState) {
    $initStmt = $pdo->prepare("INSERT INTO game_state (voucher_code, circle_count, bomb_position, opened_circles, game_over)
                              VALUES (?, ?, ?, '', 0)");
    $initStmt->execute([$voucher_code, $selected_circles, $bomb_click]);
    $openedCircles = [];
    $game_over = 0;
} else {
    $openedCircles = !empty($gameState['opened_circles']) ? explode(',', $gameState['opened_circles']) : [];
    $openedCircles = array_map('intval', array_filter($openedCircles, 'is_numeric'));
    $game_over = (int) $gameState['game_over'];
}
$_SESSION['selected_circles'] = $selected_circles;
$_SESSION['is_winner'] = $is_winner;
$bomb_revealed_index = null;
if ($game_over && !$is_winner && !empty($openedCircles)) {
    $bomb_revealed_index = (int) end($openedCircles);
}
$safe_target = max($selected_circles - 1, 1);
$safe_found = count($openedCircles) - ($bomb_revealed_index !== null ? 1 : 0);
$safe_found = max($safe_found, 0);
$progress_percent = min(100, (int) round(($safe_found / $safe_target) * 100));
?>

<!DOCTYPE html>
<html lang="id">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Game Gosok Voucher</title>
    <style>
        :root {
            --bg-top: #10273d;
            --bg-bottom: #08111d;
            --panel: rgba(11, 24, 37, 0.82);
            --panel-border: rgba(255, 255, 255, 0.1);
            --gold-1: #f8df98;
            --gold-2: #e0a43d;
            --safe-1: #4fd78f;
            --safe-2: #1d8d62;
            --danger-1: #ff7a59;
            --danger-2: #b02e28;
            --text: #f8fbff;
            --muted: #aac0d1;
            --shadow: rgba(0, 0, 0, 0.35);
        }
        * {
            box-sizing: border-box;
        }
        body {
            margin: 0;
            min-height: 100vh;
            padding: 14px 10px 30px;
            font-family: "Trebuchet MS", "Segoe UI", sans-serif;
            color: var(--text);
            background:
                radial-gradient(circle at top, rgba(223, 159, 54, 0.12), transparent 22%),
                radial-gradient(circle at bottom right, rgba(45, 121, 199, 0.12), transparent 26%),
                linear-gradient(180deg, var(--bg-top), var(--bg-bottom));
        }
        .page-shell {
            width: 100%;
            max-width: 1060px;
            margin: 0 auto;
        }
        .navbar {
            display: flex;
            align-items: center;
            justify-content: space-between;
            gap: 16px;
            padding: 12px 16px;
            border: 1px solid var(--panel-border);
            border-radius: 18px;
            background: rgba(7, 17, 27, 0.72);
            backdrop-filter: blur(10px);
            box-shadow: 0 16px 30px rgba(0, 0, 0, 0.18);
        }
        .navbar-brand img {
            width: clamp(100px, 18vw, 130px);
            height: auto;
            display: block;
        }
        .navbar-title {
            font-size: 13px;
            font-weight: 800;
            letter-spacing: 0.1em;
            text-transform: uppercase;
            color: rgba(248, 251, 255, 0.72);
        }

        .hero {
            display: flex;
            flex-direction: column;
            gap: 20px;
            margin-top: 18px;
        }

        /* Panel Informasi - Diperkecil & dipindah ke bawah */
        .panel {
            padding: 20px 18px;
            border: 1px solid var(--panel-border);
            border-radius: 24px;
            background: var(--panel);
            backdrop-filter: blur(12px);
            box-shadow: 0 20px 40px var(--shadow);
            order: 2;
        }

        /* Board Panel - Tetap di atas */
        .board-panel {
            padding: 20px;
            border: 1px solid var(--panel-border);
            border-radius: 28px;
            background: var(--panel);
            backdrop-filter: blur(12px);
            box-shadow: 0 26px 50px var(--shadow);
            order: 1;
        }

        .eyebrow {
            margin: 0 0 8px;
            color: var(--gold-1);
            font-size: 11px;
            font-weight: 800;
            letter-spacing: 0.14em;
            text-transform: uppercase;
        }
        h1 {
            margin: 0;
            font-size: 27px;
            line-height: 1.1;
        }
        .lead {
            margin: 12px 0 0;
            color: var(--muted);
            font-size: 14.5px;
            line-height: 1.6;
        }

        .stat-grid {
            display: grid;
            grid-template-columns: repeat(2, 1fr);
            gap: 10px;
            margin-top: 18px;
        }
        .stat-card {
            padding: 12px;
            border-radius: 16px;
            background: rgba(255, 255, 255, 0.05);
            border: 1px solid rgba(255, 255, 255, 0.08);
        }
        .stat-label {
            display: block;
            color: var(--muted);
            font-size: 11.5px;
            letter-spacing: 0.08em;
            text-transform: uppercase;
        }
        .stat-value {
            display: block;
            margin-top: 6px;
            color: #fff7df;
            font-size: 19px;
            font-weight: 900;
        }

        .progress-card {
            margin-top: 16px;
            padding: 14px;
            border-radius: 18px;
            background: rgba(255, 244, 219, 0.07);
            border: 1px solid rgba(255, 230, 180, 0.12);
        }
        .progress-head {
            display: flex;
            align-items: center;
            justify-content: space-between;
            gap: 12px;
            margin-bottom: 8px;
            color: #fff6e2;
            font-size: 13.5px;
            font-weight: 700;
        }
        .progress-bar {
            width: 100%;
            height: 10px;
            overflow: hidden;
            border-radius: 999px;
            background: rgba(255, 255, 255, 0.08);
        }
        .progress-bar span {
            display: block;
            height: 100%;
            width: 0;
            border-radius: inherit;
            background: linear-gradient(90deg, var(--gold-1), var(--gold-2));
            box-shadow: 0 0 16px rgba(224, 164, 61, 0.4);
            transition: width 0.35s ease;
        }

        .status-banner {
            margin-top: 16px;
            padding: 13px 16px;
            border-radius: 16px;
            background: rgba(255, 255, 255, 0.05);
            border: 1px solid rgba(255, 255, 255, 0.08);
            color: #eef6ff;
            font-size: 14.5px;
            font-weight: 700;
            min-height: 48px;
            display: flex;
            align-items: center;
        }
        .status-banner.win {
            color: #d7ffe9;
            background: rgba(79, 215, 143, 0.14);
            border-color: rgba(79, 215, 143, 0.24);
        }
        .status-banner.lose {
            color: #ffe1da;
            background: rgba(255, 122, 89, 0.14);
            border-color: rgba(255, 122, 89, 0.24);
        }

        .board-header {
            display: flex;
            align-items: center;
            justify-content: space-between;
            gap: 12px;
            margin-bottom: 18px;
        }
        .board-title {
            margin: 0;
            font-size: 23px;
            color: #fff8ea;
        }
        .board-subtitle {
            margin: 4px 0 0;
            color: var(--muted);
            font-size: 13.5px;
        }
        .board-chip {
            padding: 8px 14px;
            border-radius: 999px;
            background: rgba(255, 240, 211, 0.08);
            border: 1px solid rgba(255, 228, 176, 0.15);
            color: #fff1cf;
            font-size: 12.5px;
            font-weight: 700;
            white-space: nowrap;
        }

        .game-container {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(105px, 1fr));
            gap: 12px;
        }

        /* Token Styles */
        .token {
            position: relative;
            width: 100%;
            aspect-ratio: 1;
            border: none;
            padding: 0;
            cursor: pointer;
            background: transparent;
            transition: transform 0.2s ease;
        }
        .token:hover {
            transform: translateY(-4px);
        }
        .token:disabled {
            cursor: not-allowed;
            transform: none;
        }
        .token-shell,
        .token-core {
            position: absolute;
            inset: 0;
            border-radius: 50%;
        }
        .token-shell {
            background: linear-gradient(145deg, #5a260f 0%, #a94a1d 16%, #f7d98b 32%, #7e3513 48%, #3f1408 100%);
            box-shadow: inset 0 0 0 5px rgba(255, 240, 211, 0.25), 0 16px 24px rgba(0, 0, 0, 0.24);
        }
        .token-core {
            inset: 11px;
            display: flex;
            align-items: center;
            justify-content: center;
            background: radial-gradient(circle at 30% 30%, rgba(255,255,255,0.24), transparent 28%), linear-gradient(180deg, #234869, #15293f);
            box-shadow: inset 0 2px 10px rgba(255,255,255,0.08);
            overflow: hidden;
        }
        .token-core::before {
            content: "";
            position: absolute;
            inset: 0;
            background: radial-gradient(circle at center, rgba(255,255,255,0.06), transparent 58%);
        }
        .token-overlay-canvas {
            position: absolute;
            inset: 11px;
            z-index: 2;
            width: calc(100% - 22px);
            height: calc(100% - 22px);
            border-radius: 50%;
            touch-action: none;
            user-select: none;
            transition: opacity 0.3s ease, transform 0.3s ease;
        }
        .token.opened .token-overlay-canvas {
            opacity: 0;
            transform: scale(0.92);
            pointer-events: none;
        }
        .token-symbol {
            position: relative;
            z-index: 1;
            font-size: clamp(32px, 5vw, 42px);
            font-weight: 900;
            color: rgba(255, 255, 255, 0.95);
            transform: scale(0.9);
            transition: transform 0.25s ease;
        }
        .token.safe .token-core {
            background: radial-gradient(circle at 30% 30%, rgba(255,255,255,0.26), transparent 28%), linear-gradient(180deg, var(--safe-1), var(--safe-2));
        }
        .token.safe .token-symbol {
            color: #f6fffa;
            transform: scale(1);
        }
        .token.bomb .token-core {
            background: radial-gradient(circle at 30% 30%, rgba(255,255,255,0.2), transparent 28%), linear-gradient(180deg, var(--danger-1), var(--danger-2));
            box-shadow: 0 0 28px rgba(255, 122, 89, 0.32);
        }
        .token.bomb .token-symbol {
            color: #fff4ef;
            transform: scale(1.06);
        }
        .token-label {
            position: absolute;
            left: 50%;
            bottom: 10px;
            z-index: 3;
            transform: translateX(-50%);
            padding: 4px 10px;
            border-radius: 999px;
            background: rgba(6, 15, 24, 0.72);
            color: rgba(255, 255, 255, 0.84);
            font-size: 10.5px;
            font-weight: 800;
            letter-spacing: 0.08em;
            text-transform: uppercase;
        }
        .token.safe .token-label {
            color: #d7ffe9;
        }
        .token.bomb .token-label {
            color: #ffe1da;
        }
        .token.bomb {
            animation: bombShake 0.35s ease 2;
        }

        .scratch-particle {
            position: absolute;
            z-index: 4;
            width: 6px;
            height: 6px;
            margin-left: -3px;
            margin-top: -3px;
            border-radius: 50%;
            pointer-events: none;
            opacity: 0.88;
            background: radial-gradient(circle at 30% 30%, rgba(255,255,255,0.95), rgba(80,80,80,0.9) 42%, rgba(20,20,20,0.9) 100%);
            animation: scratchBurst 0.55s ease-out forwards;
        }

        .overlay {
            position: fixed;
            inset: 0;
            z-index: 1000;
            display: none;
            align-items: center;
            justify-content: center;
            padding: 20px;
            background: rgba(2, 7, 13, 0.84);
            backdrop-filter: blur(6px);
        }
        .overlay.show {
            display: flex;
        }
        .modal {
            width: min(100%, 420px);
            padding: 28px 24px;
            border-radius: 26px;
            border: 1px solid rgba(255, 255, 255, 0.12);
            background: linear-gradient(180deg, rgba(18, 35, 51, 0.98), rgba(7, 15, 24, 0.98));
            box-shadow: 0 24px 50px rgba(0, 0, 0, 0.35);
            text-align: center;
        }
        .modal-badge {
            width: 78px;
            height: 78px;
            margin: 0 auto 16px;
            border-radius: 50%;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 36px;
            font-weight: 900;
            color: #fff;
            background: linear-gradient(180deg, #f4ca68, #b9741f);
            box-shadow: 0 16px 24px rgba(0, 0, 0, 0.2);
        }
        .modal.lose .modal-badge {
            background: linear-gradient(180deg, #ff8d72, #b1342c);
        }
        .modal h3 {
            margin: 0;
            font-size: 30px;
            color: #fff8ea;
        }
        .modal-text {
            margin: 12px 0 18px;
            color: var(--muted);
            line-height: 1.65;
            font-size: 15px;
        }
        .modal-info {
            margin: 0;
            color: #ecf3fb;
            font-size: 14px;
            line-height: 1.7;
        }
        .modal-actions {
            display: grid;
            grid-template-columns: 1fr 1fr;
            gap: 10px;
            margin-top: 22px;
        }
        .btn {
            display: inline-flex;
            align-items: center;
            justify-content: center;
            min-height: 48px;
            padding: 12px 16px;
            border: none;
            border-radius: 14px;
            font-size: 14px;
            font-weight: 800;
            letter-spacing: 0.04em;
            text-decoration: none;
            cursor: pointer;
        }
        .btn-primary {
            color: #201106;
            background: linear-gradient(180deg, #ffe29f, #e1a53d);
        }
        .btn-secondary {
            color: #edf6ff;
            background: rgba(255, 255, 255, 0.08);
            border: 1px solid rgba(255, 255, 255, 0.1);
        }

        @keyframes bombShake {
            0% { transform: translateX(0); }
            25% { transform: translateX(-5px); }
            50% { transform: translateX(5px); }
            75% { transform: translateX(-3px); }
            100% { transform: translateX(0); }
        }
        @keyframes scratchBurst {
            0% {
                transform: translate(0, 0) scale(1);
                opacity: 0.88;
            }
            100% {
                transform: translate(var(--dx), var(--dy)) scale(0.2);
                opacity: 0;
            }
        }

        @media (max-width: 640px) {
            .hero { gap: 16px; }
            .panel { padding: 18px 16px; }
            h1 { font-size: 25px; }
            .game-container {
                grid-template-columns: repeat(3, minmax(0, 1fr));
                gap: 10px;
            }
            .modal-actions {
                grid-template-columns: 1fr;
            }
        }
    </style>
</head>
<body>
    <div class="page-shell">
        <header class="navbar">
            <div class="navbar-brand">
                <img src="logo.png" alt="Logo">
            </div>
            <div class="navbar-title">GOSOK BOM</div>
        </header>

        <section class="hero">
            <!-- BOARD GAME (di atas) -->
            <div class="board-panel">
                <div class="board-header">
                    <div>
                        <h2 class="board-title">GOSOK GOSOK BERHADIAH</h2>
                        <p class="board-subtitle">Gosok Satu Persatu, Jangan Sampai Terkena Bom.</p>
                    </div>
                    <div class="board-chip">Safe target: <?= $safe_target ?></div>
                </div>
                <div class="progress-card">
                    <div class="progress-head">
                        <span>Progress permainan</span>
                        <span id="progressText"><?= $safe_found ?> / <?= $safe_target ?></span>
                    </div>
                    <div class="progress-bar">
                        <span id="progressFill" style="width: <?= $progress_percent ?>%"></span>
                    </div>
                </div>
                <div class="game-container" id="gameBoard">
                    <?php for ($i = 0; $i < $selected_circles; $i++): ?>
                        <?php 
                            $is_opened = in_array($i, $openedCircles, true); 
                            $is_bomb_revealed = $bomb_revealed_index !== null && $i === $bomb_revealed_index; 
                        ?>
                        <button
                            class="token<?= $is_opened ? ' opened ' . ($is_bomb_revealed ? 'bomb' : 'safe') : '' ?>"
                            id="circle-<?= $i ?>"
                            type="button"
                            <?= $game_over ? 'disabled' : '' ?>
                        >
                            <span class="token-shell"></span>
                            <span class="token-core"></span>
                            <canvas class="token-overlay-canvas" id="scratch-<?= $i ?>" data-index="<?= $i ?>" style="<?= $is_opened ? 'opacity:0;transform:scale(0.92);' : '' ?>"></canvas>
                            <span class="token-symbol" id="content-<?= $i ?>"><?= $is_opened ? ($is_bomb_revealed ? '💣' : 'OK') : '?' ?></span>
                            <span class="token-label" id="label-<?= $i ?>"><?= $is_opened ? ($is_bomb_revealed ? 'Bomb' : 'Safe') : 'Hidden' ?></span>
                        </button>
                    <?php endfor; ?>
                </div>
            </div>

            <!-- PANEL INFORMASI (diperkecil & dipindah ke bawah) -->
            <div class="panel">
                <p class="eyebrow">GOSOK GOSOK BERHADIAH</p>
                <h1>Gosok Lingkaran, hindari bom dan sisakan 1 lingkaran terakhir yang berisi bom</h1>
                <p class="lead">Setiap lingkaran yang digosok akan menampilkan simbol OK atau BOM . Gesek semua lingkaran dan sisakan 1 lingkaran untuk menyelesaikan permainan.</p>
                
                <div class="stat-grid">
                    <div class="stat-card">
                        <span class="stat-label">Player</span>
                        <span class="stat-value"><?= htmlspecialchars($user_name) ?></span>
                    </div>
                    <div class="stat-card">
                        <span class="stat-label">Voucher</span>
                        <span class="stat-value"><?= htmlspecialchars($voucher_code) ?></span>
                    </div>
                </div>


                <div class="status-banner<?= $game_over ? ($is_winner ? ' win' : ' lose') : '' ?>" id="result">
                    <?= $game_over ? ($is_winner ? 'Semua token aman berhasil dibuka.' : 'Bom sudah ditemukan. Permainan selesai.') : 'Pilih satu token untuk mulai membuka board.' ?>
                </div>
            </div>
        </section>
    </div>

    <!-- Popup -->
    <div class="overlay" id="popup">
        <div class="modal" id="popupCard">
            <div class="modal-badge" id="popupBadge">OK</div>
            <h3 id="popupHeading">Permainan selesai</h3>
            <p class="modal-text" id="popup-message"></p>
            <p class="modal-info"><strong id="popup-code"></strong></p>
            <p class="modal-info"><strong id="popup-name"></strong></p>
            <p class="modal-info"><strong id="popup-status"></strong></p>
            <div class="modal-actions">
                <button class="btn btn-secondary" type="button" onclick="location.href='reset_session.php'">Main Lagi</button>
                <a class="btn btn-primary" href="https://direct.lc.chat/18975991/" target="_blank" rel="noreferrer">Claim Hadiah</a>
            </div>
        </div>
    </div>

    <script>
        let openedCircles = <?= json_encode(array_values($openedCircles)) ?>;
        let safeOpenedCount = <?= (int) $safe_found ?>;
        let gameOver = <?= $game_over ?>;
        let selectedCircles = <?= $selected_circles ?>;
        let isWinner = <?= $is_winner ? 'true' : 'false' ?>;
        let bombClick = <?= $bomb_click ?>;
        let voucherCode = <?= json_encode($voucher_code) ?>;
        let userName = <?= json_encode($user_name) ?>;
        const safeTarget = <?= $safe_target ?>;
        const resultBox = document.getElementById('result');
        const popup = document.getElementById('popup');
        const popupCard = document.getElementById('popupCard');
        const popupBadge = document.getElementById('popupBadge');
        const popupHeading = document.getElementById('popupHeading');
        const progressText = document.getElementById('progressText');
        const progressFill = document.getElementById('progressFill');
        const scratchState = {};

        updateProgress();

        if (gameOver) {
            disableAllCircles();
            window.setTimeout(() => showPopup(isWinner), 500);
        }

        document.querySelectorAll('.token-overlay-canvas').forEach((canvas) => {
            const index = Number(canvas.dataset.index);
            scratchState[index] = {
                active: false,
                revealed: openedCircles.includes(index),
                canvas,
                ctx: null,
                lastX: 0,
                lastY: 0,
                particleTick: 0
            };
            setupScratchCanvas(index);
            if (!scratchState[index].revealed) {
                canvas.addEventListener('pointerdown', (event) => startGesture(event, index));
                canvas.addEventListener('pointermove', (event) => trackGesture(event, index));
                canvas.addEventListener('pointerup', (event) => endGesture(event, index));
                canvas.addEventListener('pointercancel', (event) => endGesture(event, index));
                canvas.addEventListener('pointerleave', (event) => endGesture(event, index));
            }
        });

        window.addEventListener('resize', () => {
            Object.keys(scratchState).forEach((key) => {
                const index = Number(key);
                if (!scratchState[index].revealed) {
                    setupScratchCanvas(index);
                }
            });
        });

        function updateProgress() {
            const progress = Math.min(100, Math.round((safeOpenedCount / safeTarget) * 100));
            progressText.textContent = `${safeOpenedCount} / ${safeTarget}`;
            progressFill.style.width = `${progress}%`;
        }

        function setupScratchCanvas(index) {
            const state = scratchState[index];
            const canvas = state.canvas;
            const rect = canvas.getBoundingClientRect();
            const size = Math.max(60, Math.floor(rect.width));
            const ratio = window.devicePixelRatio || 1;
            canvas.width = size * ratio;
            canvas.height = size * ratio;
            state.ctx = canvas.getContext('2d', { willReadFrequently: true });
            state.ctx.setTransform(1, 0, 0, 1, 0, 0);
            state.ctx.scale(ratio, ratio);
            const gradient = state.ctx.createRadialGradient(size * 0.32, size * 0.28, size * 4 / 100, size * 0.5, size * 0.5, size * 0.56);
            gradient.addColorStop(0, '#4a4a4a');
            gradient.addColorStop(0.45, '#1f1f1f');
            gradient.addColorStop(1, '#050505');
            state.ctx.clearRect(0, 0, size, size);
            state.ctx.fillStyle = gradient;
            state.ctx.beginPath();
            state.ctx.arc(size / 2, size / 2, size / 2, 0, Math.PI * 2);
            state.ctx.fill();
            state.ctx.lineWidth = Math.max(2, size * 0.012);
            state.ctx.strokeStyle = 'rgba(255,255,255,0.08)';
            state.ctx.stroke();
            state.ctx.fillStyle = 'rgba(255,255,255,0.92)';
            state.ctx.font = `900 ${Math.floor(size * 0.34)}px Trebuchet MS`;
            state.ctx.textAlign = 'center';
            state.ctx.textBaseline = 'middle';
            state.ctx.fillText('?', size / 2, size / 2);
        }

        function getScratchPoint(event, index) {
            const canvas = scratchState[index].canvas;
            const rect = canvas.getBoundingClientRect();
            return {
                x: event.clientX - rect.left,
                y: event.clientY - rect.top,
                size: rect.width
            };
        }

        function eraseScratch(index, x, y, connect) {
            const state = scratchState[index];
            const ctx = state.ctx;
            const size = Math.max(60, state.canvas.getBoundingClientRect().width);
            const radius = Math.max(10, size * 0.11);
            ctx.save();
            ctx.globalCompositeOperation = 'destination-out';
            ctx.lineCap = 'round';
            ctx.lineJoin = 'round';
            ctx.lineWidth = radius * 2;
            if (connect) {
                ctx.beginPath();
                ctx.moveTo(state.lastX, state.lastY);
                ctx.lineTo(x, y);
                ctx.stroke();
            }
            ctx.beginPath();
            ctx.arc(x, y, radius, 0, Math.PI * 2);
            ctx.fill();
            ctx.restore();
            state.particleTick += 1;
            if (state.particleTick % 2 === 0) {
                spawnScratchParticles(index, x, y, connect ? 2 : 1);
            }
        }

        function spawnScratchParticles(index, x, y, amount) {
            const token = document.getElementById(`circle-${index}`);
            const canvas = scratchState[index].canvas;
            const rect = canvas.getBoundingClientRect();
            const tokenRect = token.getBoundingClientRect();
            const offsetX = (rect.left - tokenRect.left) + x;
            const offsetY = (rect.top - tokenRect.top) + y;
            for (let i = 0; i < amount; i += 1) {
                const particle = document.createElement('span');
                const dx = `${(Math.random() * 24) - 12}px`;
                const dy = `${(Math.random() * 18) - 14}px`;
                particle.className = 'scratch-particle';
                particle.style.left = `${offsetX}px`;
                particle.style.top = `${offsetY}px`;
                particle.style.setProperty('--dx', dx);
                particle.style.setProperty('--dy', dy);
                particle.style.width = `${4 + Math.random() * 4}px`;
                particle.style.height = particle.style.width;
                particle.style.marginLeft = `-${parseFloat(particle.style.width) / 2}px`;
                particle.style.marginTop = `-${parseFloat(particle.style.height) / 2}px`;
                token.appendChild(particle);
                window.setTimeout(() => particle.remove(), 560);
            }
        }

        function getRevealRatio(index) {
            const state = scratchState[index];
            const canvas = state.canvas;
            const ctx = state.ctx;
            const pixels = ctx.getImageData(0, 0, canvas.width, canvas.height).data;
            let transparent = 0;
            for (let i = 3; i < pixels.length; i += 4) {
                if (pixels[i] < 20) {
                    transparent += 1;
                }
            }
            return transparent / (canvas.width * canvas.height);
        }

        function revealToken(index, type) {
            const token = document.getElementById(`circle-${index}`);
            const overlay = document.getElementById(`scratch-${index}`);
            const content = document.getElementById(`content-${index}`);
            const label = document.getElementById(`label-${index}`);
            overlay.style.opacity = '0';
            overlay.style.transform = 'scale(0.92)';
            token.classList.add('opened');
            if (type === 'bomb') {
                token.classList.add('bomb');
                content.textContent = '💣';
                label.textContent = 'Bomb';
            } else {
                token.classList.add('safe');
                content.textContent = 'OK';
                label.textContent = 'Safe';
            }
        }

        function startGesture(event, index) {
            if (gameOver || openedCircles.includes(index) || scratchState[index].revealed) return;
            const point = getScratchPoint(event, index);
            scratchState[index].active = true;
            scratchState[index].lastX = point.x;
            scratchState[index].lastY = point.y;
            event.target.setPointerCapture(event.pointerId);
            eraseScratch(index, point.x, point.y, false);
        }

        function trackGesture(event, index) {
            const state = scratchState[index];
            if (!state || !state.active || gameOver || openedCircles.includes(index)) return;
            const point = getScratchPoint(event, index);
            eraseScratch(index, point.x, point.y, true);
            state.lastX = point.x;
            state.lastY = point.y;
            if (getRevealRatio(index) >= 0.42) {
                state.active = false;
                state.revealed = true;
                startScratch(index);
            }
        }

        function endGesture(event, index) {
            const state = scratchState[index];
            if (!state) return;
            if (event && event.target && typeof event.target.releasePointerCapture === 'function') {
                try { event.target.releasePointerCapture(event.pointerId); } catch (e) {}
            }
            state.active = false;
        }

        function setStatus(message, type) {
            resultBox.textContent = message;
            resultBox.classList.remove('win', 'lose');
            if (type) resultBox.classList.add(type);
        }

        function startScratch(index) {
            if (gameOver || openedCircles.includes(index)) return;

            if (isWinner) {
                revealToken(index, 'safe');
                openedCircles.push(index);
                safeOpenedCount += 1;
                updateProgress();
                setStatus('Token aman ditemukan. Gosok token berikutnya.', 'win');
                if (safeOpenedCount === selectedCircles - 1) {
                    setStatus('Semua token aman berhasil dibuka.', 'win');
                    finishGame(true);
                }
            } else {
                const currentClick = openedCircles.length + 1;
                if (currentClick === bombClick) {
                    revealToken(index, 'bomb');
                    openedCircles.push(index);
                    setStatus('Bom ditemukan. Permainan berakhir di token ini.', 'lose');
                    finishGame(false);
                } else {
                    revealToken(index, 'safe');
                    openedCircles.push(index);
                    safeOpenedCount += 1;
                    updateProgress();
                    setStatus('Token aman ditemukan. Terus gosok dan hindari bom.', 'win');
                    if (safeOpenedCount === selectedCircles - 1) {
                        setStatus('Semua token aman berhasil dibuka.', 'win');
                        finishGame(true);
                    }
                }
            }
            updateGameState(index, gameOver ? 1 : 0);
        }

        function finishGame(win) {
            gameOver = true;
            disableAllCircles();
            window.setTimeout(() => showPopup(win), 750);
        }

        function disableAllCircles() {
            for (let i = 0; i < selectedCircles; i += 1) {
                const token = document.getElementById(`circle-${i}`);
                if (token) token.disabled = true;
            }
        }

        function showPopup(win) {
            popup.classList.add('show');
            popupCard.classList.toggle('lose', !win);
            popupBadge.textContent = win ? '🎉' : '💣';
            popupHeading.textContent = win ? 'Anda Menang' : 'Kamu Kalah';
            document.getElementById('popup-code').textContent = `Code: ${voucherCode}`;
            document.getElementById('popup-name').textContent = `Player: ${userName}`;
            document.getElementById('popup-status').textContent = win ? 'Status: Menang' : 'Status: Kalah';
            document.getElementById('popup-message').textContent = win
                ? 'Board berhasil dibersihkan. Simpan hasil ini lalu lanjutkan klaim hadiah Anda.'
                : 'Yahhh, Kamu kurang beruntung.Coba lagi dengan voucher berikutnya.';
        }

        function updateGameState(index, isGameOver) {
            fetch('update_game_state.php', {
                method: 'POST',
                headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' },
                body: `voucher_code=${encodeURIComponent(voucherCode)}&opened_index=${encodeURIComponent(index)}&game_over=${encodeURIComponent(isGameOver)}`
            }).catch(() => {});
        }
    </script>
</body>
</html>