<?php
require_once __DIR__ . '/../../includes/auth.php';
require_once __DIR__ . '/../../includes/square.php';
header('Content-Type: application/json');
requireAdmin();

$action = $_GET['action'] ?? '';

switch ($action) {

    // ─── STATS ────────────────────────────────────────────────
    case 'stats':
        echo json_encode(['success' => true, 'stats' => [
            'total_users'       => db()->query("SELECT COUNT(*) FROM users")->fetchColumn(),
            'active_users'      => db()->query("SELECT COUNT(*) FROM users WHERE status='active'")->fetchColumn(),
            'pending_purchases' => db()->query("SELECT COUNT(*) FROM token_purchases WHERE status='pending'")->fetchColumn(),
            'pending_cashouts'  => db()->query("SELECT COUNT(*) FROM cashout_requests WHERE status='pending'")->fetchColumn(),
            'pending_signups'   => db()->query("SELECT COUNT(*) FROM pending_registrations WHERE expires_at > NOW() AND username != '__reset__'")->fetchColumn(),
            'total_tokens_sold' => db()->query("SELECT COALESCE(SUM(tokens),0) FROM token_purchases WHERE status='completed'")->fetchColumn(),
            'total_revenue'     => db()->query("SELECT COALESCE(SUM(amount_cents),0)/100 FROM token_purchases WHERE status='completed'")->fetchColumn(),
        ]]);
        break;

    // ─── PENDING SIGNUPS ──────────────────────────────────────
    case 'pending_signups':
        $rows = db()->query("SELECT id,username,alias,email,expires_at,created_at FROM pending_registrations WHERE expires_at > NOW() AND username != '__reset__' ORDER BY created_at DESC")->fetchAll();
        echo json_encode(['success'=>true,'pending'=>$rows]);
        break;

    case 'delete_pending':
        if ($_SERVER['REQUEST_METHOD'] !== 'POST') { echo json_encode(['success'=>false]); exit; }
        $data = json_decode(file_get_contents('php://input'), true);
        $id   = (int)($data['id'] ?? 0);
        db()->prepare("DELETE FROM pending_registrations WHERE id=?")->execute([$id]);
        echo json_encode(['success'=>true]);
        break;

    case 'approve_pending':
        if ($_SERVER['REQUEST_METHOD'] !== 'POST') { echo json_encode(['success'=>false]); exit; }
        $data = json_decode(file_get_contents('php://input'), true);
        $id   = (int)($data['id'] ?? 0);
        // Fetch the pending record
        $stmt = db()->prepare("SELECT * FROM pending_registrations WHERE id=?");
        $stmt->execute([$id]);
        $pending = $stmt->fetch();
        if (!$pending) { echo json_encode(['success'=>false,'error'=>'Pending signup not found']); exit; }
        // Check username/email not already taken
        $chkUser = db()->prepare("SELECT id FROM users WHERE username=?");
        $chkUser->execute([$pending['username']]);
        if ($chkUser->fetch()) { echo json_encode(['success'=>false,'error'=>'Username already taken']); exit; }
        if (!empty($pending['email'])) {
            $chkEmail = db()->prepare("SELECT id FROM users WHERE email=?");
            $chkEmail->execute([$pending['email']]);
            if ($chkEmail->fetch()) { echo json_encode(['success'=>false,'error'=>'Email already registered']); exit; }
        }
        // Create the user account — bypass email verification
        db()->beginTransaction();
        try {
            db()->prepare("INSERT INTO users (username,password,alias,email,email_verified,tokens,is_admin,status)
                VALUES (?,?,?,?,1,0,0,'active')")
               ->execute([$pending['username'],$pending['password'],$pending['alias'],$pending['email']]);
            db()->prepare("DELETE FROM pending_registrations WHERE id=?")->execute([$id]);
            db()->commit();
            logActivity('account_approved', (int)db()->lastInsertId(), (int)$_SESSION['user_id'], 'user', 0, 'Account approved for '.$pending['username']);
            echo json_encode(['success'=>true,'username'=>$pending['username']]);
        } catch (Exception $e) {
            db()->rollBack();
            echo json_encode(['success'=>false,'error'=>'Could not create account']);
        }
        break;

    // ─── PLATFORM STATS ──────────────────────────────────────
    case 'platform_stats':
        $rows = db()->query("
            SELECT p.id, p.name, p.slug, p.color,
                COALESCE(SUM(CASE WHEN pc.type='debit' THEN -pc.credits_purchased ELSE pc.credits_purchased END),0) AS credits_balance,
                (SELECT COALESCE(SUM(tp.amount_cents),0)/100 FROM token_purchases tp WHERE tp.platform_id=p.slug AND tp.status='completed') AS purchases_total,
                (SELECT COALESCE(SUM(cr.tokens),0) FROM cashout_requests cr WHERE cr.platform_id=p.slug AND cr.status IN ('sent','approved')) AS cashouts_total
            FROM platforms p
            LEFT JOIN platform_credits pc ON pc.platform_id=p.id
            WHERE p.is_deleted=0 AND p.is_active=1
            GROUP BY p.id, p.name, p.slug, p.color
            ORDER BY p.sort_order, p.id
        ")->fetchAll();
        echo json_encode(['success'=>true,'platforms'=>$rows]);
        break;

    // ─── PURCHASES ────────────────────────────────────────────
    case 'purchases':
        $status = $_GET['status'] ?? 'pending';
        if ($status === 'all') {
            $stmt = db()->query("SELECT tp.*, u.username, u.alias FROM token_purchases tp JOIN users u ON tp.user_id=u.id ORDER BY tp.created_at DESC LIMIT 200");
        } else {
            $stmt = db()->prepare("SELECT tp.*, u.username, u.alias FROM token_purchases tp JOIN users u ON tp.user_id=u.id WHERE tp.status=? ORDER BY tp.created_at DESC LIMIT 200");
            $stmt->execute([$status]);
        }
        echo json_encode(['success' => true, 'purchases' => $stmt->fetchAll()]);
        break;

    // ─── RESOLVE PURCHASE (approve manual / reject) ──────────
    case 'resolve_purchase':
        if ($_SERVER['REQUEST_METHOD'] !== 'POST') { echo json_encode(['success'=>false]); exit; }
        $data   = json_decode(file_get_contents('php://input'), true);
        $id     = (int)($data['id']     ?? 0);
        $status = $data['status'] ?? '';
        $note   = trim($data['note']   ?? '');

        if (!in_array($status, ['completed','failed'])) {
            echo json_encode(['success'=>false,'error'=>'Invalid status']); exit;
        }

        // Fetch purchase
        $row = db()->prepare("SELECT * FROM token_purchases WHERE id=? AND status='pending'");
        $row->execute([$id]);
        $purchase = $row->fetch();

        if (!$purchase) {
            echo json_encode(['success'=>false,'error'=>'Purchase not found or already resolved']); exit;
        }

        db()->beginTransaction();
        try {
            if ($status === 'completed') {
                db()->prepare("UPDATE users SET tokens=tokens+? WHERE id=?")->execute([$purchase['tokens'], $purchase['user_id']]);
            }
            db()->prepare("UPDATE token_purchases SET status=?,admin_note=? WHERE id=?")->execute([$status, $note, $id]);
            db()->commit();
        } catch (Exception $e) {
            db()->rollBack();
            echo json_encode(['success'=>false,'error'=>'DB error']); exit;
        }

        // Insert debit entry into platform_credits when approved
        if ($status === 'completed' && !empty($purchase['platform_id'])) {
            $platRow = db()->prepare("SELECT id FROM platforms WHERE slug=?");
            $platRow->execute([$purchase['platform_id']]);
            $platNumId = (int)$platRow->fetchColumn();
            if ($platNumId) {
                $userRow = db()->prepare("SELECT username FROM users WHERE id=?");
                $userRow->execute([$purchase['user_id']]);
                $username = $userRow->fetchColumn() ?: 'User#'.$purchase['user_id'];
                $amtDollars = number_format($purchase['amount_cents'] / 100, 2);
                $playerLabel = trim($purchase['player_name'] ?: $purchase['game_alias'] ?: $username);
                $debitNotes = "Purchase #{$id} · {$playerLabel} ({$username}) · {$purchase['tokens']} tokens · \${$amtDollars} via {$purchase['payment_method']}";
                db()->prepare("INSERT INTO platform_credits (platform_id, credits_purchased, credit_date, payment_method, notes, type, purchase_ref_id) VALUES (?,?,CURDATE(),?,?,?,?)")
                    ->execute([$platNumId, $purchase['tokens'], $purchase['payment_method'], $debitNotes, 'debit', $id]);
            }
        }

        echo json_encode(['success'=>true]);
        break;

    // ─── REFUND PURCHASE (real Square refund) ────────────────
    case 'refund_purchase':
        if ($_SERVER['REQUEST_METHOD'] !== 'POST') { echo json_encode(['success'=>false]); exit; }
        $data   = json_decode(file_get_contents('php://input'), true);
        $id     = (int)($data['id'] ?? 0);
        $reason = trim($data['reason'] ?? '');

        $row = db()->prepare("SELECT * FROM token_purchases WHERE id=? AND status='completed'");
        $row->execute([$id]);
        $purchase = $row->fetch();

        if (!$purchase) {
            echo json_encode(['success'=>false,'error'=>'Purchase not found or not in a refundable state']); exit;
        }
        if ($purchase['payment_method'] !== 'card' || empty($purchase['square_payment_id'])) {
            echo json_encode(['success'=>false,'error'=>'This purchase has no Square payment to refund']); exit;
        }

        $amountCents = isset($data['amount']) ? (int) round((float)$data['amount'] * 100) : (int) $purchase['amount_cents'];
        if ($amountCents <= 0 || $amountCents > (int) $purchase['amount_cents']) {
            echo json_encode(['success'=>false,'error'=>'Invalid refund amount']); exit;
        }

        $square = new SquarePayment();
        $result = $square->refund($purchase['square_payment_id'], $amountCents, $reason ?: ('Purchase #' . $id));

        if (!$result['success']) {
            echo json_encode(['success'=>false,'error'=>$result['error']]); exit;
        }

        $note = 'Refunded $' . number_format($amountCents / 100, 2) . ' via Square (refund ID: ' . $result['refund_id'] . ')' . ($reason ? ' - ' . $reason : '');
        $existingNote = $purchase['admin_note'] ? $purchase['admin_note'] . " | " . $note : $note;

        db()->beginTransaction();
        try {
            db()->prepare("UPDATE token_purchases SET status='refunded', admin_note=?, refund_id=? WHERE id=?")
                ->execute([$existingNote, $result['refund_id'], $id]);

            // Claw back the tokens credited on purchase, clamped at 0
            $userRow = db()->prepare("SELECT tokens FROM users WHERE id=?");
            $userRow->execute([$purchase['user_id']]);
            $currentTokens = (float) ($userRow->fetchColumn() ?: 0);
            $newTokens = max(0, $currentTokens - (float) $purchase['tokens']);
            db()->prepare("UPDATE users SET tokens=? WHERE id=?")->execute([$newTokens, $purchase['user_id']]);

            db()->commit();
        } catch (Exception $e) {
            db()->rollBack();
            echo json_encode(['success'=>false,'error'=>'Refund processed on Square but failed to update local records: ' . $e->getMessage()]); exit;
        }

        $tokensClawedBack = min((float) $purchase['tokens'], $currentTokens);
        $shortfall = (float) $purchase['tokens'] - $tokensClawedBack;

        echo json_encode([
            'success'          => true,
            'refund_id'        => $result['refund_id'],
            'tokens_clawed_back' => $tokensClawedBack,
            'token_shortfall'  => $shortfall,
        ]);
        break;

    // ─── CASHOUTS ─────────────────────────────────────────────
    case 'cashouts':
        $status = $_GET['status'] ?? 'pending';
        $valid  = ['pending','sent','approved','rejected','deleted'];
        if (!in_array($status, $valid)) $status = 'pending';
        if ($status === 'pending') {
            // Show both pending (player editing) and locked (submitted to admin)
            $stmt = db()->prepare("SELECT cr.*, u.username, u.alias AS user_alias FROM cashout_requests cr JOIN users u ON cr.user_id=u.id WHERE cr.status IN ('pending','locked') ORDER BY cr.status DESC, cr.created_at DESC");
            $stmt->execute();
        } elseif ($status === 'sent') {
            $stmt = db()->prepare("SELECT cr.*, u.username, u.alias AS user_alias FROM cashout_requests cr JOIN users u ON cr.user_id=u.id WHERE cr.status IN ('sent','approved') ORDER BY cr.created_at DESC");
            $stmt->execute();
        } else {
            $stmt = db()->prepare("SELECT cr.*, u.username, u.alias AS user_alias FROM cashout_requests cr JOIN users u ON cr.user_id=u.id WHERE cr.status=? ORDER BY cr.created_at DESC");
            $stmt->execute([$status]);
        }
        echo json_encode(['success'=>true,'cashouts'=>$stmt->fetchAll()]);
        break;

    case 'resolve_cashout':
        if ($_SERVER['REQUEST_METHOD'] !== 'POST') { echo json_encode(['success'=>false]); exit; }
        $data   = json_decode(file_get_contents('php://input'), true);
        $id     = (int)($data['id']     ?? 0);
        $status = $data['status'] ?? '';
        $note   = trim($data['note']   ?? '');
        // 'approved' is treated as 'sent' (payment sent to player)
        if ($status === 'approved') $status = 'sent';
        if (!in_array($status, ['sent','rejected','deleted'])) { echo json_encode(['success'=>false,'error'=>'Invalid status']); exit; }

        $r = db()->prepare("SELECT user_id,tokens FROM cashout_requests WHERE id=? AND status IN ('pending','locked')");
        $r->execute([$id]);
        $req = $r->fetch();
        if (!$req) { echo json_encode(['success'=>false,'error'=>'Not found or already resolved']); exit; }

        db()->beginTransaction();
        try {
            // Return tokens to player if denied or deleted
            if (in_array($status, ['rejected','deleted'])) {
                db()->prepare("UPDATE users SET tokens=tokens+? WHERE id=?")->execute([$req['tokens'],$req['user_id']]);
            }
            db()->prepare("UPDATE cashout_requests SET status=?,admin_note=?,resolved_at=NOW() WHERE id=?")->execute([$status,$note,$id]);
            db()->commit();
            logActivity('cashout_'.$status, $req['user_id'], (int)$_SESSION['user_id'], 'cashout', $id,
                'Cashout '.$status.' by admin. Tokens: '.$req['tokens'].($note?' Note: '.$note:''));
            echo json_encode(['success'=>true,'status'=>$status]);
        } catch (Exception $e) {
            db()->rollBack();
            echo json_encode(['success'=>false,'error'=>'DB error']);
        }
        break;
        if (!in_array($status, ['approved','rejected'])) { echo json_encode(['success'=>false,'error'=>'Invalid status']); exit; }

        if ($status === 'rejected') {
            $r = db()->prepare("SELECT user_id,tokens FROM cashout_requests WHERE id=? AND status='pending'");
            $r->execute([$id]);
            $req = $r->fetch();
            if ($req) db()->prepare("UPDATE users SET tokens=tokens+? WHERE id=?")->execute([$req['tokens'],$req['user_id']]);
        }
        db()->prepare("UPDATE cashout_requests SET status=?,admin_note=?,resolved_at=NOW() WHERE id=?")->execute([$status,$note,$id]);
        echo json_encode(['success'=>true]);
        break;

    // ─── USERS LIST ───────────────────────────────────────────
    case 'users':
        $users = db()->query("SELECT id,username,alias,email,email_verified,tokens,is_admin,status,created_at,last_login FROM users ORDER BY created_at DESC")->fetchAll();
        echo json_encode(['success'=>true,'users'=>$users]);
        break;

    // ─── SINGLE USER DETAIL ───────────────────────────────────
    case 'user_detail':
        $uid = (int)($_GET['user_id'] ?? 0);
        if (!$uid) { echo json_encode(['success'=>false,'error'=>'user_id required']); exit; }
        $stmt = db()->prepare("SELECT id,username,alias,email,email_verified,tokens,is_admin,status,created_at,last_login FROM users WHERE id=?");
        $stmt->execute([$uid]);
        $user = $stmt->fetch();
        if (!$user) { echo json_encode(['success'=>false,'error'=>'User not found']); exit; }
        // Rich stats
        $s1 = db()->prepare("SELECT COALESCE(SUM(amount_cents),0)/100 FROM token_purchases WHERE user_id=? AND status='completed'");
        $s1->execute([$uid]);
        $s2 = db()->prepare("SELECT COUNT(*) FROM token_purchases WHERE user_id=? AND status='completed'"); $s2->execute([$uid]);
        $s3 = db()->prepare("SELECT COUNT(*) FROM token_purchases WHERE user_id=? AND status='pending'");  $s3->execute([$uid]);
        $s4 = db()->prepare("SELECT COUNT(*) FROM token_purchases WHERE user_id=? AND status='failed'");   $s4->execute([$uid]);
        $s5 = db()->prepare("SELECT COUNT(*) FROM cashout_requests WHERE user_id=?"); $s5->execute([$uid]);
        $s6 = db()->prepare("SELECT COALESCE(SUM(tokens),0) FROM token_purchases WHERE user_id=? AND status='completed'"); $s6->execute([$uid]);
        $stats = [
            'total_spent'        => $s1->fetchColumn(),
            'completed_purchases'=> $s2->fetchColumn(),
            'pending_purchases'  => $s3->fetchColumn(),
            'failed_purchases'   => $s4->fetchColumn(),
            'total_cashouts'     => $s5->fetchColumn(),
            'total_tokens_bought'=> $s6->fetchColumn(),
        ];
        echo json_encode(['success'=>true,'user'=>$user,'stats'=>$stats]);
        break;

    // ─── USER PURCHASES ───────────────────────────────────────
    case 'user_purchases':
        $uid = (int)($_GET['user_id'] ?? 0);
        $stmt = db()->prepare("SELECT id,tokens,amount_cents,payment_method,square_payment_id,platform_id,game_alias,player_name,billing_name,billing_address,billing_city,billing_state,billing_zip,billing_email,is_custom,failure_reason,card_brand,card_last4,receipt_url,status,admin_note,created_at FROM token_purchases WHERE user_id=? ORDER BY created_at DESC LIMIT 100");
        $stmt->execute([$uid]);
        echo json_encode(['success'=>true,'purchases'=>$stmt->fetchAll()]);
        break;

    // ─── USER CASHOUTS ────────────────────────────────────────
    case 'user_cashouts':
        $uid = (int)($_GET['user_id'] ?? 0);
        $stmt = db()->prepare("SELECT * FROM cashout_requests WHERE user_id=? ORDER BY created_at DESC LIMIT 100");
        $stmt->execute([$uid]);
        echo json_encode(['success'=>true,'cashouts'=>$stmt->fetchAll()]);
        break;

    // ─── ADJUST TOKENS ────────────────────────────────────────
    case 'adjust_tokens':
        if ($_SERVER['REQUEST_METHOD'] !== 'POST') { echo json_encode(['success'=>false]); exit; }
        $data   = json_decode(file_get_contents('php://input'), true);
        $uid    = (int)($data['user_id'] ?? 0);
        $amount = (float)($data['amount'] ?? 0);
        db()->prepare("UPDATE users SET tokens=tokens+? WHERE id=?")->execute([$amount,$uid]);
        $bal = db()->prepare("SELECT tokens FROM users WHERE id=?"); $bal->execute([$uid]);
        $newBal = $bal->fetchColumn();
        echo json_encode(['success'=>true,'new_balance'=>$newBal]);
        break;

    // ─── SET EXACT TOKEN BALANCE ──────────────────────────────
    case 'set_tokens':
        if ($_SERVER['REQUEST_METHOD'] !== 'POST') { echo json_encode(['success'=>false]); exit; }
        $data   = json_decode(file_get_contents('php://input'), true);
        $uid    = (int)($data['user_id'] ?? 0);
        $bal    = (float)($data['balance'] ?? 0);
        if ($bal < 0) { echo json_encode(['success'=>false,'error'=>'Balance cannot be negative']); exit; }
        db()->prepare("UPDATE users SET tokens=? WHERE id=?")->execute([$bal,$uid]);
        echo json_encode(['success'=>true,'new_balance'=>$bal]);
        break;

    // ─── EDIT USER ────────────────────────────────────────────
    case 'edit_user':
        if ($_SERVER['REQUEST_METHOD'] !== 'POST') { echo json_encode(['success'=>false]); exit; }
        $data     = json_decode(file_get_contents('php://input'), true);
        $uid      = (int)($data['user_id'] ?? 0);
        $username = strtolower(trim($data['username'] ?? ''));
        $alias    = trim($data['alias']    ?? '');
        $email    = strtolower(trim($data['email']   ?? ''));
        $password = trim($data['password'] ?? '');

        if (!$uid || empty($username) || empty($alias))
            { echo json_encode(['success'=>false,'error'=>'Username and alias required']); exit; }
        if (!preg_match('/^[a-z0-9_]{3,50}$/', $username))
            { echo json_encode(['success'=>false,'error'=>'Invalid username format']); exit; }
        if (!empty($email) && !filter_var($email, FILTER_VALIDATE_EMAIL))
            { echo json_encode(['success'=>false,'error'=>'Invalid email address']); exit; }

        // Check username not taken by another user
        $chk = db()->prepare("SELECT id FROM users WHERE username=? AND id!=?");
        $chk->execute([$username,$uid]);
        if ($chk->fetch()) { echo json_encode(['success'=>false,'error'=>'Username already taken']); exit; }

        if (!empty($email)) {
            $chk2 = db()->prepare("SELECT id FROM users WHERE email=? AND id!=?");
            $chk2->execute([$email,$uid]);
            if ($chk2->fetch()) { echo json_encode(['success'=>false,'error'=>'Email already in use']); exit; }
        }

        if (!empty($password)) {
            if (strlen($password) < 6) { echo json_encode(['success'=>false,'error'=>'Password must be 6+ characters']); exit; }
            $hash = password_hash($password, PASSWORD_BCRYPT);
            db()->prepare("UPDATE users SET username=?,alias=?,email=?,password=? WHERE id=?")->execute([$username,$alias,$email,$hash,$uid]);
        } else {
            db()->prepare("UPDATE users SET username=?,alias=?,email=? WHERE id=?")->execute([$username,$alias,$email,$uid]);
        }
        echo json_encode(['success'=>true]);
        break;

    // ─── TOGGLE ADMIN ROLE ───────────────────────────────────
    case 'toggle_admin':
        if ($_SERVER['REQUEST_METHOD'] !== 'POST') { echo json_encode(['success'=>false]); exit; }
        $data = json_decode(file_get_contents('php://input'), true);
        $uid  = (int)($data['user_id'] ?? 0);
        // Master admin (ID=1) can NEVER lose admin status
        if ($uid === MASTER_ADMIN_ID) {
            echo json_encode(['success'=>false,'error'=>'Master admin cannot be modified.']); exit;
        }
        // Cannot remove your own admin
        if ($uid === (int)$_SESSION['user_id']) {
            echo json_encode(['success'=>false,'error'=>'You cannot change your own admin status.']); exit;
        }
        // Only master admin can grant/revoke admin
        if ((int)$_SESSION['user_id'] !== MASTER_ADMIN_ID) {
            echo json_encode(['success'=>false,'error'=>'Only the master admin can change admin roles.']); exit;
        }
        $stmt = db()->prepare("SELECT is_admin FROM users WHERE id=?");
        $stmt->execute([$uid]);
        $current = $stmt->fetchColumn();
        $new_val = $current ? 0 : 1;
        if ($new_val) {
            db()->prepare("UPDATE users SET is_admin=1, email_verified=1 WHERE id=?")->execute([$uid]);
        } else {
            db()->prepare("UPDATE users SET is_admin=0 WHERE id=?")->execute([$uid]);
        }
        // Force the affected user to re-login by invalidating their sessions
        // Store a flag in DB that forces re-auth on next request
        db()->prepare("UPDATE users SET last_login=last_login WHERE id=?")->execute([$uid]);
        logActivity($new_val?'admin_granted':'admin_revoked', $uid, (int)$_SESSION['user_id'], 'user', $uid, 'Admin status changed to '.($new_val?'admin':'player'), '', 'admin', '', '', 'warning');
        echo json_encode(['success'=>true, 'is_admin'=>$new_val, 'needs_relogin'=>true, 'message'=>$new_val ? 'Admin access granted. User must log out and back in.' : 'Admin access removed. User must log out and back in.']);
        break;

    // ─── TOGGLE SUSPEND ───────────────────────────────────────
    case 'toggle_user':
        if ($_SERVER['REQUEST_METHOD'] !== 'POST') { echo json_encode(['success'=>false]); exit; }
        $data = json_decode(file_get_contents('php://input'), true);
        $uid  = (int)($data['user_id'] ?? 0);
        if ($uid === MASTER_ADMIN_ID) { echo json_encode(['success'=>false,'error'=>'Cannot suspend the master admin.']); exit; }
        db()->prepare("UPDATE users SET status=IF(status='active','suspended','active') WHERE id=?")->execute([$uid]);
        logAdminAction('USER_STATUS_CHANGE', (int)$_SESSION['user_id'], 'user', $uid, 'Changed user status', '', ($data['status']??''), 'warning');
        echo json_encode(['success'=>true]);
        break;

    // ─── DELETE USER ──────────────────────────────────────────
    case 'delete_user':
        if ($_SERVER['REQUEST_METHOD'] !== 'POST') { echo json_encode(['success'=>false]); exit; }
        $data = json_decode(file_get_contents('php://input'), true);
        $uid  = (int)($data['user_id'] ?? 0);
        if (!$uid) { echo json_encode(['success'=>false,'error'=>'Invalid user']); exit; }
        // Prevent deleting own account
        if ($uid === MASTER_ADMIN_ID) { echo json_encode(['success'=>false,'error'=>'Cannot delete the master admin account.']); exit; }
        if ($uid === (int)$_SESSION['user_id']) { echo json_encode(['success'=>false,'error'=>'Cannot delete your own account']); exit; }
        db()->beginTransaction();
        try {
            db()->prepare("DELETE FROM chat_messages WHERE user_id=?")->execute([$uid]);
            db()->prepare("DELETE FROM cashout_requests WHERE user_id=?")->execute([$uid]);
            db()->prepare("DELETE FROM token_purchases WHERE user_id=?")->execute([$uid]);
            db()->prepare("DELETE FROM users WHERE id=?")->execute([$uid]);
            db()->commit();
            echo json_encode(['success'=>true]);
        } catch (Exception $e) {
            db()->rollBack();
            echo json_encode(['success'=>false,'error'=>'Delete failed']);
        }
        break;

    // ─── SEND PASSWORD RESET ──────────────────────────────────
    case 'send_password_reset':
        if ($_SERVER['REQUEST_METHOD'] !== 'POST') { echo json_encode(['success'=>false]); exit; }
        $data = json_decode(file_get_contents('php://input'), true);
        $uid  = (int)($data['user_id'] ?? 0);
        $stmt = db()->prepare("SELECT email,alias FROM users WHERE id=?");
        $stmt->execute([$uid]);
        $user = $stmt->fetch();
        if (!$user || empty($user['email'])) { echo json_encode(['success'=>false,'error'=>'No email on file']); exit; }
        // Generate reset token — reuse pending_registrations pattern
        $token = bin2hex(random_bytes(32));
        $exp   = date('Y-m-d H:i:s', time() + 3600); // 1 hour
        db()->prepare("INSERT INTO pending_registrations (username,password,alias,email,token,expires_at) VALUES ('__reset__','',?,?,?,?) ON DUPLICATE KEY UPDATE token=VALUES(token),expires_at=VALUES(expires_at)")->execute([$user['alias'],$user['email'],$token,$exp]);
        // Simple reset email
        $resetUrl = rtrim(SITE_URL,'/') . '/reset_password.php?token=' . urlencode($token);
        $subject  = SITE_NAME . ' — Password Reset Request';
        $body     = "Hi {$user['alias']},\n\nA password reset was requested for your account.\n\nClick here to reset: {$resetUrl}\n\nExpires in 1 hour. If you didn't request this, ignore this email.\n\n— " . SITE_NAME;
        $sent = sendPasswordResetEmail($user['email'], $user['alias'], $resetUrl);
        echo json_encode($sent ? ['success'=>true] : ['success'=>false,'error'=>'Failed to send reset email. Please try again.']);
        break;

    // ─── PLATFORM ACCOUNTS ────────────────────────────────
    case 'platform_accounts_list':
        $status = $_GET['status'] ?? 'pending';
        $uid    = (int)($_GET['user_id'] ?? 0);
        if ($uid) {
            $stmt = db()->prepare("SELECT pa.*, COALESCE(p.name,pa.platform_slug) AS platform_name, u.username, u.alias AS user_alias FROM platform_accounts pa LEFT JOIN platforms p ON pa.platform_slug=p.slug JOIN users u ON pa.user_id=u.id WHERE pa.user_id=? ORDER BY pa.requested_at DESC");
            $stmt->execute([$uid]);
        } else {
            $valid = ['pending','approved','denied','deleted'];
            if (!in_array($status,$valid)) $status='pending';
            $stmt = db()->prepare("SELECT pa.*, COALESCE(p.name,pa.platform_slug) AS platform_name, u.username, u.alias AS user_alias FROM platform_accounts pa LEFT JOIN platforms p ON pa.platform_slug=p.slug JOIN users u ON pa.user_id=u.id WHERE pa.status=? ORDER BY pa.requested_at DESC");
            $stmt->execute([$status]);
        }
        echo json_encode(['success'=>true,'accounts'=>$stmt->fetchAll()]);
        break;

    case 'platform_account_resolve':
        if ($_SERVER['REQUEST_METHOD'] !== 'POST') { echo json_encode(['success'=>false]); exit; }
        $d = json_decode(file_get_contents('php://input'), true);
        $id=$d['id']??0; $status=$d['status']??'';
        $uname=substr(trim($d['platform_username']??''),0,100);
        $pass=substr(trim($d['platform_password']??''),0,200);
        $note=substr(trim($d['admin_note']??''),0,300);
        if (!in_array($status,['approved','denied','deleted'])){echo json_encode(['success'=>false,'error'=>'Invalid status']);exit;}
        $chk=db()->prepare("SELECT user_id,platform_slug FROM platform_accounts WHERE id=?");$chk->execute([$id]);$row=$chk->fetch();
        if (!$row){echo json_encode(['success'=>false,'error'=>'Not found']);exit;}
        db()->prepare("UPDATE platform_accounts SET status=?,platform_username=?,platform_password=?,admin_note=?,resolved_at=NOW(),admin_id=? WHERE id=?")
           ->execute([$status,$uname,$pass,$note,(int)$_SESSION['user_id'],$id]);
        if ($status==='approved'&&$uname) {
            db()->prepare("INSERT INTO game_aliases (user_id,platform_slug,alias) VALUES (?,?,?) ON DUPLICATE KEY UPDATE alias=VALUES(alias)")
               ->execute([$row['user_id'],$row['platform_slug'],$uname]);
        }
        echo json_encode(['success'=>true]);
        break;

    case 'platform_account_update':
        if ($_SERVER['REQUEST_METHOD'] !== 'POST') { echo json_encode(['success'=>false]); exit; }
        $d=json_decode(file_get_contents('php://input'),true);
        $id=$d['id']??0;
        $uname=substr(trim($d['platform_username']??''),0,100);
        $pass=substr(trim($d['platform_password']??''),0,200);
        $note=substr(trim($d['admin_note']??''),0,300);
        $chk=db()->prepare("SELECT user_id,platform_slug FROM platform_accounts WHERE id=?");$chk->execute([$id]);$row=$chk->fetch();
        if (!$row){echo json_encode(['success'=>false,'error'=>'Not found']);exit;}
        db()->prepare("UPDATE platform_accounts SET platform_username=?,platform_password=?,admin_note=? WHERE id=?")
           ->execute([$uname,$pass,$note,$id]);
        if ($uname){
            db()->prepare("INSERT INTO game_aliases (user_id,platform_slug,alias) VALUES (?,?,?) ON DUPLICATE KEY UPDATE alias=VALUES(alias)")
               ->execute([$row['user_id'],$row['platform_slug'],$uname]);
        }
        echo json_encode(['success'=>true]);
        break;

    case 'broadcast_list':
        try {
            $sql = "SELECT b.id, b.subject, b.message, b.target, b.sent_at,
                           u.username AS sender_name,
                           (SELECT COUNT(*) FROM broadcast_reads WHERE broadcast_id=b.id) AS read_count,
                           (SELECT COUNT(*) FROM broadcast_replies WHERE broadcast_id=b.id) AS reply_count,
                           (SELECT COUNT(*) FROM users WHERE status='active' AND is_admin=0) AS total_players
                    FROM broadcasts b
                    JOIN users u ON b.admin_id=u.id
                    ORDER BY b.sent_at DESC
                    LIMIT 100";
            $stmt = db()->query($sql);
            echo json_encode(['success'=>true,'broadcasts'=>$stmt->fetchAll()]);
        } catch(Exception $e) {
            echo json_encode(['success'=>false,'error'=>$e->getMessage()]);
        }
        break;

    case 'broadcast_send':
        if ($_SERVER['REQUEST_METHOD'] !== 'POST') { echo json_encode(['success'=>false]); exit; }
        $d       = json_decode(file_get_contents('php://input'), true);
        $subject = substr(trim($d['subject']??''),0,200);
        $message = substr(trim($d['message']??''),0,5000);
        $target  = in_array($d['target']??'',['all','verified','unverified','admins']) ? $d['target'] : 'all';
        if (!$subject||!$message) { echo json_encode(['success'=>false,'error'=>'Subject and message required']); exit; }
        db()->prepare("INSERT INTO broadcasts (admin_id,subject,message,target) VALUES (?,?,?,?)")
           ->execute([$_SESSION['user_id'],$subject,$message,$target]);
        $bid = db()->lastInsertId();
        // Count recipients
        $countQ = [
            'all'         => "SELECT COUNT(*) FROM users WHERE status='active' AND is_admin=0",
            'verified'    => "SELECT COUNT(*) FROM users WHERE status='active' AND is_admin=0 AND email_verified=1",
            'unverified'  => "SELECT COUNT(*) FROM users WHERE status='active' AND is_admin=0 AND email_verified=0",
            'admins'      => "SELECT COUNT(*) FROM users WHERE is_admin=1",
        ];
        $count = db()->query($countQ[$target])->fetchColumn();
        echo json_encode(['success'=>true,'id'=>$bid,'recipient_count'=>(int)$count]);
        break;

    case 'broadcast_delete':
        if ($_SERVER['REQUEST_METHOD'] !== 'POST') { echo json_encode(['success'=>false]); exit; }
        $d  = json_decode(file_get_contents('php://input'), true);
        $id = (int)($d['id']??0);
        db()->prepare("DELETE FROM broadcasts WHERE id=?")->execute([$id]);
        echo json_encode(['success'=>true]);
        break;

    case 'broadcast_edit':
        if ($_SERVER['REQUEST_METHOD'] !== 'POST') { echo json_encode(['success'=>false]); exit; }
        $d = json_decode(file_get_contents('php://input'), true);
        $id = (int)($d['id'] ?? 0);
        $subject = substr(trim($d['subject'] ?? ''), 0, 200);
        $message = trim($d['message'] ?? '');
        $target  = in_array($d['target']??'', ['all','verified','unverified','admins']) ? $d['target'] : 'all';
        if (!$id || !$subject || !$message) { echo json_encode(['success'=>false,'error'=>'Missing fields']); exit; }
        db()->prepare("UPDATE broadcasts SET subject=?, message=?, target=? WHERE id=?")->execute([$subject, $message, $target, $id]);
        logAdminAction('BROADCAST_EDITED', $adminId, 'broadcast', $id, 'Edited broadcast #'.$id, '', '', 'info');
        echo json_encode(['success'=>true]);
        break;

    case 'broadcast_resend':
        if ($_SERVER['REQUEST_METHOD'] !== 'POST') { echo json_encode(['success'=>false]); exit; }
        $d = json_decode(file_get_contents('php://input'), true);
        $id = (int)($d['id'] ?? 0);
        if (!$id) { echo json_encode(['success'=>false,'error'=>'Missing ID']); exit; }
        $bc = db()->prepare("SELECT * FROM broadcasts WHERE id=?");
        $bc->execute([$id]);
        $orig = $bc->fetch();
        if (!$orig) { echo json_encode(['success'=>false,'error'=>'Broadcast not found']); exit; }
        // Count recipients
        $target = $orig['target'];
        $countSql = "SELECT COUNT(*) FROM users WHERE status='active' AND is_admin=0";
        if ($target === 'verified')   $countSql .= " AND email_verified=1";
        if ($target === 'unverified') $countSql .= " AND email_verified=0";
        $recipientCount = (int)db()->query($countSql)->fetchColumn();
        // Delete old reads so everyone sees it again
        db()->prepare("DELETE FROM broadcast_reads WHERE broadcast_id=?")->execute([$id]);
        // Update sent_at to now
        db()->prepare("UPDATE broadcasts SET sent_at=NOW() WHERE id=?")->execute([$id]);
        logAdminAction('BROADCAST_RESENT', $adminId, 'broadcast', $id, 'Resent broadcast #'.$id.' to '.$recipientCount.' players', '', '', 'info');
        echo json_encode(['success'=>true,'recipient_count'=>$recipientCount]);
        break;

    case 'broadcast_reads':
        $bid  = (int)($_GET['broadcast_id']??0);
        $rows = db()->prepare("SELECT br.read_at, u.username, u.alias FROM broadcast_reads br JOIN users u ON br.user_id=u.id WHERE br.broadcast_id=? ORDER BY br.read_at ASC");
        $rows->execute([$bid]);
        echo json_encode(['success'=>true,'reads'=>$rows->fetchAll()]);
        break;

    case 'broadcast_replies':
        $bid  = (int)($_GET['broadcast_id']??0);
        $rows = db()->prepare("SELECT br.*, u.username, u.alias, u.is_admin FROM broadcast_replies br JOIN users u ON br.user_id=u.id WHERE br.broadcast_id=? ORDER BY br.created_at ASC");
        $rows->execute([$bid]);
        echo json_encode(['success'=>true,'replies'=>$rows->fetchAll()]);
        break;

    case 'broadcast_reply':
        if ($_SERVER['REQUEST_METHOD'] !== 'POST') { echo json_encode(['success'=>false]); exit; }
        $d   = json_decode(file_get_contents('php://input'), true);
        $bid = (int)($d['broadcast_id']??0);
        $msg = substr(trim($d['message']??''),0,1000);
        if (!$bid||!$msg) { echo json_encode(['success'=>false,'error'=>'Required fields missing']); exit; }
        db()->prepare("INSERT INTO broadcast_replies (broadcast_id,user_id,message) VALUES (?,?,?)")
           ->execute([$bid,$_SESSION['user_id'],$msg]);
        echo json_encode(['success'=>true,'id'=>db()->lastInsertId()]);
        break;
        $rows = db()->query("SELECT * FROM cashout_method_types ORDER BY sort_order ASC, id ASC")->fetchAll();
        echo json_encode(['success'=>true,'types'=>$rows]);
        break;

    case 'cashout_methods_create':
        if ($_SERVER['REQUEST_METHOD'] !== 'POST') { echo json_encode(['success'=>false]); exit; }
        $d    = json_decode(file_get_contents('php://input'), true);
        $slug = preg_replace('/[^a-z0-9_]/','',strtolower(trim($d['slug']??'')));
        $label= substr(trim($d['label']??''),0,100);
        $icon = substr(trim($d['icon']??'💰'),0,10);
        $desc = substr(trim($d['description']??''),0,200);
        $sort = (int)($d['sort_order']??99);
        $active=(int)(bool)($d['is_active']??1);
        if (!$slug||!$label){echo json_encode(['success'=>false,'error'=>'Slug and label required']);exit;}
        try {
            db()->prepare("INSERT INTO cashout_method_types (slug,label,icon,description,is_active,sort_order) VALUES (?,?,?,?,?,?)")
               ->execute([$slug,$label,$icon,$desc,$active,$sort]);
            echo json_encode(['success'=>true,'id'=>db()->lastInsertId()]);
        } catch(Exception $e){ echo json_encode(['success'=>false,'error'=>'Slug already exists']); }
        break;

    case 'cashout_methods_update':
        if ($_SERVER['REQUEST_METHOD'] !== 'POST') { echo json_encode(['success'=>false]); exit; }
        $d    = json_decode(file_get_contents('php://input'), true);
        $id   = (int)($d['id']??0);
        $label= substr(trim($d['label']??''),0,100);
        $icon = substr(trim($d['icon']??'💰'),0,10);
        $desc = substr(trim($d['description']??''),0,200);
        $sort = (int)($d['sort_order']??0);
        $active=(int)(bool)($d['is_active']??1);
        if (!$id||!$label){echo json_encode(['success'=>false,'error'=>'ID and label required']);exit;}
        db()->prepare("UPDATE cashout_method_types SET label=?,icon=?,description=?,is_active=?,sort_order=? WHERE id=?")
           ->execute([$label,$icon,$desc,$active,$sort,$id]);
        echo json_encode(['success'=>true]);
        break;

    case 'cashout_methods_delete':
        if ($_SERVER['REQUEST_METHOD'] !== 'POST') { echo json_encode(['success'=>false]); exit; }
        $d=(json_decode(file_get_contents('php://input'),true));
        $id=(int)($d['id']??0);
        if (!$id){echo json_encode(['success'=>false,'error'=>'ID required']);exit;}
        db()->prepare("DELETE FROM cashout_method_types WHERE id=?")->execute([$id]);
        echo json_encode(['success'=>true]);
        break;

    // ──
    case 'platform_account_deny':
        if ($_SERVER['REQUEST_METHOD']!=='POST'){echo json_encode(['success'=>false]);exit;}
        $d=json_decode(file_get_contents('php://input'),true);
        $id=(int)($d['id']??0);$nt=substr(trim($d['admin_note']??''),0,500);
        db()->prepare("UPDATE platform_accounts SET status='denied',admin_note=?,admin_id=? WHERE id=?")->execute([$nt,$_SESSION['user_id'],$id]);
        echo json_encode(['success'=>true]);
        break;

    case 'platform_account_delete':
        if ($_SERVER['REQUEST_METHOD']!=='POST'){echo json_encode(['success'=>false]);exit;}
        $d=json_decode(file_get_contents('php://input'),true);
        $id=(int)($d['id']??0);
        db()->prepare("DELETE FROM platform_accounts WHERE id=?")->execute([$id]);
        echo json_encode(['success'=>true]);
        break;

    case 'platform_accounts_user':
        $uid=(int)($_GET['user_id']??0);
        $stmt=db()->prepare("SELECT pa.*,COALESCE(p.name,pa.platform_name,pa.platform_slug) AS display_name,p.color,p.player_url FROM platform_accounts pa LEFT JOIN platforms p ON pa.platform_slug=p.slug WHERE pa.user_id=? ORDER BY pa.requested_at DESC");
        $stmt->execute([$uid]);
        echo json_encode(['success'=>true,'accounts'=>$stmt->fetchAll()]);
        break;
    case 'activity_log':
    case 'activity_log_v2':
        $page     = max(1, (int)($_GET['page']??1));
        $limit    = 20;
        $offset   = ($page - 1) * $limit;
        $category = trim($_GET['category'] ?? '');
        $severity = trim($_GET['severity'] ?? '');
        $search   = trim($_GET['search']   ?? '');
        $date     = trim($_GET['date']     ?? '');

        $where = ["al.created_at >= DATE_SUB(NOW(), INTERVAL 90 DAY)"];
        $params = [];

        if ($category) { $where[] = "al.category = ?"; $params[] = $category; }
        if ($severity) { $where[] = "al.severity = ?"; $params[] = $severity; }
        if ($date)     { $where[] = "DATE(al.created_at) = ?"; $params[] = $date; }
        if ($search)   {
            $where[] = "(al.action LIKE ? OR al.detail LIKE ? OR u.username LIKE ? OR u.alias LIKE ? OR al.ip LIKE ?)";
            $s = '%'.$search.'%';
            $params = array_merge($params, [$s,$s,$s,$s,$s]);
        }

        $whereStr = implode(' AND ', $where);
        $baseQuery = "FROM activity_log al
                      LEFT JOIN users u ON al.user_id  = u.id
                      LEFT JOIN users a ON al.admin_id = a.id
                      WHERE $whereStr";

        $countStmt = db()->prepare("SELECT COUNT(*) $baseQuery");
        $countStmt->execute($params);
        $total = (int)$countStmt->fetchColumn();

        $dataStmt = db()->prepare("SELECT al.*, u.username, u.alias,
                                          a.username AS admin_username
                                   $baseQuery
                                   ORDER BY al.created_at DESC
                                   LIMIT $limit OFFSET $offset");
        $dataStmt->execute($params);
        $events = $dataStmt->fetchAll();

        // Stats for the current filter set
        $statsParams = $params;
        $statsStmt = db()->prepare("SELECT
            SUM(al.severity='critical') AS critical,
            SUM(al.severity='warning') AS warning,
            COUNT(DISTINCT al.ip) AS unique_ips
            $baseQuery");
        $statsStmt->execute($statsParams);
        $stats = $statsStmt->fetch();

        echo json_encode(['success'=>true,'events'=>$events,'total'=>$total,'page'=>$page,'stats'=>$stats]);
        break;

    case 'activity_log_csv':
        $category = trim($_GET['category'] ?? '');
        $severity = trim($_GET['severity'] ?? '');
        $search   = trim($_GET['search']   ?? '');
        $date     = trim($_GET['date']     ?? '');

        $where = ["al.created_at >= DATE_SUB(NOW(), INTERVAL 90 DAY)"];
        $params = [];
        if ($category) { $where[] = "al.category = ?"; $params[] = $category; }
        if ($severity) { $where[] = "al.severity = ?"; $params[] = $severity; }
        if ($date)     { $where[] = "DATE(al.created_at) = ?"; $params[] = $date; }
        if ($search)   {
            $where[] = "(al.action LIKE ? OR al.detail LIKE ? OR u.username LIKE ?)";
            $s = '%'.$search.'%'; $params = array_merge($params, [$s,$s,$s]);
        }

        $whereStr = implode(' AND ', $where);
        $stmt = db()->prepare("SELECT al.*, u.username, u.alias, a.username AS admin_username
                               FROM activity_log al
                               LEFT JOIN users u ON al.user_id=u.id
                               LEFT JOIN users a ON al.admin_id=a.id
                               WHERE $whereStr ORDER BY al.created_at DESC LIMIT 5000");
        $stmt->execute($params);
        $rows = $stmt->fetchAll();

        header('Content-Type: text/csv');
        header('Content-Disposition: attachment; filename="tomtomgames_audit_' . date('Y-m-d') . '.csv"');
        $out = fopen('php://output', 'w');
        fputcsv($out, ['ID','Timestamp','Category','Severity','Action','Username','Alias','Admin','Detail','Old Value','New Value','IP','User Agent','Page','Session ID']);
        foreach ($rows as $r) {
            fputcsv($out, [$r['id'],$r['created_at'],$r['category'],$r['severity'],$r['action'],
                           $r['username']??'',$r['alias']??'',$r['admin_username']??'',
                           $r['detail']??'',$r['old_value']??'',$r['new_value']??'',
                           $r['ip']??'',$r['user_agent']??'',$r['page']??'',$r['session_id']??'']);
        }
        fclose($out);
        exit;
        break;

    // ─── CASHOUT METHODS: list (admin) ────────────────────
    case 'cashout_methods_list':
        $rows = db()->query("SELECT * FROM cashout_method_types ORDER BY sort_order ASC, id ASC")->fetchAll();
        echo json_encode(['success'=>true,'types'=>$rows]);
        break;

    // ─── PAYMENT SETTINGS: list (admin) ───────────────────
    case 'payment_settings_list':
        $rows = db()->query("SELECT * FROM payment_settings ORDER BY sort_order ASC, id ASC")->fetchAll();
        echo json_encode(['success'=>true,'methods'=>$rows]);
        break;

    case 'payment_settings_update':
        if ($_SERVER['REQUEST_METHOD'] !== 'POST') { echo json_encode(['success'=>false]); exit; }
        $d = json_decode(file_get_contents('php://input'), true);
        $id   = (int)($d['id'] ?? 0);
        $label= substr(trim($d['label']??''), 0, 100);
        $handle = substr(trim($d['handle']??''), 0, 200);
        $inst = substr(trim($d['instructions']??''), 0, 500);
        $enabled = (int)(bool)($d['is_enabled'] ?? 1);
        $sort = (int)($d['sort_order'] ?? 0);
        if (!$id) { echo json_encode(['success'=>false,'error'=>'ID required']); exit; }
        db()->prepare("UPDATE payment_settings SET label=?,handle=?,instructions=?,is_enabled=?,sort_order=? WHERE id=?")
             ->execute([$label,$handle,$inst,$enabled,$sort,$id]);
        echo json_encode(['success'=>true]);
        break;


    // ─── PAYOUT METHODS: get for user ────────────────────────
    case 'payout_methods_get':
        $uid = (int)($_GET['user_id'] ?? 0);
        if (!$uid) { echo json_encode(['success'=>false,'error'=>'user_id required']); exit; }
        $rows = db()->prepare("SELECT * FROM payout_methods WHERE user_id=? ORDER BY is_default DESC, id ASC");
        $rows->execute([$uid]);
        echo json_encode(['success'=>true,'methods'=>$rows->fetchAll()]);
        break;

    // ─── GAME ALIASES: get ────────────────────────────────
    case 'game_aliases_get':
        $uid = (int)($_GET['user_id'] ?? 0);
        if (!$uid) { echo json_encode(['success'=>false,'error'=>'user_id required']); exit; }
        $stmt = db()->prepare("SELECT platform_slug, alias FROM game_aliases WHERE user_id=?");
        $stmt->execute([$uid]);
        $rows = $stmt->fetchAll();
        $map  = [];
        foreach ($rows as $r) $map[$r['platform_slug']] = $r['alias'];
        echo json_encode(['success'=>true,'aliases'=>$map]);
        break;

    // ─── GAME ALIASES: save all ───────────────────────────
    case 'game_aliases_save_all':
        if ($_SERVER['REQUEST_METHOD'] !== 'POST') { echo json_encode(['success'=>false]); exit; }
        $data    = json_decode(file_get_contents('php://input'), true);
        $uid     = (int)($data['user_id'] ?? 0);
        $aliases = $data['aliases'] ?? [];
        if (!$uid) { echo json_encode(['success'=>false,'error'=>'user_id required']); exit; }
        $stmt = db()->prepare("INSERT INTO game_aliases (user_id,platform_slug,alias) VALUES (?,?,?)
            ON DUPLICATE KEY UPDATE alias=VALUES(alias)");
        $del  = db()->prepare("DELETE FROM game_aliases WHERE user_id=? AND platform_slug=?");
        foreach ($aliases as $slug => $alias) {
            $slug  = preg_replace('/[^a-z0-9_]/', '', strtolower(trim($slug)));
            $alias = substr(trim($alias), 0, 100);
            if (!$slug) continue;
            if ($alias === '') $del->execute([$uid, $slug]);
            else $stmt->execute([$uid, $slug, $alias]);
        }
        echo json_encode(['success'=>true]);
        break;

    // ─── PLATFORMS: admin list (active + inactive, no archived) ──
    case 'platforms_admin':
        $rows = db()->query("SELECT * FROM platforms WHERE is_deleted=0 ORDER BY sort_order ASC, id ASC")->fetchAll();
        echo json_encode(['success'=>true,'platforms'=>$rows]);
        break;

    // ─── PLATFORMS: archived list ─────────────────────────
    case 'platforms_archived':
        $rows = db()->query("SELECT * FROM platforms WHERE is_deleted=1 ORDER BY deleted_at DESC")->fetchAll();
        echo json_encode(['success'=>true,'platforms'=>$rows]);
        break;

    // ─── PLATFORMS: restore archived ──────────────────────
    case 'platforms_restore':
        if ($_SERVER['REQUEST_METHOD'] !== 'POST') { echo json_encode(['success'=>false]); exit; }
        $d  = json_decode(file_get_contents('php://input'), true);
        $id = (int)($d['id'] ?? 0);
        if (!$id) { echo json_encode(['success'=>false,'error'=>'ID required']); exit; }
        db()->prepare("UPDATE platforms SET is_deleted=0, deleted_at=NULL, updated_at=NOW() WHERE id=?")->execute([$id]);
        echo json_encode(['success'=>true]);
        break;

    // ─── PLATFORMS: permanent delete (archived only) ──────
    case 'platforms_purge':
        if ($_SERVER['REQUEST_METHOD'] !== 'POST') { echo json_encode(['success'=>false]); exit; }
        $d  = json_decode(file_get_contents('php://input'), true);
        $id = (int)($d['id'] ?? 0);
        if (!$id) { echo json_encode(['success'=>false,'error'=>'ID required']); exit; }
        db()->prepare("DELETE FROM platforms WHERE id=? AND is_deleted=1")->execute([$id]);
        echo json_encode(['success'=>true]);
        break;

    // ─── PLATFORMS: create ────────────────────────────────
    case 'platforms_create':
        if ($_SERVER['REQUEST_METHOD'] !== 'POST') { echo json_encode(['success'=>false]); exit; }
        if ((int)($_SESSION['user_id'] ?? 0) !== MASTER_ADMIN_ID) { echo json_encode(['success'=>false,'error'=>'Only master admin can add games']); exit; }
        $d             = json_decode(file_get_contents('php://input'), true);
        $isMasterAdmin = true;
        $slug   = preg_replace('/[^a-z0-9_]/', '', strtolower(trim($d['slug'] ?? '')));
        $name   = substr(trim($d['name']       ?? ''), 0, 100);
        $purl   = substr(trim($d['player_url'] ?? ''), 0, 500);
        $color  = preg_match('/^#[0-9a-fA-F]{3,8}$/', $d['color']??'') ? $d['color'] : '#f0c040';
        $sort   = (int)($d['sort_order'] ?? 99);
        $active = (int)(bool)($d['is_active'] ?? 1);
        $agent_link         = $isMasterAdmin ? substr(trim($d['agent_link']         ?? ''), 0, 500) : '';
        $agent_login        = $isMasterAdmin ? substr(trim($d['agent_login']        ?? ''), 0, 200) : '';
        $agent_password     = $isMasterAdmin ? substr(trim($d['agent_password']     ?? ''), 0, 200) : '';
        $games_link         = $isMasterAdmin ? substr(trim($d['games_link']         ?? ''), 0, 500) : '';
        $agent_guide        = $isMasterAdmin ? trim($d['agent_guide'] ?? '') : '';
        $sub_agent_login    = $isMasterAdmin ? substr(trim($d['sub_agent_login']    ?? ''), 0, 200) : '';
        $sub_agent_password = $isMasterAdmin ? substr(trim($d['sub_agent_password'] ?? ''), 0, 200) : '';
        $cashier_login      = $isMasterAdmin ? substr(trim($d['cashier_login']      ?? ''), 0, 200) : '';
        $cashier_password   = $isMasterAdmin ? substr(trim($d['cashier_password']   ?? ''), 0, 200) : '';
        if (!$slug||!$name||!$purl) { echo json_encode(['success'=>false,'error'=>'Slug, name, and player URL required']); exit; }
        // Check if slug belongs to an archived platform — reactivate it instead of inserting
        $existing = db()->prepare("SELECT id FROM platforms WHERE slug=? AND is_deleted=1 LIMIT 1");
        $existing->execute([$slug]);
        $archivedId = $existing->fetchColumn();
        if ($archivedId) {
            db()->prepare("UPDATE platforms SET name=?,player_url=?,agent_link=?,agent_login=?,agent_password=?,games_link=?,agent_guide=?,sub_agent_login=?,sub_agent_password=?,cashier_login=?,cashier_password=?,color=?,sort_order=?,is_active=?,is_deleted=0,deleted_at=NULL,updated_at=NOW() WHERE id=?")
               ->execute([$name,$purl,$agent_link,$agent_login,$agent_password,$games_link,$agent_guide,$sub_agent_login,$sub_agent_password,$cashier_login,$cashier_password,$color,$sort,$active,$archivedId]);
            echo json_encode(['success'=>true,'id'=>$archivedId,'restored'=>true]);
        } else {
            try {
                db()->prepare("INSERT INTO platforms (slug,name,player_url,agent_link,agent_login,agent_password,games_link,agent_guide,sub_agent_login,sub_agent_password,cashier_login,cashier_password,color,sort_order,is_active) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)")
                   ->execute([$slug,$name,$purl,$agent_link,$agent_login,$agent_password,$games_link,$agent_guide,$sub_agent_login,$sub_agent_password,$cashier_login,$cashier_password,$color,$sort,$active]);
                echo json_encode(['success'=>true,'id'=>db()->lastInsertId()]);
            } catch (Exception $e) { echo json_encode(['success'=>false,'error'=>'Slug already in use by an active game']); }
        }
        break;

    // ─── PLATFORMS: update ────────────────────────────────
    case 'platforms_update':
        if ($_SERVER['REQUEST_METHOD'] !== 'POST') { echo json_encode(['success'=>false]); exit; }
        $d             = json_decode(file_get_contents('php://input'), true);
        $isMasterAdmin = (int)($_SESSION['user_id'] ?? 0) === MASTER_ADMIN_ID;
        $id     = (int)($d['id'] ?? 0);
        $name   = substr(trim($d['name']       ?? ''), 0, 100);
        $purl   = substr(trim($d['player_url'] ?? ''), 0, 500);
        $color  = preg_match('/^#[0-9a-fA-F]{3,8}$/', $d['color']??'') ? $d['color'] : '#f0c040';
        $sort   = (int)($d['sort_order'] ?? 99);
        $active = (int)(bool)($d['is_active'] ?? 1);
        if (!$id||!$name||!$purl) { echo json_encode(['success'=>false,'error'=>'ID, name, and URL required']); exit; }
        if ($isMasterAdmin) {
            $agent_link         = substr(trim($d['agent_link']         ?? ''), 0, 500);
            $agent_login        = substr(trim($d['agent_login']        ?? ''), 0, 200);
            $agent_password     = substr(trim($d['agent_password']     ?? ''), 0, 200);
            $games_link         = substr(trim($d['games_link']         ?? ''), 0, 500);
            $agent_guide        = trim($d['agent_guide'] ?? '');
            $sub_agent_login    = substr(trim($d['sub_agent_login']    ?? ''), 0, 200);
            $sub_agent_password = substr(trim($d['sub_agent_password'] ?? ''), 0, 200);
            $cashier_login      = substr(trim($d['cashier_login']      ?? ''), 0, 200);
            $cashier_password   = substr(trim($d['cashier_password']   ?? ''), 0, 200);
            db()->prepare("UPDATE platforms SET name=?,player_url=?,agent_link=?,agent_login=?,agent_password=?,games_link=?,agent_guide=?,sub_agent_login=?,sub_agent_password=?,cashier_login=?,cashier_password=?,color=?,sort_order=?,is_active=?,updated_at=NOW() WHERE id=?")
               ->execute([$name,$purl,$agent_link,$agent_login,$agent_password,$games_link,$agent_guide,$sub_agent_login,$sub_agent_password,$cashier_login,$cashier_password,$color,$sort,$active,$id]);
        } else {
            db()->prepare("UPDATE platforms SET name=?,player_url=?,color=?,sort_order=?,is_active=?,updated_at=NOW() WHERE id=?")
               ->execute([$name,$purl,$color,$sort,$active,$id]);
        }
        echo json_encode(['success'=>true]);
        break;

    // ─── PLATFORMS: soft-delete (archive) ────────────────
    case 'platforms_delete':
        if ($_SERVER['REQUEST_METHOD'] !== 'POST') { echo json_encode(['success'=>false]); exit; }
        if ((int)($_SESSION['user_id'] ?? 0) !== MASTER_ADMIN_ID) { echo json_encode(['success'=>false,'error'=>'Only master admin can archive games']); exit; }
        $d  = json_decode(file_get_contents('php://input'), true);
        $id = (int)($d['id'] ?? 0);
        if (!$id) { echo json_encode(['success'=>false,'error'=>'ID required']); exit; }
        db()->prepare("UPDATE platforms SET is_deleted=1, deleted_at=NOW(), updated_at=NOW() WHERE id=?")->execute([$id]);
        echo json_encode(['success'=>true]);
        break;
    case 'billing_get':
        $uid = (int)($_GET['user_id'] ?? 0);
        if (!$uid) { echo json_encode(['success'=>false,'error'=>'user_id required']); exit; }
        $stmt = db()->prepare("SELECT * FROM saved_billing WHERE user_id=?");
        $stmt->execute([$uid]);
        $row = $stmt->fetch();
        // Admin sees masked card info
        if ($row) {
            $row['card_display'] = $row['card_brand'] && $row['card_last4']
                ? $row['card_brand'] . ' ····' . $row['card_last4'] : null;
            // Don't expose raw sq_card_id
            unset($row['sq_card_id']);
        }
        echo json_encode(['success'=>true,'billing'=>$row ?: null]);
        break;

    // ─── BILLING: save/update ────────────────────────────────
    case 'billing_save':
        if ($_SERVER['REQUEST_METHOD'] !== 'POST') { echo json_encode(['success'=>false]); exit; }
        $data = json_decode(file_get_contents('php://input'), true);
        $uid  = (int)($data['user_id'] ?? 0);
        if (!$uid) { echo json_encode(['success'=>false,'error'=>'user_id required']); exit; }
        $stmt = db()->prepare("
            INSERT INTO saved_billing (user_id,first_name,last_name,email,address,city,state,zip)
            VALUES (?,?,?,?,?,?,?,?)
            ON DUPLICATE KEY UPDATE
                first_name=VALUES(first_name), last_name=VALUES(last_name),
                email=VALUES(email), address=VALUES(address),
                city=VALUES(city), state=VALUES(state), zip=VALUES(zip)
        ");
        $stmt->execute([
            $uid,
            substr(trim($data['first_name']??''),0,80),
            substr(trim($data['last_name'] ??''),0,80),
            substr(strtolower(trim($data['email']??'')),0,150),
            substr(trim($data['address']   ??''),0,200),
            substr(trim($data['city']      ??''),0,80),
            strtoupper(substr(trim($data['state']??''),0,2)),
            substr(trim($data['zip']       ??''),0,10),
        ]);
        echo json_encode(['success'=>true]);
        break;

    // ─── BILLING: clear card ─────────────────────────────────
    case 'billing_clear_card':
        if ($_SERVER['REQUEST_METHOD'] !== 'POST') { echo json_encode(['success'=>false]); exit; }
        $data = json_decode(file_get_contents('php://input'), true);
        $uid  = (int)($data['user_id'] ?? 0);
        db()->prepare("UPDATE saved_billing SET card_brand=NULL,card_last4=NULL,card_exp_month=NULL,card_exp_year=NULL,sq_card_id=NULL WHERE user_id=?")->execute([$uid]);
        echo json_encode(['success'=>true]);
        break;

    // ─── BILLING: clear all ──────────────────────────────────
    case 'billing_clear_all':
        if ($_SERVER['REQUEST_METHOD'] !== 'POST') { echo json_encode(['success'=>false]); exit; }
        $data = json_decode(file_get_contents('php://input'), true);
        $uid  = (int)($data['user_id'] ?? 0);
        db()->prepare("DELETE FROM saved_billing WHERE user_id=?")->execute([$uid]);
        echo json_encode(['success'=>true]);
        break;

    // ─── RESEND VERIFICATION (from admin) ─────────────────────
    case 'resend_verification':
        if ($_SERVER['REQUEST_METHOD'] !== 'POST') { echo json_encode(['success'=>false]); exit; }
        $data = json_decode(file_get_contents('php://input'), true);
        $uid  = (int)($data['user_id'] ?? 0);
        $stmt = db()->prepare("SELECT email,alias FROM users WHERE id=?");
        $stmt->execute([$uid]);
        $user = $stmt->fetch();
        if (!$user) { echo json_encode(['success'=>false,'error'=>'User not found']); exit; }
        $result = resendVerification($user['email']);
        echo json_encode($result);
        break;

    // ─── CHAT: inbox list ──────────────────────────────────
    case 'chat_inbox':
        $rows = db()->query("
            SELECT u.id AS user_id, u.username, u.alias,
                   cm.message AS last_message, cm.sender AS last_sender,
                   cm.created_at AS last_time,
                   (SELECT COUNT(*) FROM chat_messages
                    WHERE user_id=u.id AND sender='user' AND is_read=0) AS unread_count
            FROM users u
            INNER JOIN chat_messages cm ON cm.id=(
                SELECT id FROM chat_messages WHERE user_id=u.id ORDER BY id DESC LIMIT 1
            )
            ORDER BY cm.created_at DESC
        ")->fetchAll();
        echo json_encode(['success'=>true,'inbox'=>$rows]);
        break;

    // ─── CHAT: full thread for one user ───────────────────
    case 'chat_thread':
        $tid   = (int)($_GET['user_id'] ?? 0);
        $since = (int)($_GET['since']   ?? 0);
        if (!$tid) { echo json_encode(['success'=>false,'error'=>'user_id required']); exit; }
        $stmt = db()->prepare("SELECT id,sender,message,is_read,created_at FROM chat_messages WHERE user_id=? AND id>? ORDER BY id ASC LIMIT 300");
        $stmt->execute([$tid, $since]);
        // Mark user messages read
        db()->prepare("UPDATE chat_messages SET is_read=1 WHERE user_id=? AND sender='user' AND is_read=0")->execute([$tid]);
        $uStmt = db()->prepare("SELECT id,username,alias,tokens FROM users WHERE id=?");
        $uStmt->execute([$tid]);
        echo json_encode(['success'=>true,'messages'=>$stmt->fetchAll(),'user'=>$uStmt->fetch()]);
        break;

    // ─── CHAT: admin reply ────────────────────────────────
    case 'chat_admin_send':
        if ($_SERVER['REQUEST_METHOD'] !== 'POST') { echo json_encode(['success'=>false]); exit; }
        $data = json_decode(file_get_contents('php://input'), true);
        $tid  = (int)($data['user_id'] ?? 0);
        $msg  = trim($data['message']  ?? '');
        if (!$tid || empty($msg)) { echo json_encode(['success'=>false,'error'=>'Invalid']); exit; }
        $stmt = db()->prepare("INSERT INTO chat_messages (user_id,sender,message) VALUES (?,'admin',?)");
        $stmt->execute([$tid, $msg]);
        echo json_encode(['success'=>true,'id'=>db()->lastInsertId()]);
        break;

    // ─── CHAT: clear single user thread ───────────────────
    case 'chat_clear_thread':
        if ($_SERVER['REQUEST_METHOD'] !== 'POST') { echo json_encode(['success'=>false]); exit; }
        $data = json_decode(file_get_contents('php://input'), true);
        $tid  = (int)($data['user_id'] ?? 0);
        if (!$tid) { echo json_encode(['success'=>false,'error'=>'user_id required']); exit; }
        db()->prepare("DELETE FROM chat_messages WHERE user_id=?")->execute([$tid]);
        echo json_encode(['success'=>true]);
        break;

    // ─── CHAT: clear ALL chats ────────────────────────────
    case 'chat_clear_all':
        if ($_SERVER['REQUEST_METHOD'] !== 'POST') { echo json_encode(['success'=>false]); exit; }
        try {
            db()->exec("DELETE FROM chat_messages");
            logAdminAction('CHAT_CLEAR_ALL', (int)$_SESSION['user_id'], 'chat', 0, 'Cleared all chat messages', '', '', 'warning');
            echo json_encode(['success'=>true]);
        } catch (Exception $e) {
            echo json_encode(['success'=>false,'error'=>'Failed to clear chat']);
        }
        break;
    case 'chat_unread':
        $count = db()->query("SELECT COUNT(*) FROM chat_messages WHERE sender='user' AND is_read=0")->fetchColumn();
        echo json_encode(['success'=>true,'count'=>(int)$count]);
        break;

    default:
        echo json_encode(['success'=>false,'error'=>'Unknown action']);
}
