<?php

/* ===========================
   ATPLUS Key Server
   config.php
=========================== */

// MySQL
$db_host = "localhost";
$db_name = "huudasit_db";
$db_user = "huudasit_user";
$db_pass = "142cracker";

// Kết nối
$conn = new mysqli($db_host, $db_user, $db_pass, $db_name);

// Kiểm tra
if ($conn->connect_error) {
    die(json_encode([
        "success" => false,
        "message" => "Database Error"
    ]));
}

// UTF8
$conn->set_charset("utf8mb4");

// Múi giờ Việt Nam
date_default_timezone_set("Asia/Ho_Chi_Minh");

// Link4m API — dùng để rút gọn link "lấy key" (request_key.php)
define("LINK4M_API_KEY", "6a524d2593451c386738b7eb");
define("LINK4M_ENDPOINT", "https://link4m.co/st");

// Gtraffic — dịch vụ rút gọn thứ 2, dùng tham số "apikey" (khác link4m dùng "api")
define("GTRAFFIC_API_KEY", "1dfd120b9a6347fdabbe978fa1f3a097");
define("GTRAFFIC_ENDPOINT", "https://gtraffic.io/st");

function build_link4m_url($destination, $apiKey = null)
{
    $key = $apiKey !== null && $apiKey !== "" ? $apiKey : LINK4M_API_KEY;
    return LINK4M_ENDPOINT . "?api=" . urlencode($key) . "&url=" . urlencode($destination);
}

function build_gtraffic_url($destination, $apiKey = null)
{
    $key = $apiKey !== null && $apiKey !== "" ? $apiKey : GTRAFFIC_API_KEY;
    return GTRAFFIC_ENDPOINT . "?apikey=" . urlencode($key) . "&url=" . urlencode($destination);
}

// Ontops — API tạo short link (khác Link4m/Gtraffic: gọi API lấy URL rồi redirect user)
define("ONTOPS_API_KEY", "db8d4443503e4b958b63e3268593595e");
define("ONTOPS_ENDPOINT", "https://api-management.ontops.link/api/public/create-short-link");
define("ONTOPS_SHORT_BASE", "https://ontops.link/");

/**
 * Gọi Ontops API, trả về short URL trang vượt link (không phải JSON API).
 * Response mẫu: {"id":"T3qQEXo","url":"https://...","remaining":49998}
 * Short link user cần mở: https://ontops.link/{id}
 */
function create_ontops_short_link($destination, $apiKey = null)
{
    $key = $apiKey !== null && $apiKey !== "" ? $apiKey : ONTOPS_API_KEY;
    $apiUrl = ONTOPS_ENDPOINT . "?apikey=" . urlencode($key) . "&url=" . urlencode($destination);

    $raw = "";
    // Ưu tiên cURL (InfinityFree thường chặn allow_url_fopen)
    if (function_exists("curl_init")) {
        $ch = curl_init($apiUrl);
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_CONNECTTIMEOUT => 10,
            CURLOPT_TIMEOUT => 15,
            CURLOPT_SSL_VERIFYPEER => false,
            CURLOPT_SSL_VERIFYHOST => 0,
            CURLOPT_HTTPHEADER => [
                "Accept: application/json",
                "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/120.0.0.0",
            ],
        ]);
        $raw = curl_exec($ch);
        curl_close($ch);
        if ($raw === false) $raw = "";
    }
    if ($raw === "") {
        $ctx = stream_context_create([
            "http" => [
                "method" => "GET",
                "timeout" => 15,
                "header" => "Accept: application/json
User-Agent: Mozilla/5.0
",
                "ignore_errors" => true,
            ],
            "ssl" => [
                "verify_peer" => false,
                "verify_peer_name" => false,
            ],
        ]);
        $raw = @file_get_contents($apiUrl, false, $ctx);
        if ($raw === false) $raw = "";
    }
    if ($raw === "") {
        return "";
    }

    $data = json_decode($raw, true);
    if (!is_array($data)) {
        return "";
    }

    // Bị ban / lỗi
    if (!empty($data["banned"]) || !empty($data["error"])) {
        return "";
    }

    // Ưu tiên id → https://ontops.link/{id} (trang nhiệm vụ)
    if (!empty($data["id"]) && is_string($data["id"])) {
        $id = preg_replace('/[^A-Za-z0-9_-]/', '', $data["id"]);
        if ($id !== "") {
            return "https://ontops.link/" . $id;
        }
    }

    // Fallback các field short URL đầy đủ nếu API có
    foreach (["short_url", "shortUrl", "shortlink", "short_link", "link"] as $k) {
        if (!empty($data[$k]) && is_string($data[$k]) && preg_match('#^https?://#i', $data[$k])) {
            // Không bao giờ trả về URL API JSON
            if (stripos($data[$k], "api-management.ontops") !== false) {
                continue;
            }
            if (stripos($data[$k], "create-short-link") !== false) {
                continue;
            }
            return $data[$k];
        }
    }

    return "";
}

/**
 * Tạo URL bước rút gọn để redirect user.
 * link4m / gtraffic: gateway ?api=&url=
 * ontops: short link https://ontops.link/{id} (sau khi gọi API)
 */
function build_shortener_redirect($service, $destination, $keys, $sellerRef = "")
{
    $service = strtolower(trim((string)$service));
    if ($service === "gtraffic") {
        return build_gtraffic_url($destination, $keys["gtraffic"] ?? null);
    }
    if ($service === "ontops") {
        // Không gọi API từ server (IP host hay bị Ontops banned).
        // Chuyển user qua ontops_go.php → JS gọi API bằng IP trình duyệt → ontops.link/{id}
        $q = "url=" . urlencode($destination);
        if ($sellerRef !== "") {
            $q .= "&s=" . urlencode($sellerRef);
        }
        return rtrim(SITE_BASE_URL, "/") . "/ontops_go.php?" . $q;
    }
    return build_link4m_url($destination, $keys["link4m"] ?? null);
}


// Domain gốc của server — dùng để tự dựng link claim.php khi tạo link4m link.
// Đổi lại nếu bạn đổi domain.
define("SITE_BASE_URL", "https://huuda.is-best.net");

function response($data){
    header("Content-Type: application/json");
    echo json_encode($data, JSON_UNESCAPED_UNICODE);
    exit();
}

function generateKey($length = 16)
{
    $chars = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
    $key = "";

    for ($i = 0; $i < $length; $i++) {
        $key .= $chars[random_int(0, strlen($chars) - 1)];
    }

    return substr($key, 0, 4) . "-" .
           substr($key, 4, 4) . "-" .
           substr($key, 8, 4) . "-" .
           substr($key, 12, 4);
}

/* ===========================
   Admin session / security helpers
=========================== */

function admin_session_start()
{
    if (session_status() === PHP_SESSION_NONE) {
        session_set_cookie_params([
            "httponly" => true,
            "samesite" => "Lax",
            "secure"   => isset($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] !== "off",
        ]);
        session_start();
    }
}

function require_admin()
{
    admin_session_start();
    if (empty($_SESSION["admin"])) {
        header("Location: login.php");
        exit();
    }
    // Idle timeout: 30 minutes
    if (!empty($_SESSION["last_activity"]) && (time() - $_SESSION["last_activity"] > 1800)) {
        session_unset();
        session_destroy();
        header("Location: login.php?timeout=1");
        exit();
    }
    $_SESSION["last_activity"] = time();
}

function csrf_token()
{
    admin_session_start();
    if (empty($_SESSION["csrf_token"])) {
        $_SESSION["csrf_token"] = bin2hex(random_bytes(32));
    }
    return $_SESSION["csrf_token"];
}

function csrf_field()
{
    return '<input type="hidden" name="csrf_token" value="' . htmlspecialchars(csrf_token()) . '">';
}

function csrf_verify()
{
    admin_session_start();
    $token = $_POST["csrf_token"] ?? $_GET["csrf_token"] ?? "";
    if (empty($_SESSION["csrf_token"]) || !hash_equals($_SESSION["csrf_token"], $token)) {
        http_response_code(403);
        die("Yêu cầu không hợp lệ hoặc đã hết hạn. Vui lòng quay lại và thử lại.");
    }
}

/* Simple login throttle keyed on IP (table auto-created) so brute forcing
   the admin login is rate limited. */
function login_attempts_guard($conn, $ip)
{
    $conn->query("CREATE TABLE IF NOT EXISTS login_attempts (
        ip VARCHAR(45) PRIMARY KEY,
        attempts INT NOT NULL DEFAULT 0,
        locked_until DATETIME NULL
    )");

    $stmt = $conn->prepare("SELECT locked_until FROM login_attempts WHERE ip=?");
    $stmt->bind_param("s", $ip);
    $stmt->execute();
    $row = $stmt->get_result()->fetch_assoc();

    if ($row && $row["locked_until"] && strtotime($row["locked_until"]) > time()) {
        $waitMin = (int)ceil((strtotime($row["locked_until"]) - time()) / 60);
        die("Quá nhiều lần đăng nhập sai. Vui lòng thử lại sau {$waitMin} phút.");
    }
}

function login_attempts_fail($conn, $ip)
{
    $stmt = $conn->prepare("
        INSERT INTO login_attempts (ip, attempts, locked_until)
        VALUES (?, 1, NULL)
        ON DUPLICATE KEY UPDATE attempts = attempts + 1
    ");
    $stmt->bind_param("s", $ip);
    $stmt->execute();

    $stmt = $conn->prepare("SELECT attempts FROM login_attempts WHERE ip=?");
    $stmt->bind_param("s", $ip);
    $stmt->execute();
    $attempts = (int)($stmt->get_result()->fetch_assoc()["attempts"] ?? 0);

    if ($attempts >= 5) {
        $lockUntil = date("Y-m-d H:i:s", time() + 15 * 60);
        $stmt = $conn->prepare("UPDATE login_attempts SET locked_until = ? WHERE ip=?");
        $stmt->bind_param("ss", $lockUntil, $ip);
        $stmt->execute();
    }
}

function login_attempts_reset($conn, $ip)
{
    $stmt = $conn->prepare("DELETE FROM login_attempts WHERE ip=?");
    $stmt->bind_param("s", $ip);
    $stmt->execute();
}

/* ===========================
   Key limits (key dùng chung nhiều thiết bị)
=========================== */

function ensure_key_limits_table($conn)
{
    $conn->query("CREATE TABLE IF NOT EXISTS key_limits (
        user_key VARCHAR(64) PRIMARY KEY,
        key_name VARCHAR(100) NULL,
        max_devices INT NOT NULL DEFAULT 1,
        expired DATETIME NULL,
        status TINYINT NOT NULL DEFAULT 1,
        created DATETIME NOT NULL
    )");

    // Nếu bảng đã tồn tại từ trước (chưa có cột key_name) -> thêm cột, không mất dữ liệu
    $check = $conn->query("SHOW COLUMNS FROM key_limits LIKE 'key_name'");
    if ($check && $check->num_rows == 0) {
        $conn->query("ALTER TABLE key_limits ADD COLUMN key_name VARCHAR(100) NULL AFTER user_key");
    }
}

/* ===========================
   Lịch sử đăng nhập admin
=========================== */

function ensure_login_history_table($conn)
{
    $conn->query("CREATE TABLE IF NOT EXISTS admin_login_history (
        id INT AUTO_INCREMENT PRIMARY KEY,
        username VARCHAR(100) NOT NULL,
        ip VARCHAR(45) NOT NULL,
        user_agent VARCHAR(255) NULL,
        success TINYINT NOT NULL,
        created DATETIME NOT NULL
    )");
}

function log_admin_login($conn, $username, $ip, $success)
{
    ensure_login_history_table($conn);
    $ua = substr($_SERVER["HTTP_USER_AGENT"] ?? "", 0, 255);
    $now = date("Y-m-d H:i:s");
    $successInt = $success ? 1 : 0;

    $stmt = $conn->prepare("
        INSERT INTO admin_login_history (username, ip, user_agent, success, created)
        VALUES (?, ?, ?, ?, ?)
    ");
    $stmt->bind_param("sssis", $username, $ip, $ua, $successInt, $now);
    $stmt->execute();
}

/* ===========================
   Định nghĩa các loại key (dùng chung cho keys.php và các hành động hàng loạt)
=========================== */

function get_key_categories()
{
    $isAdminMade = "(device_name='Manual' OR created_ip='ADMIN')";
    return [
        "locked"    => ["label" => "🔒 Đã khóa",   "where" => "status=0", "needsNow" => false],
        "expired"   => ["label" => "⌛ Hết hạn",    "where" => "status=1 AND expired IS NOT NULL AND expired < ?", "needsNow" => true],
        "admin"     => ["label" => "🛠️ Admin tạo",  "where" => "status=1 AND (expired IS NULL OR expired >= ?) AND $isAdminMade", "needsNow" => true],
        "permanent" => ["label" => "♾️ Vĩnh viễn",  "where" => "status=1 AND expired IS NULL AND NOT $isAdminMade", "needsNow" => false],
        "timed"     => ["label" => "🕐 Còn hạn",    "where" => "status=1 AND expired IS NOT NULL AND expired >= ? AND NOT $isAdminMade", "needsNow" => true],
        "shared"    => ["label" => "🔗 Dùng chung", "where" => null, "needsNow" => false],
    ];
}

/* ===========================
   Mở rộng claim_tokens cho trang tạo link công khai (getkey.php)
=========================== */

function ensure_claim_tokens_columns($conn)
{
    $checkHours = $conn->query("SHOW COLUMNS FROM claim_tokens LIKE 'expire_hours'");
    if ($checkHours && $checkHours->num_rows == 0) {
        $conn->query("ALTER TABLE claim_tokens ADD COLUMN expire_hours INT NULL");
    }

    $checkDevices = $conn->query("SHOW COLUMNS FROM claim_tokens LIKE 'max_devices'");
    if ($checkDevices && $checkDevices->num_rows == 0) {
        $conn->query("ALTER TABLE claim_tokens ADD COLUMN max_devices INT NULL");
    }

    $checkSeller = $conn->query("SHOW COLUMNS FROM claim_tokens LIKE 'seller_id'");
    if ($checkSeller && $checkSeller->num_rows == 0) {
        $conn->query("ALTER TABLE claim_tokens ADD COLUMN seller_id INT NULL DEFAULT NULL");
        $conn->query("ALTER TABLE claim_tokens ADD INDEX idx_claim_seller (seller_id)");
    }

    $checkChain = $conn->query("SHOW COLUMNS FROM claim_tokens LIKE 'chain'");
    if ($checkChain && $checkChain->num_rows == 0) {
        $conn->query("ALTER TABLE claim_tokens ADD COLUMN chain VARCHAR(40) NULL DEFAULT NULL");
    }
}

/* ===========================
   Seller / Reseller system
=========================== */

function ensure_sellers_table($conn)
{
    $conn->query("CREATE TABLE IF NOT EXISTS sellers (
        id INT AUTO_INCREMENT PRIMARY KEY,
        username VARCHAR(64) NOT NULL UNIQUE,
        password VARCHAR(255) NOT NULL,
        display_name VARCHAR(120) NULL,
        max_keys INT NOT NULL DEFAULT 20,
        max_devices INT NOT NULL DEFAULT 1,
        default_hours INT NOT NULL DEFAULT 24,
        can_create_permanent TINYINT NOT NULL DEFAULT 0,
        link4m_api_key VARCHAR(128) NULL,
        gtraffic_api_key VARCHAR(128) NULL,
        ontops_api_key VARCHAR(128) NULL,
        status TINYINT NOT NULL DEFAULT 1,
        note TEXT NULL,
        created DATETIME NOT NULL,
        last_login DATETIME NULL
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");

    // migrate old sellers table missing API columns
    $c1 = $conn->query("SHOW COLUMNS FROM sellers LIKE 'link4m_api_key'");
    if ($c1 && $c1->num_rows == 0) {
        $conn->query("ALTER TABLE sellers ADD COLUMN link4m_api_key VARCHAR(128) NULL AFTER can_create_permanent");
    }
    $c2 = $conn->query("SHOW COLUMNS FROM sellers LIKE 'gtraffic_api_key'");
    if ($c2 && $c2->num_rows == 0) {
        $conn->query("ALTER TABLE sellers ADD COLUMN gtraffic_api_key VARCHAR(128) NULL AFTER link4m_api_key");
    }
    $c3 = $conn->query("SHOW COLUMNS FROM sellers LIKE 'ontops_api_key'");
    if ($c3 && $c3->num_rows == 0) {
        $conn->query("ALTER TABLE sellers ADD COLUMN ontops_api_key VARCHAR(128) NULL AFTER gtraffic_api_key");
    }

    $check = $conn->query("SHOW COLUMNS FROM key_limits LIKE 'seller_id'");
    if ($check && $check->num_rows == 0) {
        $conn->query("ALTER TABLE key_limits ADD COLUMN seller_id INT NULL DEFAULT NULL AFTER created");
        $conn->query("ALTER TABLE key_limits ADD INDEX idx_seller (seller_id)");
    }

    $check2 = $conn->query("SHOW COLUMNS FROM users LIKE 'seller_id'");
    if ($check2 && $check2->num_rows == 0) {
        $conn->query("ALTER TABLE users ADD COLUMN seller_id INT NULL DEFAULT NULL");
        $conn->query("ALTER TABLE users ADD INDEX idx_user_seller (seller_id)");
    }
}

function seller_session_start()
{
    if (session_status() === PHP_SESSION_NONE) {
        session_set_cookie_params([
            "httponly" => true,
            "samesite" => "Lax",
            "secure"   => isset($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] !== "off",
        ]);
        session_start();
    }
}

function require_seller()
{
    seller_session_start();
    if (empty($_SESSION["seller_id"])) {
        header("Location: login.php");
        exit();
    }
    if (!empty($_SESSION["seller_last_activity"]) && (time() - $_SESSION["seller_last_activity"] > 3600)) {
        session_unset();
        session_destroy();
        header("Location: login.php?err=" . urlencode("Phiên đăng nhập đã hết hạn"));
        exit();
    }
    $_SESSION["seller_last_activity"] = time();
}

function current_seller($conn)
{
    if (empty($_SESSION["seller_id"])) return null;
    $id = (int)$_SESSION["seller_id"];
    $stmt = $conn->prepare("SELECT * FROM sellers WHERE id=? AND status=1 LIMIT 1");
    $stmt->bind_param("i", $id);
    $stmt->execute();
    $row = $stmt->get_result()->fetch_assoc();
    return $row ?: null;
}

function seller_key_count($conn, $sellerId)
{
    $stmt = $conn->prepare("SELECT COUNT(*) c FROM key_limits WHERE seller_id=?");
    $stmt->bind_param("i", $sellerId);
    $stmt->execute();
    return (int)$stmt->get_result()->fetch_assoc()["c"];
}

/** Resolve seller from ?s= username or id */
function find_seller_by_ref($conn, $ref)
{
    $ref = trim((string)$ref);
    if ($ref === "") return null;

    if (ctype_digit($ref)) {
        $id = (int)$ref;
        $stmt = $conn->prepare("SELECT * FROM sellers WHERE id=? AND status=1 LIMIT 1");
        $stmt->bind_param("i", $id);
    } else {
        $stmt = $conn->prepare("SELECT * FROM sellers WHERE username=? AND status=1 LIMIT 1");
        $stmt->bind_param("s", $ref);
    }
    $stmt->execute();
    return $stmt->get_result()->fetch_assoc() ?: null;
}

/**
 * Lấy API key shortener của seller; fallback về key admin nếu seller chưa cấu hình.
 */
function seller_shortener_keys($seller)
{
    $link4m = "";
    $gtraffic = "";
    $ontops = "";
    if (is_array($seller)) {
        $link4m = trim($seller["link4m_api_key"] ?? "");
        $gtraffic = trim($seller["gtraffic_api_key"] ?? "");
        $ontops = trim($seller["ontops_api_key"] ?? "");
    }
    return [
        "link4m" => $link4m !== "" ? $link4m : LINK4M_API_KEY,
        "gtraffic" => $gtraffic !== "" ? $gtraffic : GTRAFFIC_API_KEY,
        "ontops" => $ontops !== "" ? $ontops : ONTOPS_API_KEY,
        "using_own_link4m" => $link4m !== "",
        "using_own_gtraffic" => $gtraffic !== "",
        "using_own_ontops" => $ontops !== "",
    ];
}

