<?php
// webhook.php — shop + gmail bridge + OTP notifications + delete flow

require __DIR__ . '/db.php';
require __DIR__ . '/bot_functions.php';
$config = require __DIR__ . '/config.php';
$input = json_decode(file_get_contents('php://input'), true);
if (!$input) exit;

// try include QR lib if present
$has_qrcode_lib = false;
if (file_exists(__DIR__ . '/phpqrcode/qrlib.php')) {
    require_once __DIR__ . '/phpqrcode/qrlib.php';
    if (class_exists('QRcode')) $has_qrcode_lib = true;
}

/* ---------------- browse_sessions table (auto setup) ---------------- */
try {
    $pdo->exec("
        CREATE TABLE IF NOT EXISTS browse_sessions (
            id INT AUTO_INCREMENT PRIMARY KEY,
            user_id INT NOT NULL,
            chat_id BIGINT NOT NULL,
            category_id INT NOT NULL,
            page INT NOT NULL DEFAULT 1,
            msg_ids TEXT NOT NULL,
            updated_at TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
            UNIQUE KEY uniq_user (user_id)
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
    ");
} catch (PDOException $e) {
    error_log('DB ERROR browse_sessions create: ' . $e->getMessage());
}

/* ---------------- orders table alter (for QR + error messages) --------------- */
try {
    $pdo->exec("ALTER TABLE orders ADD COLUMN qr_message_id BIGINT NULL");
} catch (PDOException $e) {}
try {
    $pdo->exec("ALTER TABLE orders ADD COLUMN last_error_message_id BIGINT NULL");
} catch (PDOException $e) {}
// snapshot of gmail at purchase time (for Show Purchased ids)
try {
    $pdo->exec("ALTER TABLE orders ADD COLUMN gmail_snapshot VARCHAR(255) NULL");
} catch (PDOException $e) {}

/* *** NEW: extra security columns on orders *** */
try {
    $pdo->exec("ALTER TABLE orders ADD COLUMN amount DECIMAL(10,2) NULL");
} catch (PDOException $e) {}
try {
    $pdo->exec("ALTER TABLE orders ADD COLUMN txn_ref VARCHAR(64) NULL");
} catch (PDOException $e) {}
try {
    $pdo->exec("ALTER TABLE orders ADD COLUMN verified_at DATETIME NULL");
} catch (PDOException $e) {}

/* ---------------- gmail_notifications table (for auto delete of gmail msgs) --------------- */
try {
    $pdo->exec("
        CREATE TABLE IF NOT EXISTS gmail_notifications (
            id INT AUTO_INCREMENT PRIMARY KEY,
            user_id INT NOT NULL,
            chat_id BIGINT NOT NULL,
            gmail VARCHAR(255) NULL,
            message_id BIGINT NOT NULL,
            type ENUM('otp','notice') NOT NULL DEFAULT 'otp',
            delete_at DATETIME NOT NULL,
            created_at TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
    ");
} catch (PDOException $e) {
    error_log('DB ERROR gmail_notifications create: ' . $e->getMessage());
}

// add gmail + indexes if table already existed
try {
    $pdo->exec("ALTER TABLE gmail_notifications ADD COLUMN gmail VARCHAR(255) NULL");
} catch (PDOException $e) {}
try {
    $pdo->exec("CREATE INDEX idx_gmail ON gmail_notifications (gmail)");
} catch (PDOException $e) {}
try {
    $pdo->exec("CREATE INDEX idx_delete_at ON gmail_notifications (delete_at)");
} catch (PDOException $e) {}

/* --------------- accounts alter (store Gen ID / delete command / status) --------------- */
try {
    $pdo->exec("ALTER TABLE accounts ADD COLUMN gmail_gen_id VARCHAR(32) NULL");
} catch (PDOException $e) {}
try {
    $pdo->exec("ALTER TABLE accounts ADD COLUMN gmail_delete_cmd VARCHAR(255) NULL");
} catch (PDOException $e) {}
try {
    $pdo->exec("ALTER TABLE accounts ADD COLUMN gmail_status ENUM('none','pending','ok','error') NOT NULL DEFAULT 'none'");
} catch (PDOException $e) {}
try {
    $pdo->exec("ALTER TABLE accounts ADD COLUMN gmail_error TEXT NULL");
} catch (PDOException $e) {}

/* ---------------- helpers ---------------- */

function getOwnerUsername($pdo, $owner_tg_id) {
    try {
        $stmt = $pdo->prepare("SELECT username FROM users WHERE telegram_id = ? LIMIT 1");
        $stmt->execute([$owner_tg_id]);
        $r = $stmt->fetch();
        if ($r && !empty($r['username'])) return $r['username'];
    } catch (PDOException $e) {}
    return null;
}

function format_inr_label($price) {
    if ($price === null) return '';
    $p = (float)$price;
    if (floor($p) == $p) return '₹' . number_format($p, 0);
    return '₹' . number_format($p, 2);
}

/**
 * Mask gmail for user-facing messages.
 * Example: you123@hi2.in => you***@hi2.in
 */
function mask_gmail($gmail) {
    $parts = explode('@', $gmail, 2);
    if (count($parts) !== 2) {
        return $gmail;
    }
    $local  = $parts[0];
    $domain = $parts[1];

    $prefixLen = min(3, max(0, strlen($local)));
    $prefix    = substr($local, 0, $prefixLen);
    return $prefix . '***@' . $domain;
}

// small wrapper to call Telegram API
if (!function_exists('apiRequest')) {
    function apiRequest($method, $params = []) {
        global $config;
        $token = $config['bot_token'] ?? null;
        if (!$token) return false;
        $url = "https://api.telegram.org/bot{$token}/{$method}";
        $ch = curl_init($url);
        $payload = json_encode($params);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
        curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        $resp = curl_exec($ch);
        curl_close($ch);
        return $resp;
    }
}

/* ---------------- browse session helpers ---------------- */

function getBrowseSession($pdo, $user_id) {
    try {
        $stmt = $pdo->prepare("SELECT * FROM browse_sessions WHERE user_id = ? LIMIT 1");
        $stmt->execute([$user_id]);
        return $stmt->fetch();
    } catch (PDOException $e) {
        error_log("DB ERROR getBrowseSession: " . $e->getMessage());
        return null;
    }
}

function saveBrowseSession($pdo, $user_id, $chat_id, $category_id, $page, array $msg_ids) {
    $msg_ids = array_values(array_unique(array_map('intval', $msg_ids)));
    $json = json_encode($msg_ids);
    if ($json === false) $json = '[]';

    try {
        $stmt = $pdo->prepare("
            INSERT INTO browse_sessions (user_id, chat_id, category_id, page, msg_ids)
            VALUES (?,?,?,?,?)
            ON DUPLICATE KEY UPDATE
                chat_id = VALUES(chat_id),
                category_id = VALUES(category_id),
                page = VALUES(page),
                msg_ids = VALUES(msg_ids)
        ");
        $stmt->execute([$user_id, $chat_id, $category_id, $page, $json]);
    } catch (PDOException $e) {
        error_log("DB ERROR saveBrowseSession: " . $e->getMessage());
    }
}

function cleanupBrowseSession($pdo, $user_id, $chat_id, $keep_message_id = null) {
    if (!$user_id) return;
    $session = getBrowseSession($pdo, $user_id);
    if (!$session) return;

    $raw = $session['msg_ids'] ?? '[]';
    if (is_string($raw)) {
        $ids = json_decode($raw, true);
        if (!is_array($ids)) $ids = [];
    } elseif (is_array($raw)) {
        $ids = $raw;
    } else {
        $ids = [];
    }

    foreach ($ids as $mid) {
        $mid = (int)$mid;
        if ($mid <= 0) continue;
        if ($keep_message_id !== null && (int)$keep_message_id === $mid) continue;
        apiRequest('deleteMessage', [
            'chat_id'    => $chat_id,
            'message_id' => $mid
        ]);
    }

    if ($keep_message_id === null) {
        try {
            $stmt = $pdo->prepare("DELETE FROM browse_sessions WHERE user_id = ?");
            $stmt->execute([$user_id]);
        } catch (PDOException $e) {
            error_log("DB ERROR cleanupBrowseSession delete: " . $e->getMessage());
        }
    } else {
        try {
            $json = json_encode([(int)$keep_message_id]);
            $stmt = $pdo->prepare("UPDATE browse_sessions SET msg_ids = ? WHERE user_id = ?");
            $stmt->execute([$json, $user_id]);
        } catch (PDOException $e) {
            error_log("DB ERROR cleanupBrowseSession update: " . $e->getMessage());
        }
    }
}

/* cancel all pending payments UI for user */
function cleanupUserPendingPayments($pdo, $userRow) {
    if (!$userRow || !isset($userRow['id'])) return;
    $user_id = (int)$userRow['id'];
    $chat_id = $userRow['telegram_id'] ?? null;
    if (!$chat_id) return;

    try {
        $stmt = $pdo->prepare("SELECT id, qr_message_id, last_error_message_id FROM orders WHERE user_id = ? AND status = 'pending'");
        $stmt->execute([$user_id]);
        $rows = $stmt->fetchAll();
    } catch (PDOException $e) {
        error_log("DB ERROR cleanupUserPendingPayments fetch: " . $e->getMessage());
        return;
    }

    foreach ($rows as $r) {
        if (!empty($r['qr_message_id'])) {
            apiRequest('deleteMessage', [
                'chat_id'    => $chat_id,
                'message_id' => (int)$r['qr_message_id']
            ]);
        }
        if (!empty($r['last_error_message_id'])) {
            apiRequest('deleteMessage', [
                'chat_id'    => $chat_id,
                'message_id' => (int)$r['last_error_message_id']
            ]);
        }

        try {
            $upd = $pdo->prepare("UPDATE orders SET status='cancelled', qr_message_id=NULL, last_error_message_id=NULL, updated_at = NOW() WHERE id = ?");
            $upd->execute([$r['id']]);
        } catch (PDOException $e) {
            error_log("DB ERROR cleanupUserPendingPayments update: " . $e->getMessage());
        }
    }
}

/* ---------------- existing helpers ---------------- */

function getUserRow($pdo, $telegram_id) {
    try {
        $stmt = $pdo->prepare("SELECT * FROM users WHERE telegram_id = ?");
        $stmt->execute([$telegram_id]);
        return $stmt->fetch();
    } catch (PDOException $e) {
        error_log("DB ERROR getUserRow: " . $e->getMessage());
        return false;
    }
}

function createUserIfNotExists($pdo, $tg) {
    try {
        $u = getUserRow($pdo, $tg['id']);
        if ($u) return $u;
        $token = bin2hex(random_bytes(16));
        $username   = $tg['username'] ?? null;
        $first_name = $tg['first_name'] ?? null;
        $last_name  = $tg['last_name'] ?? null;

        $stmt = $pdo->prepare("INSERT INTO users (telegram_id, username, first_name, last_name, token) VALUES (?,?,?,?,?)");
        $stmt->execute([$tg['id'], $username, $first_name, $last_name, $token]);
        return getUserRow($pdo, $tg['id']);
    } catch (PDOException $e) {
        error_log("DB ERROR createUserIfNotExists: " . $e->getMessage());
        return false;
    }
}

function isOwner($tg_id) {
    global $config;
    return (string)$tg_id === (string)$config['owner_chat_id'];
}

/* send purchased items list */
function sendUserPurchases($pdo, $userRow, $chat_id) {
    global $config;
    try {
        $stmt = $pdo->prepare("
            SELECT 
                o.id           AS order_id,
                o.created_at   AS ordered_at,
                o.gmail_snapshot,
                a.*
            FROM orders o
            JOIN accounts a ON o.account_id = a.id
            WHERE o.user_id = ? 
              AND o.status = 'paid' 
              AND o.visible = 1
            ORDER BY o.created_at DESC
        ");
        $stmt->execute([$userRow['id']]);
        $rows = $stmt->fetchAll();
    } catch (PDOException $e) {
        error_log("DB ERROR sendUserPurchases: ".$e->getMessage());
        sendMessage($chat_id, "⚠️ Internal error. Try again later.");
        return;
    }

    if (!$rows) {
        sendMessage($chat_id, "📭 You don't have any visible purchases right now.");
        return;
    }

    foreach ($rows as $r) {
        $img_url   = $config['site_url'] . '/uploads/' . basename($r['image_path']);
        $title     = htmlspecialchars($r['title'] ?: 'Account');
        $level     = $r['level'] ? htmlspecialchars($r['level']) : null;

        // prefer current accounts.gmail, else use snapshot saved in orders
        $gmail_raw = $r['gmail'] ?: $r['gmail_snapshot'];
        $gmail     = $gmail_raw ? htmlspecialchars($gmail_raw) : null;

        $cred_user = htmlspecialchars($r['username_value'] ?? '—');
        $cred_pass = htmlspecialchars($r['password_value'] ?? '—');

        $price_block = "";
        if (!is_null($r['price'])) {
            $p = number_format((float)$r['price'], 2);
            $price_block = "<blockquote><b>💰 Price:</b> <code>{$p}</code></blockquote>";
        }

        $lines = [];
        $lines[] = "<blockquote><b>🎉 {$title}</b></blockquote>";
        if ($level) {
            $lines[] = "<blockquote><b>📶 Level:</b> <code>{$level}</code></blockquote>";
        }
        $lines[] = "<blockquote><b>👤 Username:</b> <code>{$cred_user}</code></blockquote>";
        $lines[] = "<blockquote><b>🔑 Password:</b> <code>{$cred_pass}</code></blockquote>";
        if ($gmail) {
            $lines[] = "<blockquote><b>📧 Gmail:</b> <code>{$gmail}</code></blockquote>";
        }
        if ($price_block) $lines[] = $price_block;
        $lines[] = "<b>🙏 Thanks for purchasing — keep these credentials safe.</b>";

        $caption = implode("\n", array_filter($lines));
        $kb = ['inline_keyboard' => [
            [
                ['text' => '🗑️ Remove', 'callback_data' => "remove_{$r['order_id']}"],
                ['text' => '☎️ Contact Owner', 'url' => 'https://t.me/' . ltrim($config['owner_username'], '@')]
            ]
        ]];

        sendPhoto($chat_id, $img_url, $caption, $kb);
    }
}

/* map gmail -> buyer (from paid orders) — CORE SECURITY BINDING */
function findBuyerByGmail($pdo, $gmail) {
    try {
        $stmt = $pdo->prepare("
            SELECT 
                u.id          AS user_id,
                u.telegram_id AS chat_id,
                o.id          AS order_id,
                a.id          AS account_id
            FROM orders o
            JOIN accounts a ON o.account_id = a.id
            JOIN users u    ON o.user_id = u.id
            WHERE a.gmail = ? 
              AND o.status = 'paid'
            ORDER BY o.created_at DESC
            LIMIT 1
        ");
        $stmt->execute([$gmail]);
        return $stmt->fetch();
    } catch (PDOException $e) {
        error_log('DB ERROR findBuyerByGmail: ' . $e->getMessage());
        return null;
    }
}

/* ---------------- incoming message ---------------- */

if (isset($input['message'])) {
    $msg     = $input['message'];
    $chat_id = $msg['chat']['id'];
    $from    = $msg['from'];
    $user    = createUserIfNotExists($pdo, $from);
    $text    = $msg['text'] ?? '';

/* ---- BRIDGE: messages coming from VPS USERBOT (Telethon) ---- */
    if (!empty($config['mail_userbot_id']) && (string)$from['id'] === (string)$config['mail_userbot_id']) {
        if (!$text) exit;

        // -------------- CASE 1: Gen ID + delete command mapping --------------
        if (
            preg_match('/Gen ID\s*:\s*([0-9]+)/i', $text, $gm_id) &&
            preg_match('/Mail\s*:\s*([^\s]+)/i', $text, $gm_mail) &&
            preg_match('/Dlt Command\s*:\s*(\/delete_\d+)/i', $text, $gm_del)
        ) {
            $gen_id     = trim($gm_id[1]);
            $gmail      = trim($gm_mail[1]);
            $delete_cmd = trim($gm_del[1]);

            try {
                $stmt = $pdo->prepare("
                    UPDATE accounts
                    SET gmail_gen_id     = ?,
                        gmail_delete_cmd = ?,
                        gmail_status     = 'ok',
                        gmail_error      = NULL
                    WHERE gmail = ?
                    LIMIT 5
                ");
                $stmt->execute([$gen_id, $delete_cmd, $gmail]);
            } catch (PDOException $e) {
                error_log('DB ERROR save Gen ID/delete_cmd: ' . $e->getMessage());
            }

            if (!empty($config['owner_chat_id'])) {
                $info = "✅ Gmail linked\n\n📧 <code>{$gmail}</code>\n🆔 Gen ID: <code>{$gen_id}</code>\n🗑️ Cmd: <code>{$delete_cmd}</code>";
                apiRequest('sendMessage', [
                    'chat_id'    => $config['owner_chat_id'],
                    'text'       => $info,
                    'parse_mode' => 'HTML'
                ]);
            }
            exit;
        }

        // -------------- CASE 2: Mail replies (error / delete success / pwd changed) --------------
        if (
            preg_match('/Mail\s*:\s*([^\s]+)/i', $text, $gm_mail2) &&
            preg_match('/Mail-Reply\s*:\s*(.+)$/is', $text, $gm_reply2)
        ) {
            $gmail = trim($gm_mail2[1]);
            $reply = trim($gm_reply2[1]);
            $lower = strtolower($reply);

            /* ---- DELETE SUCCESS: "Your fakemail address ... has been deleted." ---- */
            if (strpos($lower, 'has been deleted') !== false) {
                // find buyer
                $buyer = findBuyerByGmail($pdo, $gmail);
                if ($buyer && !empty($buyer['chat_id'])) {
                    $buyer_chat    = $buyer['chat_id'];
                    $buyer_user_id = $buyer['user_id'];

                    // mark account gmail inactive + clear bindings
                    try {
                        $stmt = $pdo->prepare("
                            UPDATE accounts
                            SET gmail_status     = 'none',
                                gmail            = NULL,
                                gmail_gen_id     = NULL,
                                gmail_delete_cmd = NULL,
                                gmail_error      = NULL
                            WHERE gmail = ?
                        ");
                        $stmt->execute([$gmail]);
                    } catch (PDOException $e) {
                        error_log('DB ERROR accounts gmail mark none on delete: ' . $e->getMessage());
                    }

                    // delete all old notifications (OTPs, security, delete-request)
                    try {
                        $stmt = $pdo->prepare("
                            SELECT chat_id, message_id 
                            FROM gmail_notifications 
                            WHERE gmail = ?
                        ");
                        $stmt->execute([$gmail]);
                        $oldRows = $stmt->fetchAll();
                    } catch (PDOException $e) {
                        $oldRows = [];
                        error_log('DB ERROR gmail_notifications fetch for wipe: ' . $e->getMessage());
                    }

                    foreach ($oldRows as $r) {
                        $c = (int)$r['chat_id'];
                        $m = (int)$r['message_id'];
                        if ($c && $m) {
                            apiRequest('deleteMessage', [
                                'chat_id'    => $c,
                                'message_id' => $m
                            ]);
                        }
                    }

                    try {
                        $stmt = $pdo->prepare("DELETE FROM gmail_notifications WHERE gmail = ?");
                        $stmt->execute([$gmail]);
                    } catch (PDOException $e) {
                        error_log('DB ERROR gmail_notifications delete for wipe: ' . $e->getMessage());
                    }

                    // final "Gmail Deleted" message
                    $pretty = "🗑️ Gmail Deleted\n\n"
                            . "📧 Gmail: {$gmail}\n"
                            . "✅ {$reply}\n"
                            . "⏳ Auto-delete in 24 hours.";

                    $kb = [
                        'inline_keyboard' => [
                            [
                                ['text' => '🧹 Go to Secure', 'url' => 'https://t.me/FakemailBOT']
                            ]
                        ]
                    ];

                    $resp = apiRequest('sendMessage', [
                        'chat_id'      => $buyer_chat,
                        'text'         => $pretty,
                        'reply_markup' => json_encode($kb)
                    ]);

                    $resp = is_string($resp) ? json_decode($resp, true) : $resp;
                    if (!empty($resp['ok']) && !empty($resp['result']['message_id'])) {
                        $mid = (int)$resp['result']['message_id'];
                        try {
                            $stmt = $pdo->prepare("
                                INSERT INTO gmail_notifications (user_id, chat_id, gmail, message_id, type, delete_at)
                                VALUES (?,?,?,?,?, DATE_ADD(NOW(), INTERVAL 24 HOUR))
                            ");
                            $stmt->execute([$buyer_user_id, $buyer_chat, $gmail, $mid, 'notice']);
                        } catch (PDOException $e) {
                            error_log('DB ERROR gmail_notifications insert gmail deleted: ' . $e->getMessage());
                        }
                    }
                } else {
                    // no buyer, just clean DB
                    try {
                        $stmt = $pdo->prepare("
                            UPDATE accounts
                            SET gmail_status     = 'none',
                                gmail            = NULL,
                                gmail_gen_id     = NULL,
                                gmail_delete_cmd = NULL,
                                gmail_error      = NULL
                            WHERE gmail = ?
                        ");
                        $stmt->execute([$gmail]);
                    } catch (PDOException $e) {
                        error_log('DB ERROR accounts gmail mark none on delete (no buyer): ' . $e->getMessage());
                    }
                }
                exit;
            }

            /* ---- PASSWORD CHANGED -> let dedicated handler below send UI ---- */
            if (strpos($lower, 'password changed') !== false) {
                // do not mark error here, just fall through to pwd-changed handler
            } else {
                /* ---- REAL ERROR: taken / invalid / etc ---- */
                try {
                    $stmt = $pdo->prepare("
                        UPDATE accounts
                        SET gmail_status     = 'error',
                            gmail_error      = ?,
                            gmail_gen_id     = NULL,
                            gmail_delete_cmd = NULL
                        WHERE gmail = ?
                        LIMIT 5
                    ");
                    $stmt->execute([$reply, $gmail]);
                } catch (PDOException $e) {
                    error_log('DB ERROR gmail error update: ' . $e->getMessage());
                }

                if (!empty($config['owner_chat_id'])) {
                    $info = "⚠️ Gmail error\n\n📧 <code>{$gmail}</code>\n❌ {$reply}";
                    apiRequest('sendMessage', [
                        'chat_id'    => $config['owner_chat_id'],
                        'text'       => $info,
                        'parse_mode' => 'HTML'
                    ]);
                }
                exit;
            }
        }

        // From here, we expect: Mail : something
        if (!preg_match('/Mail\s*:\s*([^\s]+)/i', $text, $gm_any)) exit;
        $gmail = trim($gm_any[1]);

        // STRICT: map gmail -> buyer through DB
        $buyer = findBuyerByGmail($pdo, $gmail);
        if (!$buyer || empty($buyer['chat_id'])) exit;

        $buyer_chat    = $buyer['chat_id'];
        $buyer_user_id = $buyer['user_id'];

        // -------------- RESET OTP (alphanumeric) --------------
        if (stripos($text, 'Reset OTP') !== false) {
            if (!preg_match('/Reset OTP\s*:\s*`?([A-Za-z0-9]{4,32})`?/i', $text, $om)) exit;
            $otp = trim($om[1]);
            $u   = null;
            if (preg_match('/User\s*:\s*(.+)/i', $text, $um)) $u = trim($um[1]);

            $lines = [];
            $lines[] = "🔐 Password Reset OTP";
            $lines[] = "";
            $lines[] = "📧 Gmail: {$gmail}";
            if ($u) {
                $lines[] = "👤 User: {$u}";
            }
            $lines[] = "🔑 OTP: {$otp}";
            $lines[] = "";
            $lines[] = "⏳ Auto-delete in 2 hours.";
            $pretty = implode("\n", $lines);

            $inline_keyboard = [];
            if (!empty($buyer['order_id'])) {
                $inline_keyboard = [
                    [
                        [
                            'text' => '🧺 Delete ' . $gmail,
                            'callback_data' => 'delgmail_' . $buyer['order_id']
                        ]
                    ]
                ];
            }

            $params = [
                'chat_id'    => $buyer_chat,
                'text'       => $pretty,
            ];
            if ($inline_keyboard) {
                $params['reply_markup'] = json_encode(['inline_keyboard' => $inline_keyboard]);
            }

            $resp = apiRequest('sendMessage', $params);
            $resp = is_string($resp) ? json_decode($resp, true) : $resp;

            if (!empty($resp['ok']) && !empty($resp['result']['message_id'])) {
                $mid = (int)$resp['result']['message_id'];
                try {
                    $stmt = $pdo->prepare("
                        INSERT INTO gmail_notifications (user_id, chat_id, gmail, message_id, type, delete_at)
                        VALUES (?,?,?,?,?, DATE_ADD(NOW(), INTERVAL 2 HOUR))
                    ");
                    $stmt->execute([$buyer_user_id, $buyer_chat, $gmail, $mid, 'otp']);
                } catch (PDOException $e) {
                    error_log('DB ERROR gmail_notifications insert reset otp: ' . $e->getMessage());
                }
            }
            exit;
        }

        // -------------- LOGIN OTP (6-digit) --------------
        if (preg_match('/OTP\s*:\s*`?([0-9]{4,8})`?/i', $text, $om)) {
            $otp          = trim($om[1]);
            $masked_gmail = mask_gmail($gmail);

            $lines = [];
            $lines[] = "🔓 Login OTP";
            $lines[] = "";
            $lines[] = "📧 Gmail: {$masked_gmail}";
            $lines[] = "🔑 OTP: {$otp}";
            $lines[] = "";
            $lines[] = "⏳ Auto-delete in 2 hours.";
            $pretty = implode("\n", $lines);

            $inline_keyboard = [];
            if (!empty($buyer['order_id'])) {
                $inline_keyboard = [
                    [
                        [
                            'text' => '🧺 Delete ' . $gmail,
                            'callback_data' => 'delgmail_' . $buyer['order_id']
                        ]
                    ]
                ];
            }

            $params = [
                'chat_id'    => $buyer_chat,
                'text'       => $pretty,
            ];
            if ($inline_keyboard) {
                $params['reply_markup'] = json_encode(['inline_keyboard' => $inline_keyboard]);
            }

            $resp = apiRequest('sendMessage', $params);
            $resp = is_string($resp) ? json_decode($resp, true) : $resp;

            if (!empty($resp['ok']) && !empty($resp['result']['message_id'])) {
                $mid = (int)$resp['result']['message_id'];
                try {
                    $stmt = $pdo->prepare("
                        INSERT INTO gmail_notifications (user_id, chat_id, gmail, message_id, type, delete_at)
                        VALUES (?,?,?,?,?, DATE_ADD(NOW(), INTERVAL 2 HOUR))
                    ");
                    $stmt->execute([$buyer_user_id, $buyer_chat, $gmail, $mid, 'otp']);
                } catch (PDOException $e) {
                    error_log('DB ERROR gmail_notifications insert login otp: ' . $e->getMessage());
                }
            }
            exit;
        }

        // -------------- PASSWORD CHANGED ALERT --------------
        if (preg_match('/Mail-Reply\s*:\s*(.+)$/mi', $text, $rm) && stripos(strtolower($rm[1]), 'password changed') !== false) {
            $u = null;
            if (preg_match('/User\s*:\s*(.+)/i', $text, $um)) {
                $u = trim($um[1]);
            }

            $replyText    = trim($rm[1]); // "Twitter password Changed."
            $masked_gmail = mask_gmail($gmail);

            $lines = [];
            $lines[] = "⚠️ Security Alert";
            $lines[] = "";
            $lines[] = "📧 Gmail: {$masked_gmail}";
            if ($u) {
                $lines[] = "👤 User: {$u}";
            }
            $lines[] = "💬 Mail Reply: {$replyText}";
            $lines[] = "";
            $lines[] = "❗ If this wasn’t you, change your password ASAP.";
            $lines[] = "⏳ Auto-delete in 24 hours.";
            $pretty = implode("\n", $lines);

            $inline_keyboard = [];
            if (!empty($buyer['order_id'])) {
                $inline_keyboard = [
                    [
                        [
                            'text' => '🧺 Delete ' . $gmail,
                            'callback_data' => 'delgmail_' . $buyer['order_id']
                        ]
                    ]
                ];
            }

            $params = [
                'chat_id'    => $buyer_chat,
                'text'       => $pretty,
            ];
            if ($inline_keyboard) {
                $params['reply_markup'] = json_encode(['inline_keyboard' => $inline_keyboard]);
            }

            $resp = apiRequest('sendMessage', $params);
            $resp = is_string($resp) ? json_decode($resp, true) : $resp;

            if (!empty($resp['ok']) && !empty($resp['result']['message_id'])) {
                $mid = (int)$resp['result']['message_id'];
                try {
                    $stmt = $pdo->prepare("
                        INSERT INTO gmail_notifications (user_id, chat_id, gmail, message_id, type, delete_at)
                        VALUES (?,?,?,?,?, DATE_ADD(NOW(), INTERVAL 24 HOUR))
                    ");
                    $stmt->execute([$buyer_user_id, $buyer_chat, $gmail, $mid, 'notice']);
                } catch (PDOException $e) {
                    error_log('DB ERROR gmail_notifications insert notice (pwd changed): ' . $e->getMessage());
                }
            }
            exit;
        }

        // nothing matched, just ignore silently
        exit;
    }

/* -------- OWNER DEBUG: /debuggmail email@hi2.in -------- */
    if (isset($msg['text']) && strpos($msg['text'], '/debuggmail') === 0) {

        // Only owner can debug
        if (!isOwner($from['id'])) {
            apiRequest('sendMessage', [
                'chat_id' => $chat_id,
                'text'    => "⛔ Owner only command."
            ]);
            exit;
        }

        $parts = explode(' ', trim($msg['text']), 2);
        if (count($parts) < 2 || empty(trim($parts[1]))) {
            apiRequest('sendMessage', [
                'chat_id' => $chat_id,
                'text'    => "Usage:\n/debuggmail email@hi2.in"
            ]);
            exit;
        }

        $gmail = trim(strtolower($parts[1]));

        // 1) Look in accounts + last paid order mapping
        try {
            $stmt = $pdo->prepare("
                SELECT 
                    a.gmail,
                    a.gmail_status,
                    a.gmail_gen_id,
                    a.gmail_delete_cmd,
                    a.gmail_error,
                    o.id          AS order_id,
                    o.status      AS order_status,
                    o.created_at  AS order_created_at,
                    u.id          AS user_id,
                    u.telegram_id AS chat_id,
                    u.username    AS username
                FROM accounts a
                LEFT JOIN orders o ON o.account_id = a.id
                LEFT JOIN users  u ON o.user_id   = u.id
                WHERE a.gmail = ?
                ORDER BY 
                    (o.status = 'paid') DESC,
                    o.created_at DESC
                LIMIT 5
            ");
            $stmt->execute([$gmail]);
            $accRows = $stmt->fetchAll();
        } catch (PDOException $e) {
            error_log('DB ERROR debuggmail accounts: ' . $e->getMessage());
            apiRequest('sendMessage', [
                'chat_id' => $chat_id,
                'text'    => "⚠️ DB error while debugging."
            ]);
            exit;
        }

        // 2) Look at recent gmail_notifications
        try {
            $stmt2 = $pdo->prepare("
                SELECT chat_id, message_id, type, delete_at, created_at 
                FROM gmail_notifications
                WHERE gmail = ?
                ORDER BY id DESC
                LIMIT 10
            ");
            $stmt2->execute([$gmail]);
            $notifs = $stmt2->fetchAll();
        } catch (PDOException $e) {
            $notifs = [];
            error_log('DB ERROR debuggmail notifications: ' . $e->getMessage());
        }

        if (!$accRows && !$notifs) {
            apiRequest('sendMessage', [
                'chat_id' => $chat_id,
                'text'    => "❌ No data found for gmail:\n<code>{$gmail}</code>",
                'parse_mode' => 'HTML'
            ]);
            exit;
        }

        $lines = [];
        $lines[] = "🛠 <b>Debug Gmail</b>";
        $lines[] = "";
        $lines[] = "📧 <code>{$gmail}</code>";
        $lines[] = "";

        if ($accRows) {
            $first = $accRows[0];
            $lines[] = "📂 <b>Account Binding</b>";
            $lines[] = "• Status: <code>" . ($first['gmail_status'] ?? 'null') . "</code>";
            $lines[] = "• Gen ID: <code>" . ($first['gmail_gen_id'] ?? 'null') . "</code>";
            $lines[] = "• Delete Cmd: <code>" . ($first['gmail_delete_cmd'] ?? 'null') . "</code>";
            if (!empty($first['gmail_error'])) {
                $lines[] = "• Error: <code>" . htmlspecialchars($first['gmail_error']) . "</code>";
            }

            $lines[] = "";
            $lines[] = "🧾 <b>Orders (top 3)</b>";
            $i = 0;
            foreach ($accRows as $row) {
                if ($i >= 3) break;
                $i++;
                $uname = $row['username'] ? '@'.$row['username'] : '—';
                $lines[] = "#{$i}) Order: <code>" . ($row['order_id'] ?? 'none') . "</code>";
                $lines[] = "   • Status: <code>" . ($row['order_status'] ?? 'null') . "</code>";
                $lines[] = "   • Buyer TG: <code>" . ($row['chat_id'] ?? 'null') . "</code> ({$uname})";
                $lines[] = "   • Created: <code>" . ($row['order_created_at'] ?? 'null') . "</code>";
            }
        } else {
            $lines[] = "📂 No account row found for this gmail in accounts.";
        }

        if ($notifs) {
            $lines[] = "";
            $lines[] = "🔔 <b>Last Notifications</b>";
            foreach ($notifs as $n) {
                $lines[] = "• chat_id=<code>{$n['chat_id']}</code>, msg_id=<code>{$n['message_id']}</code>";
                $lines[] = "  type=<code>{$n['type']}</code>, delete_at=<code>{$n['delete_at']}</code>";
            }
        } else {
            $lines[] = "";
            $lines[] = "🔔 No gmail_notifications rows for this gmail.";
        }

        $debugText = implode("\n", $lines);

        apiRequest('sendMessage', [
            'chat_id'    => $chat_id,
            'text'       => $debugText,
            'parse_mode' => 'HTML'
        ]);
        exit;
    }

    // /start
    if (isset($msg['text']) && strpos($msg['text'], '/start') === 0) {

        if ($user && isset($user['id'])) {
            cleanupUserPendingPayments($pdo, $user);
            cleanupBrowseSession($pdo, $user['id'], $chat_id, null);
        }

        try {
            $cats = $pdo->query("SELECT id, title, slug FROM categories WHERE IFNULL(is_hidden,0) = 0 ORDER BY sort_order")->fetchAll();
        } catch (PDOException $e) {
            error_log("DB ERROR categories: " . $e->getMessage());
            $cats = [];
        }

        $inline = [];
        foreach ($cats as $c) {
            $inline[] = [['text' => "📁 " . $c['title'], 'callback_data' => "cat_{$c['id']}_page_1"]];
        }
        $reply_markup_inline = ['inline_keyboard' => $inline];

        $reply_markup2 = [
            'keyboard' => [
                [['text' => '📦 Show Purchased ids']]
            ],
            'resize_keyboard' => true,
            'one_time_keyboard' => false
        ];

        if (empty($inline)) {
            if (isOwner($chat_id)) {
                sendMessage($chat_id, "⚠️ No categories configured yet. Add categories via admin: /admin/manage_categories.php", $reply_markup2);
            } else {
                sendMessage($chat_id, "⏳ Shop is empty right now. Check back soon!", $reply_markup2);
            }
            exit;
        }

        sendMessage($chat_id, "✨ Welcome! Choose a category to browse available accounts:", $reply_markup2);
        sendMessage($chat_id, "📚 Categories:", $reply_markup_inline);
        exit;
    }

    if (!empty($msg['text']) && ($msg['text'] === '📦 Show Purchased ids' || $msg['text'] === 'Show Purchased ids')) {
        // make sure user exists in DB
        $userRow = createUserIfNotExists($pdo, $msg['from']);
        if (!$userRow) {
            sendMessage($chat_id, "⚠️ Could not load your profile. Try /start.");
            exit;
        }
    
        // 🧹 BEFORE sending purchased IDs:
        // 1) cancel + delete any pending payment QR / error messages
        // 2) delete old browse session cards (/cat_... messages)
        cleanupUserPendingPayments($pdo, $userRow);
        cleanupBrowseSession($pdo, $userRow['id'], $chat_id, null);
    
        // now send the list of purchased IDs
        sendUserPurchases($pdo, $userRow, $chat_id);
        exit;
    }

    exit;
}

/* ---------------- callback_query handling ---------------- */

if (isset($input['callback_query'])) {
    $cb      = $input['callback_query'];
    $data    = $cb['data'] ?? '';
    $chat_id = $cb['message']['chat']['id'];
    $msg_id  = $cb['message']['message_id'];
    $from    = $cb['from'];
    $user    = createUserIfNotExists($pdo, $from);

    // category browse: cat_{id}_page_{n}
    if (preg_match('#^cat_(\d+)_page_(\d+)$#', $data, $m)) {
        $cat_id = (int)$m[1];
        $page   = (int)$m[2];
        $per    = 5;
        $offset = ($page - 1) * $per;

        if ($user && isset($user['id'])) {
            cleanupUserPendingPayments($pdo, $user);
            cleanupBrowseSession($pdo, $user['id'], $chat_id, null);
        }

        $sql = "SELECT * FROM accounts WHERE category_id = :cat AND is_sold=0 ORDER BY created_at DESC LIMIT {$per} OFFSET {$offset}";

        try {
            $stmt = $pdo->prepare($sql);
            $stmt->execute([':cat' => $cat_id]);
            $rows = $stmt->fetchAll();
        } catch (PDOException $e) {
            error_log("DB ERROR fetch accounts: " . $e->getMessage());
            apiRequest('answerCallbackQuery', ['callback_query_id'=> $cb['id'], 'text' => '⚠️ Internal error.']);
            exit;
        }

        if (!$rows) {
            apiRequest('answerCallbackQuery', [
                'callback_query_id' => $cb['id'],
                'text' => '📭 No more accounts.',
                'show_alert' => true
            ]);
            exit;
        }

        $owner_username = getOwnerUsername($pdo, $config['owner_chat_id']);
        $owner_link = $owner_username ? "https://t.me/".urlencode($owner_username) : null;

        $sent_msg_ids = [];

        foreach ($rows as $acc) {
            $img_url = $config['site_url'] . '/uploads/' . basename($acc['image_path']);
            $title   = htmlspecialchars($acc['title'] ?: 'Account');
            $level   = $acc['level'] ? htmlspecialchars($acc['level']) : null;
            $price   = is_null($acc['price']) ? null : $acc['price'];
            $captionText = $acc['caption'] ?: '';

            $lines = [];
            $lines[] = "<blockquote><b>🧾 {$title}</b></blockquote>";
            if ($level) {
                $lines[] = "<blockquote><b>📶 Level: <code>{$level}</code></b></blockquote>";
            }
            if ($captionText) {
                $lines[] = "<blockquote expandable><b>" . htmlspecialchars($captionText) . "</b></blockquote>";
            }
            if ($price !== null) {
                $lines[] = "<blockquote><b>💰 Price: <code>" . format_inr_label($price) . "</code></b></blockquote>";
            }
            $lines[] = "\n <b>Tap BUY to reserve this account. Payments are final — pay & verify.</b>";
            $caption = implode("\n", array_filter($lines));

            $buy_label = $price !== null ? "💳 BUY [" . format_inr_label($price) . "]" : "💳 BUY";
            $kb = ['inline_keyboard' => [[['text' => $buy_label, 'callback_data' => "buy_{$acc['id']}"]]]];

            $resp = apiRequest('sendPhoto', [
                'chat_id' => $chat_id,
                'photo' => $img_url,
                'caption' => $caption,
                'parse_mode' => 'HTML',
                'reply_markup' => json_encode($kb)
            ]);

            $respData = is_string($resp) ? json_decode($resp, true) : $resp;
            if (!empty($respData['ok']) && !empty($respData['result']['message_id'])) {
                $sent_msg_ids[] = (int)$respData['result']['message_id'];
            }
        }

        $next_page = $page + 1;
        $more_row = [['text' => '🔽 More','callback_data' => "cat_{$cat_id}_page_{$next_page}"]];
        if ($owner_link) $more_row[] = ['text' => '🧾 Directly Purchase', 'url' => $owner_link];
        $kb2 = ['inline_keyboard' => [$more_row]];

        $moreResp = apiRequest('sendMessage', [
            'chat_id' => $chat_id,
            'text' => "🔽 Tap More for more in this category.",
            'reply_markup' => json_encode($kb2)
        ]);

        $moreData = is_string($moreResp) ? json_decode($moreResp, true) : $moreResp;
        if (!empty($moreData['ok']) && !empty($moreData['result']['message_id'])) {
            $sent_msg_ids[] = (int)$moreData['result']['message_id'];
        }

        if ($user && isset($user['id'])) {
            saveBrowseSession($pdo, $user['id'], $chat_id, $cat_id, $page, $sent_msg_ids);
        }

        apiRequest('answerCallbackQuery', ['callback_query_id'=> $cb['id']]);
        exit;
    }

    // buy flow: buy_{account_id}
    if (preg_match('#^buy_(\d+)$#', $data, $m)) {
        $acc_id = (int)$m[1];

        if ($user && isset($user['id'])) {
            // cancel other pending payments for this user
            cleanupUserPendingPayments($pdo, $user);
            cleanupBrowseSession($pdo, $user['id'], $chat_id, $msg_id);
        }

        try {
            $stmt = $pdo->prepare("SELECT * FROM accounts WHERE id = ?");
            $stmt->execute([$acc_id]);
            $acc = $stmt->fetch();
        } catch (PDOException $e) {
            error_log("DB ERROR fetch account: " . $e->getMessage());
            apiRequest('answerCallbackQuery', ['callback_query_id'=> $cb['id'], 'text' => '⚠️ Internal error.']);
            exit;
        }

        if (!$acc) {
            apiRequest('answerCallbackQuery', ['callback_query_id'=> $cb['id'], 'text' => '❌ Account not found.']);
            exit;
        }
        if (!empty($acc['is_sold'])) {
            apiRequest('answerCallbackQuery', ['callback_query_id'=> $cb['id'], 'text' => '❌ Already sold.']);
            exit;
        }

        $buyer_chat = $cb['from']['id'];
        $rawAmount = isset($acc['price']) && $acc['price'] !== null ? (float)$acc['price'] : 1.00;
        $amount = number_format($rawAmount, 2, '.', ''); // normalized
        $upi_id  = $config['paytm_upi_id'] ?? ($config['PAYTM_UPI_ID'] ?? null);

        // create order first so we know id
        try {
            $stmt = $pdo->prepare("INSERT INTO orders (user_id, account_id, status, amount) VALUES (?,?, 'pending', ?)");
            $stmt->execute([$user['id'], $acc_id, $amount]);
            $order_id = $pdo->lastInsertId();
        } catch (PDOException $e) {
            error_log("DB ERROR create order: " . $e->getMessage());
            apiRequest('answerCallbackQuery', ['callback_query_id'=> $cb['id'], 'text' => '⚠️ Could not create order.']);
            exit;
        }

        $txn_ref = "ORD" . $order_id;

        // save txn_ref back to DB
        try {
            $up = $pdo->prepare("UPDATE orders SET txn_ref = ? WHERE id = ?");
            $up->execute([$txn_ref, $order_id]);
        } catch (PDOException $e) {
            error_log("DB ERROR save txn_ref: " . $e->getMessage());
        }

        $upiString = "upi://pay?pa=" . rawurlencode($upi_id)
                   . "&pn=" . rawurlencode($config['site_name'] ?? 'Merchant')
                   . "&am={$amount}&tr={$txn_ref}&tn=" . rawurlencode("Purchase Order #{$order_id}");

        $kb = ['inline_keyboard'=>[
            [['text'=>'✅ Verify Payment','callback_data'=>"verifypay_{$order_id}"]],
            [['text'=>'❌ Cancel','callback_data'=>"cancel_{$order_id}"]]
        ]];

        // send QR or text
        if ($has_qrcode_lib) {
            $tmpdir = __DIR__ . '/temp';
            if (!is_dir($tmpdir)) @mkdir($tmpdir, 0755, true);
            $qrPath = $tmpdir . '/' . $txn_ref . '.png';
            QRcode::png($upiString, $qrPath, QR_ECLEVEL_L, 8);

            if (!file_exists($qrPath)) {
                error_log("QR generation failed for $qrPath");
                apiRequest('answerCallbackQuery', [
                    'callback_query_id' => $cb['id'],
                    'text' => '⚠️ Could not create QR. Try again later.',
                    'show_alert' => true
                ]);
            } else {
                $token = $config['bot_token'] ?? null;
                if (!$token) {
                    error_log("Bot token missing in config");
                    apiRequest('answerCallbackQuery', [
                        'callback_query_id' => $cb['id'],
                        'text' => '⚠️ Bot token not configured.',
                        'show_alert' => true
                    ]);
                } else {
                    $post = [
                        'chat_id' => $buyer_chat,
                        'caption' => "<b>Pay ₹{$amount} via UPI QR\nThen tap Verify Payment</b>",
                        'parse_mode' => 'HTML',
                        'reply_markup' => json_encode($kb),
                        'photo' => new CURLFile($qrPath)
                    ];
                    $ch = curl_init("https://api.telegram.org/bot{$token}/sendPhoto");
                    curl_setopt($ch, CURLOPT_POST, true);
                    curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
                    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
                    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
                    curl_setopt($ch, CURLOPT_TIMEOUT, 30);

                    $resp = curl_exec($ch);
                    $curlErr = curl_error($ch);
                    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
                    curl_close($ch);

                    if ($curlErr || $httpCode < 200 || $httpCode >= 300) {
                        error_log("sendPhoto err: $curlErr code:$httpCode resp:" . substr($resp,0,500));
                        apiRequest('answerCallbackQuery', [
                            'callback_query_id' => $cb['id'],
                            'text' => '⚠️ Could not send QR. Try again.',
                            'show_alert' => true
                        ]);
                    } else {
                        @unlink($qrPath);
                        $respArr = json_decode($resp, true);
                        if (!empty($respArr['ok']) && !empty($respArr['result']['message_id'])) {
                            $qrMid = (int)$respArr['result']['message_id'];
                            try {
                                $up = $pdo->prepare("UPDATE orders SET qr_message_id = ? WHERE id = ?");
                                $up->execute([$qrMid, $order_id]);
                            } catch (PDOException $e) {
                                error_log("DB ERROR save qr_message_id: " . $e->getMessage());
                            }
                        }
                        apiRequest('answerCallbackQuery', [
                            'callback_query_id' => $cb['id'],
                            'text' => '🧾 QR sent — tap Verify Payment after paying.'
                        ]);
                    }
                }
            }
        } else {
            $text = "<b>Open your UPI app and pay:</b>\n\nAmount: ₹{$amount}\nUPI ID: <code>{$upi_id}</code>\nNote/TxnRef: <code>{$txn_ref}</code>\n\n<code>{$upiString}</code>\n\nAfter payment, tap Verify Payment.";
            $resp = apiRequest('sendMessage', [
                'chat_id' => $buyer_chat,
                'text' => $text,
                'parse_mode' => 'HTML',
                'reply_markup' => json_encode($kb)
            ]);

            $dataResp = is_string($resp) ? json_decode($resp, true) : $resp;
            if (!empty($dataResp['ok']) && !empty($dataResp['result']['message_id'])) {
                $qrMid = (int)$dataResp['result']['message_id'];
                try {
                    $up = $pdo->prepare("UPDATE orders SET qr_message_id = ? WHERE id = ?");
                    $up->execute([$qrMid, $order_id]);
                } catch (PDOException $e) {
                    error_log("DB ERROR save qr_message_id (no QR lib): " . $e->getMessage());
                }
            }
        }

        exit;
    }

    // verify payment
    if (preg_match('#^verifypay_(\d+)$#', $data, $m)) {
        $order_id = (int)$m[1];

        try {
            $stmt = $pdo->prepare("SELECT 
                                       o.*, 
                                       u.id AS user_db_id,
                                       u.telegram_id AS buyer_tg, 
                                       u.username AS buyer_username, 
                                       u.first_name, 
                                       u.last_name, 
                                       a.title AS account_title, 
                                       a.image_path, 
                                       a.username_value, 
                                       a.password_value, 
                                       a.id AS accid, 
                                       a.is_sold, 
                                       a.level, 
                                       a.gmail,
                                       a.gmail_delete_cmd,
                                       a.price
                                   FROM orders o
                                   JOIN users u ON o.user_id = u.id
                                   JOIN accounts a ON o.account_id = a.id
                                   WHERE o.id = ?");
            $stmt->execute([$order_id]);
            $row = $stmt->fetch();
        } catch (PDOException $e) {
            error_log("DB ERROR verifypay fetch: " . $e->getMessage());
            apiRequest('answerCallbackQuery', ['callback_query_id'=> $cb['id'], 'text' => '⚠️ Internal error.']);
            exit;
        }

        if (!$row) {
            apiRequest('answerCallbackQuery', ['callback_query_id'=> $cb['id'], 'text' => '❌ Order not found.', 'show_alert' => true]);
            exit;
        }

        $caller_tg = $from['id'];
        if ((int)$caller_tg !== (int)$row['buyer_tg']) {
            apiRequest('answerCallbackQuery', ['callback_query_id'=> $cb['id'], 'text' => '⛔ You are not the buyer for this order.', 'show_alert' => true]);
            exit;
        }

        // only allow verify on pending orders
        if ($row['status'] !== 'pending') {
            apiRequest('answerCallbackQuery', [
                'callback_query_id'=> $cb['id'],
                'text' => 'ℹ️ This order is not pending anymore.',
                'show_alert' => true
            ]);
            exit;
        }

        // simple expiry (15 minutes)
        if (!empty($row['created_at'])) {
            $created_ts = strtotime($row['created_at']);
            if ($created_ts && (time() - $created_ts) > 15 * 60) {
                try {
                    $pdo->prepare("UPDATE orders SET status='cancelled', updated_at = NOW() WHERE id = ?")->execute([$order_id]);
                } catch (PDOException $e) {
                    error_log("DB ERROR expire order: " . $e->getMessage());
                }
                apiRequest('answerCallbackQuery', [
                    'callback_query_id'=> $cb['id'],
                    'text' => '⌛ Order expired. Please create a new order.',
                    'show_alert' => true
                ]);
                exit;
            }
        }

        if ((int)$row['is_sold'] === 1) {
            apiRequest('answerCallbackQuery', ['callback_query_id'=> $cb['id'], 'text' => 'ℹ️ This account was already sold.', 'show_alert' => true]);
            exit;
        }

        // paytm config
        $PAYTM_MID = $config['PAYTM_MERCHANT_ID'] ?? ($config['paytm_merchant_id'] ?? null);
        $PAYTM_KEY = $config['PAYTM_MERCHANT_KEY'] ?? ($config['paytm_merchant_key'] ?? null);

        if (!$PAYTM_MID || !$PAYTM_KEY) {
            error_log("Paytm credentials missing in config");
            apiRequest('answerCallbackQuery', ['callback_query_id'=> $cb['id'], 'text' => '⚠️ Payment gateway not configured.', 'show_alert' => true]);
            exit;
        }

        // use stored txn_ref + amount
        $txn_ref = $row['txn_ref'] ?: ("ORD" . $order_id);
        $expectedAmount = $row['amount'] !== null ? (float)$row['amount'] : (float)($row['price'] ?? 1.00);

        $payload = ["MID"=>$PAYTM_MID,"ORDERID"=>$txn_ref];
        $json     = json_encode($payload);
        $checksum = hash_hmac("sha256", $json, $PAYTM_KEY);

        $paytm_env = $config['paytm_env'] ?? 'production';
        if ($paytm_env === 'staging' || $paytm_env === 'test') {
            $url = "https://securegw-stage.paytm.in/merchant-status/getTxnStatus?JsonData=" . urlencode($json) . "&CHECKSUMHASH=" . $checksum;
        } else {
            $url = "https://securegw.paytm.in/merchant-status/getTxnStatus?JsonData=" . urlencode($json) . "&CHECKSUMHASH=" . $checksum;
        }

        $resp_raw = @file_get_contents($url);
        if ($resp_raw === false) {
            apiRequest('answerCallbackQuery', ['callback_query_id'=> $cb['id'], 'text' => '⚠️ Could not verify payment at this time. Try again.', 'show_alert' => true]);
            exit;
        }
        $resp = json_decode($resp_raw, true);

        // strong checks on Paytm response
        if (!is_array($resp) || !isset($resp["STATUS"])) {
            error_log("Paytm invalid response for order {$order_id}: " . substr($resp_raw,0,500));
            apiRequest('answerCallbackQuery', [
                'callback_query_id'=> $cb['id'],
                'text' => '⚠️ Payment verification error. Try again later.',
                'show_alert' => true
            ]);
            exit;
        }

        $status      = $resp["STATUS"]   ?? null;
        $respCode    = $resp["RESPCODE"] ?? null;
        $paytmAmount = isset($resp["TXNAMOUNT"]) ? (float)$resp["TXNAMOUNT"] : null;

        if ($status === "TXN_SUCCESS" && $respCode === "01" && $paytmAmount !== null && abs($paytmAmount - $expectedAmount) < 0.001) {
            // mark paid + sold
            try {
                $pdo->prepare("UPDATE orders SET status='paid', verified_at = NOW(), updated_at = NOW() WHERE id = ?")->execute([$order_id]);
                $pdo->prepare("UPDATE accounts SET is_sold=1 WHERE id = ?")->execute([$row['accid']]);
            } catch (PDOException $e) {
                error_log("DB ERROR verifypay update: " . $e->getMessage());
                apiRequest('answerCallbackQuery', ['callback_query_id'=> $cb['id'], 'text' => '⚠️ Internal error.']);
                exit;
            }
            
            // save gmail snapshot on order (so Show Purchased ids can still display it
            // even after gmail is deleted / set NULL on accounts)
            $gmail_for_order = $row['gmail'] ?? null;
            if ($gmail_for_order) {
                try {
                    $stmtSnap = $pdo->prepare("UPDATE orders SET gmail_snapshot = ? WHERE id = ?");
                    $stmtSnap->execute([$gmail_for_order, $order_id]);
                } catch (PDOException $e) {
                    error_log("DB ERROR save gmail_snapshot on order {$order_id}: " . $e->getMessage());
                }
            }

            // Clean QR + old error message
            if (!empty($row['qr_message_id'])) {
                apiRequest('deleteMessage', [
                    'chat_id'    => $row['buyer_tg'],
                    'message_id' => (int)$row['qr_message_id']
                ]);
            }
            if (!empty($row['last_error_message_id'])) {
                apiRequest('deleteMessage', [
                    'chat_id'    => $row['buyer_tg'],
                    'message_id' => (int)$row['last_error_message_id']
                ]);
            }

            // drop the selected card
            cleanupBrowseSession($pdo, (int)$row['user_id'], (int)$row['buyer_tg'], null);

            // send creds + gmail activation + buttons
            $img_url = $config['site_url'] . '/uploads/' . basename($row['image_path']);

            $acc_title = htmlspecialchars($row['account_title'] ?: 'Account');
            $cred_user = htmlspecialchars($row['username_value'] ?? '—');
            $cred_pass = htmlspecialchars($row['password_value'] ?? '—');
            $level     = $row['level'] ? htmlspecialchars($row['level']) : null;
            $gmail     = $row['gmail'] ? htmlspecialchars($row['gmail']) : null;

            $captionLines = [];
            $captionLines[] = "<blockquote><b>🎉 {$acc_title}</b></blockquote>";
            if ($level) {
                $captionLines[] = "<blockquote><b>𝗟𝗘𝗩𝗘𝗟: <code>{$level}</code></b></blockquote>";
            }
            $captionLines[] = "<blockquote><b>𝕏 𝗧𝗪𝗜𝗧𝗧𝗘𝗥</b></blockquote>";
            $captionLines[] = "<blockquote><b>𝗨𝗦𝗘𝗥𝗡𝗔𝗠𝗘: <code>{$cred_user}</code></b></blockquote>";
            $captionLines[] = "<blockquote><b>𝗣𝗔𝗦𝗦𝗪𝗢𝗥𝗗: <code>{$cred_pass}</code></b></blockquote>";
            if ($gmail) {
                $captionLines[] = "<blockquote><b>𝗚𝗠𝗔𝗜𝗟: <code>{$gmail}</code></b></blockquote>";
            }
            $captionLines[] = "\n<b>✅ Payment verified.</b>";
            if ($gmail) {
                $captionLines[] = "<blockquote><b>📨 Gmail Activation:</b> All OTPs & security mails for <code>{$gmail}</code> will be forwarded here only.</blockquote>";
                $captionLines[] = "<blockquote><i>⚠️ Don't share these credentials with anyone.</i></blockquote>";
            }

            $cred_caption = implode("\n", $captionLines);

            $inline_keyboard = [];
            $inline_keyboard[] = [
                ['text' => "📩 Contact Owner", 'url' => 'https://t.me/Ceo_DarkFury']
            ];
            if ($gmail) {
                $inline_keyboard[] = [
                    ['text' => "🗑️ Delete {$gmail}", 'callback_data' => "delgmail_{$row['id']}"]
                ];
            }
            $reply_markup = json_encode(['inline_keyboard' => $inline_keyboard]);

            $respSend = apiRequest('sendPhoto', [
                'chat_id' => $row['buyer_tg'],
                'photo'   => $img_url,
                'caption' => $cred_caption,
                'parse_mode' => 'HTML',
                'reply_markup' => $reply_markup
            ]);

            // owner notify
            $buyer_name = trim(($row['first_name'] ?? '') . ' ' . ($row['last_name'] ?? ''));
            $buyer_name = $buyer_name ?: ($row['buyer_username'] ?? '—');

            $owner_text_lines = [];
            $owner_text_lines[] = "<blockquote><b>🔔 Sale Completed</b></blockquote>";
            $owner_text_lines[] = "<blockquote><b>🧾 Order:</b> <code>#{$order_id}</code></blockquote>";
            $owner_text_lines[] = "<blockquote><b>👤 Buyer:</b> {$buyer_name}</blockquote>";
            $owner_text_lines[] = "<blockquote><b>🆔 Buyer TG:</b> <code>{$row['buyer_tg']}</code></blockquote>";
            $owner_text_lines[] = "<blockquote><b>📦 Account:</b> <b>{$acc_title}</b></blockquote>";
            if ($level) {
                $owner_text_lines[] = "<blockquote><b>📶 Level:</b> <code>{$level}</code></blockquote>";
            }
            $owner_text_lines[] = "<blockquote><b>🪪 Account ID:</b> <code>{$row['accid']}</code></blockquote>";
            $owner_text_lines[] = "<b>✅ Credentials sent to buyer.</b>";
            $owner_text = implode("\n", $owner_text_lines);

            sendPhoto($config['owner_chat_id'], $img_url, $owner_text, null);

            apiRequest('answerCallbackQuery', [
                'callback_query_id' => $cb['id'],
                'text' => "✅ Payment confirmed.\nCredentials sent successfully.",
                'show_alert' => true
            ]);
            exit;
        } else {
            // FAILED / NOT RECEIVED
            if (!empty($row['last_error_message_id'])) {
                apiRequest('deleteMessage', [
                    'chat_id'    => $row['buyer_tg'],
                    'message_id' => (int)$row['last_error_message_id']
                ]);
            }

            error_log("Paytm verification failed for order {$order_id}: " . substr($resp_raw,0,500));

            apiRequest('answerCallbackQuery', [
                'callback_query_id'=> $cb['id'],
                'text' => "❌ Payment not received for this order.\nIf amount is debited, wait 1–2 mins and tap Verify again.",
                'show_alert' => true
            ]);

            $text_msg = "❌ Payment not received for this order.\nIf money is debited from your bank, wait a bit and press Verify again.";
            $errResp = apiRequest('sendMessage', [
                'chat_id' => $caller_tg,
                'text'    => $text_msg
            ]);

            $errData = is_string($errResp) ? json_decode($errResp, true) : $errResp;
            if (!empty($errData['ok']) && !empty($errData['result']['message_id'])) {
                $errMid = (int)$errData['result']['message_id'];
                try {
                    $up = $pdo->prepare("UPDATE orders SET last_error_message_id = ? WHERE id = ?");
                    $up->execute([$errMid, $order_id]);
                } catch (PDOException $e) {
                    error_log("DB ERROR save last_error_message_id: " . $e->getMessage());
                }
            }

            exit;
        }
    }

// DELETE GMAIL BUTTON: delgmail_{order_id}
    if (preg_match('#^delgmail_(\d+)$#', $data, $m)) {
        $order_id = (int)$m[1];

        try {
            $stmt = $pdo->prepare("
                SELECT 
                    o.id          AS order_id,
                    o.user_id     AS user_id,
                    u.telegram_id AS buyer_tg,
                    a.gmail,
                    a.id          AS account_id,
                    a.gmail_delete_cmd
                FROM orders o
                JOIN users u   ON o.user_id = u.id
                JOIN accounts a ON o.account_id = a.id
                WHERE o.id = ?
                  AND o.status = 'paid'
                LIMIT 1
            ");
            $stmt->execute([$order_id]);
            $row = $stmt->fetch();
        } catch (PDOException $e) {
            error_log('DB ERROR delgmail fetch: ' . $e->getMessage());
            apiRequest('answerCallbackQuery', [
                'callback_query_id'=> $cb['id'],
                'text' => '⚠️ Internal error.'
            ]);
            exit;
        }

        if (!$row || empty($row['gmail'])) {
            apiRequest('answerCallbackQuery', [
                'callback_query_id'=> $cb['id'],
                'text' => '❌ Gmail not found for this order.',
                'show_alert' => true
            ]);
            exit;
        }

        if ((int)$from['id'] !== (int)$row['buyer_tg']) {
            apiRequest('answerCallbackQuery', [
                'callback_query_id'=> $cb['id'],
                'text' => '⛔ Not your order.',
                'show_alert' => true
            ]);
            exit;
        }

        $gmail     = $row['gmail'];
        $deleteCmd = $row['gmail_delete_cmd'];

        if (!$deleteCmd) {
            apiRequest('answerCallbackQuery', [
                'callback_query_id'=> $cb['id'],
                'text' => '❗ This Gmail is not active anymore.',
                'show_alert' => true
            ]);
            exit;
        }

        // send delete command to userbot
        if (!empty($config['mail_userbot_chat_id'])) {
            apiRequest('sendMessage', [
                'chat_id' => $config['mail_userbot_chat_id'],
                'text'    => $deleteCmd
            ]);
        }

        // send "Delete Requested" message to user
        $txt = "🗑️ <b>Delete Requested</b>\n\n"
             . "📧 Gmail: <code>{$gmail}</code>\n"
             . "⏳ Waiting for mail server to confirm deletion.";
        $resp = apiRequest('sendMessage', [
            'chat_id'    => $row['buyer_tg'],
            'text'       => $txt,
            'parse_mode' => 'HTML'
        ]);

        // store this message so it gets deleted when delete success arrives
        $respArr = is_string($resp) ? json_decode($resp, true) : $resp;
        if (!empty($respArr['ok']) && !empty($respArr['result']['message_id'])) {
            $mid = (int)$respArr['result']['message_id'];
            try {
                $stmtIns = $pdo->prepare("
                    INSERT INTO gmail_notifications (user_id, chat_id, gmail, message_id, type, delete_at)
                    VALUES (?,?,?,?,?, DATE_ADD(NOW(), INTERVAL 24 HOUR))
                ");
                $stmtIns->execute([$row['user_id'], $row['buyer_tg'], $gmail, $mid, 'notice']);
            } catch (PDOException $e) {
                error_log('DB ERROR gmail_notifications insert delete requested: ' . $e->getMessage());
            }
        }

        apiRequest('answerCallbackQuery', [
            'callback_query_id'=> $cb['id'],
            'text' => '🗑️ Delete request sent.',
            'show_alert' => false
        ]);
        exit;
    }

    // CANCEL PAYMENT: cancel_{order_id}
    if (preg_match('#^cancel_(\d+)$#', $data, $m)) {
        $order_id = (int)$m[1];

        try {
            $stmt = $pdo->prepare("SELECT 
                                       o.*, 
                                       u.telegram_id AS buyer_tg
                                   FROM orders o
                                   JOIN users u ON o.user_id = u.id
                                   WHERE o.id = ?");
            $stmt->execute([$order_id]);
            $row = $stmt->fetch();
        } catch (PDOException $e) {
            error_log("DB ERROR cancel fetch: " . $e->getMessage());
            apiRequest('answerCallbackQuery', ['callback_query_id'=> $cb['id'], 'text' => '⚠️ Internal error.']);
            exit;
        }

        if (!$row) {
            apiRequest('answerCallbackQuery', ['callback_query_id'=> $cb['id'], 'text' => '❌ Order not found.']);
            exit;
        }

        $caller_tg = $from['id'];
        if ((int)$caller_tg !== (int)$row['buyer_tg']) {
            apiRequest('answerCallbackQuery', ['callback_query_id'=> $cb['id'], 'text' => '⛔ You are not the buyer for this order.', 'show_alert' => true]);
            exit;
        }

        if ($row['status'] !== 'pending') {
            apiRequest('answerCallbackQuery', ['callback_query_id'=> $cb['id'], 'text' => 'ℹ️ This order is not active anymore.']);
            exit;
        }

        if (!empty($row['qr_message_id'])) {
            apiRequest('deleteMessage', [
                'chat_id'    => $row['buyer_tg'],
                'message_id' => (int)$row['qr_message_id']
            ]);
        }
        if (!empty($row['last_error_message_id'])) {
            apiRequest('deleteMessage', [
                'chat_id'    => $row['buyer_tg'],
                'message_id' => (int)$row['last_error_message_id']
            ]);
        }

        try {
            $pdo->prepare("UPDATE orders SET status='cancelled', qr_message_id=NULL, last_error_message_id=NULL, updated_at = NOW() WHERE id = ?")->execute([$order_id]);
        } catch (PDOException $e) {
            error_log("DB ERROR cancel update: " . $e->getMessage());
        }

        apiRequest('answerCallbackQuery', [
            'callback_query_id'=> $cb['id'],
            'text' => '❌ Payment cancelled.'
        ]);
        exit;
    }

    // LEGACY verify_{order_id}
    if (preg_match('#^verify_(\d+)$#', $data, $m)) {
        apiRequest('answerCallbackQuery', [
            'callback_query_id'=> $cb['id'],
            'text' => 'ℹ️ Use the Verify Payment button on the QR message to confirm payment.'
        ]);
        exit;
    }

    // remove_{order_id}
    if (preg_match('#^remove_(\d+)$#', $data, $m)) {
        $order_id = (int)$m[1];
        try {
            $stmt = $pdo->prepare("SELECT user_id FROM orders WHERE id = ?");
            $stmt->execute([$order_id]);
            $o = $stmt->fetch();
        } catch (PDOException $e) {
            error_log("DB ERROR remove fetch: ".$e->getMessage());
            apiRequest('answerCallbackQuery', ['callback_query_id'=> $cb['id'], 'text' => '⚠️ Internal error.']);
            exit;
        }
        if (!$o) {
            apiRequest('answerCallbackQuery', ['callback_query_id'=> $cb['id'], 'text' => '❌ Order not found.']);
            exit;
        }
        $userRow = $user;
        if (!$userRow) {
            apiRequest('answerCallbackQuery', ['callback_query_id'=> $cb['id'], 'text' => '⚠️ User error.']);
            exit;
        }
        if ((int)$o['user_id'] !== (int)$userRow['id']) {
            apiRequest('answerCallbackQuery', ['callback_query_id'=> $cb['id'], 'text' => '⛔ You can only remove your own purchases.']);
            exit;
        }
        try {
            $stmt = $pdo->prepare("UPDATE orders SET visible = 0 WHERE id = ? AND user_id = ?");
            $stmt->execute([$order_id, $userRow['id']]);
        } catch (PDOException $e) {
            error_log("DB ERROR remove update: ".$e->getMessage());
            apiRequest('answerCallbackQuery', ['callback_query_id'=> $cb['id'], 'text' => '⚠️ Could not remove.']);
            exit;
        }
        apiRequest('answerCallbackQuery', ['callback_query_id'=> $cb['id'], 'text' => '🗑️ Removed from your purchased list.']);
        @apiRequest('editMessageCaption', [
            'chat_id' => $chat_id,
            'message_id' => $msg_id,
            'caption' => "✅ Removed from your purchased list."
        ]);
        exit;
    }

    apiRequest('answerCallbackQuery', ['callback_query_id'=> $cb['id']]);
    exit;
}