<?php
// miniapp/api/config.php
header('Content-Type: application/json; charset=utf-8');

// --- تنظیمات دیتابیس ---
$DB_HOST = 'localhost';
$DB_NAME = 'gemaccir_369';
$DB_USER = 'gemaccir_369';
$DB_PASS = 'Alik.1997a';

// --- تنظیمات ربات (باید با فایل bot.php یکی باشد) ---
// لطفا توکن ربات خود را اینجا وارد کنید تا بتوانیم به ادمین پیام بفرستیم
define('BOT_TOKEN', '8513931261:AAFYsjXgmSSO13ixLn6RcysJiBq_NpJbdAs'); 
// آیدی عددی ادمین‌ها (با کاما جدا کنید)
define('ADMIN_IDS', '5516198479'); 

try {
    $pdo = new PDO(
        "mysql:host=$DB_HOST;dbname=$DB_NAME;charset=utf8mb4",
        $DB_USER,
        $DB_PASS,
        [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        ]
    );

    // ساخت جداول لازم اگر وجود ندارند
    $pdo->exec("CREATE TABLE IF NOT EXISTS `settings` (
        `key_name` VARCHAR(50) PRIMARY KEY,
        `value` TEXT
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;");
    
    // جدول دسته‌بندی پلن‌ها
    $pdo->exec("CREATE TABLE IF NOT EXISTS plan_categories (
        id INT AUTO_INCREMENT PRIMARY KEY,
        code VARCHAR(64) NOT NULL UNIQUE,
        name VARCHAR(128) NOT NULL,
        display_order INT DEFAULT 0,
        is_active TINYINT(1) DEFAULT 1,
        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;");
    
    // دسته‌بندی‌های پیش‌فرض
    $pdo->exec("INSERT IGNORE INTO plan_categories (code, name, display_order) VALUES
        ('VIP_1M', '👑 VIP یک‌ماهه (نامحدود)', 1),
        ('VIP_3M', '⏳ VIP سه‌ماهه (نامحدود)', 2),
        ('VOL_1M', '📦 حجمی یک‌ماهه', 3);");
    
    // جدول کانفیگ‌ها
    $pdo->exec("CREATE TABLE IF NOT EXISTS configs (
        id INT AUTO_INCREMENT PRIMARY KEY,
        plan_code VARCHAR(64) NOT NULL,
        title VARCHAR(255) NOT NULL,
        config_link TEXT DEFAULT NULL,
        config_text MEDIUMTEXT DEFAULT NULL,
        config_file_id VARCHAR(255) DEFAULT NULL,
        photo_file_id VARCHAR(255) DEFAULT NULL,
        is_used TINYINT(1) DEFAULT 0,
        used_by BIGINT DEFAULT NULL,
        used_at TIMESTAMP NULL,
        created_by BIGINT DEFAULT NULL,
        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
        INDEX(plan_code),
        INDEX(is_used)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;");
    
    // جدول اکانت‌های تست
    $pdo->exec("CREATE TABLE IF NOT EXISTS test_accounts (
        id INT AUTO_INCREMENT PRIMARY KEY,
        user_id BIGINT NOT NULL,
        config_id INT DEFAULT NULL,
        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
        expires_at TIMESTAMP NULL,
        INDEX(user_id)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;");

    // اضافه کردن ستون‌های لازم به جدول configs (اگر وجود ندارند)
    // بررسی و اضافه کردن ستون is_used
    $checkColumn = $pdo->query("SHOW COLUMNS FROM configs LIKE 'is_used'");
    if ($checkColumn->rowCount() == 0) {
        $pdo->exec("ALTER TABLE configs ADD COLUMN is_used TINYINT(1) DEFAULT 0");
    }
    
    // بررسی و اضافه کردن ستون used_by
    $checkColumn = $pdo->query("SHOW COLUMNS FROM configs LIKE 'used_by'");
    if ($checkColumn->rowCount() == 0) {
        $pdo->exec("ALTER TABLE configs ADD COLUMN used_by BIGINT DEFAULT NULL");
    }
    
    // بررسی و اضافه کردن ستون used_at
    $checkColumn = $pdo->query("SHOW COLUMNS FROM configs LIKE 'used_at'");
    if ($checkColumn->rowCount() == 0) {
        $pdo->exec("ALTER TABLE configs ADD COLUMN used_at TIMESTAMP NULL");
    }
    
    // بررسی و اضافه کردن ستون created_by
    $checkColumn = $pdo->query("SHOW COLUMNS FROM configs LIKE 'created_by'");
    if ($checkColumn->rowCount() == 0) {
        $pdo->exec("ALTER TABLE configs ADD COLUMN created_by BIGINT DEFAULT NULL");
    }
    
    // بررسی و اضافه کردن ستون created_at
    $checkColumn = $pdo->query("SHOW COLUMNS FROM configs LIKE 'created_at'");
    if ($checkColumn->rowCount() == 0) {
        $pdo->exec("ALTER TABLE configs ADD COLUMN created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP");
    }
    
    // 🎁 اضافه کردن ستون‌های سیستم جایزه و بونوس
    $checkColumn = $pdo->query("SHOW COLUMNS FROM users LIKE 'has_wallet_bonus'");
    if ($checkColumn->rowCount() == 0) {
        $pdo->exec("ALTER TABLE users ADD COLUMN has_wallet_bonus TINYINT(1) DEFAULT 0");
    }
    
    $checkColumn = $pdo->query("SHOW COLUMNS FROM users LIKE 'total_cashback'");
    if ($checkColumn->rowCount() == 0) {
        $pdo->exec("ALTER TABLE users ADD COLUMN total_cashback INT DEFAULT 0");
    }
    
    // 🔔 جدول یادآورهای انقضای سرویس
    $pdo->exec("CREATE TABLE IF NOT EXISTS service_expiry_reminders (
        id INT AUTO_INCREMENT PRIMARY KEY,
        sale_id INT NOT NULL,
        user_id BIGINT NOT NULL,
        reminder_type ENUM('2_DAYS', '1_DAY', 'EXPIRED') NOT NULL,
        sent_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
        UNIQUE KEY unique_reminder (sale_id, reminder_type),
        INDEX(sale_id),
        INDEX(user_id)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;");

} catch (PDOException $e) {
    http_response_code(500);
    echo json_encode([
        'ok'    => false,
        'error' => 'DB connection failed: ' . $e->getMessage(),
    ], JSON_UNESCAPED_UNICODE);
    exit;
}

// --- توابع کمکی ---

// گرفتن یک تنظیم (مثلا شماره کارت)
function get_option($key, $default = '') {
    global $pdo;
    $stmt = $pdo->prepare("SELECT value FROM settings WHERE key_name = ?");
    $stmt->execute([$key]);
    $res = $stmt->fetchColumn();
    return $res !== false ? $res : $default;
}

// ذخیره/آپدیت تنظیم
function update_option($key, $value) {
    global $pdo;
    $stmt = $pdo->prepare("INSERT INTO settings (key_name, value) VALUES (:k, :v) ON DUPLICATE KEY UPDATE value = :v");
    return $stmt->execute([':k' => $key, ':v' => $value]);
}

// اضافه کردن define API
define('API', 'https://api.telegram.org/bot' . BOT_TOKEN . '/');

// بررسی ادمین بودن کاربر
function isAdmin($uid): bool {
  $ids = array_map('trim', explode(',', ADMIN_IDS));
  return in_array((string)$uid, $ids, true);
}

// اطمینان از وجود کاربر در دیتابیس
function ensureUser(array $u): void {
  global $pdo;
  $stmt = $pdo->prepare("INSERT INTO users (id,username,first_name,last_name,is_admin)
    VALUES (:id,:un,:fn,:ln,:is_admin)
    ON DUPLICATE KEY UPDATE username=VALUES(username), first_name=VALUES(first_name), last_name=VALUES(last_name), is_admin=VALUES(is_admin)");
  $stmt->execute([
    ':id'=>$u['id'],
    ':un'=>$u['username']??null,
    ':fn'=>$u['first_name']??null,
    ':ln'=>$u['last_name']??null,
    ':is_admin'=> isAdmin($u['id']) ? 1 : 0
  ]);
}

// ارسال پیام به تلگرام
function tg(string $method, array $params = []) {
  $ch = curl_init(API.$method);
  
  $post_fields = $params;
  $headers = [];

  if ($method === 'sendPhoto' && isset($params['photo']) && file_exists($params['photo'])) {
      $post_fields['photo'] = new CURLFile($params['photo']);
      $headers[] = "Content-Type: multipart/form-data";
  } else {
      $post_fields = json_encode($params, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);
      $headers[] = 'Content-Type: application/json';
  }

  curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST           => true,
    CURLOPT_HTTPHEADER     => $headers,
    CURLOPT_POSTFIELDS     => $post_fields,
    CURLOPT_CONNECTTIMEOUT => 5,
    CURLOPT_TIMEOUT        => 15,
  ]);
  $res = curl_exec($ch);
  if ($res === false) {
    error_log('TG_CURL_ERR: '.curl_error($ch));
    curl_close($ch);
    return null;
  }
  $code = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
  curl_close($ch);
  if ($code !== 200) error_log('TG_HTTP_'.$code.': '.$res);
  return json_decode($res, true);
}

/**
 * گرفتن موجودی کاربر
 */
function get_user_balance($user_id): int {
    global $pdo;
    try {
        $stmt = $pdo->prepare("SELECT balance FROM users WHERE id = :id");
        $stmt->execute([':id' => $user_id]);
        $row = $stmt->fetch(PDO::FETCH_ASSOC);
        
        return $row ? (int)$row['balance'] : 0;
    } catch (Exception $e) {
        error_log("Error in get_user_balance: " . $e->getMessage());
        return 0;
    }
}

/**
 * افزایش موجودی کاربر
 */
function add_user_balance($user_id, $amount): bool {
    global $pdo;
    try {
        $stmt = $pdo->prepare("UPDATE users SET balance = balance + :amount WHERE id = :id");
        return $stmt->execute([':amount' => $amount, ':id' => $user_id]);
    } catch (Exception $e) {
        error_log("Error in add_user_balance: " . $e->getMessage());
        return false;
    }
}

/**
 * گرفتن پلن از دیتابیس بر اساس plan_code
 * 🔧 جستجوی انعطاف‌پذیر
 */
function db_get_plan_by_code(string $code) {
  global $pdo;
  $code = strtoupper(trim($code));
  
  // ابتدا جستجوی دقیق
  $stmt = $pdo->prepare("SELECT * FROM plans WHERE plan_code = :c LIMIT 1");
  $stmt->execute([':c'=>$code]);
  $row = $stmt->fetch(PDO::FETCH_ASSOC);
  if ($row) return $row;
  
  // جستجوی case-insensitive
  $stmt = $pdo->prepare("SELECT * FROM plans WHERE UPPER(TRIM(plan_code)) = :c LIMIT 1");
  $stmt->execute([':c'=>$code]);
  $row = $stmt->fetch(PDO::FETCH_ASSOC);
  return $row ?: null;
}

/**
 * پلن‌ها (قیمت «تومان واقعی») - برای سازگاری با bot_get_plan
 */
function plans(): array {
  return [
    // VIP یک‌ماهه
    'VIP_1U_1M'   => ['title'=>'نامحدود VIP | یک‌ماهه | 1 کاربر', 'price'=>150000],
    'VIP_2U_1M'   => ['title'=>'نامحدود VIP | یک‌ماهه | 2 کاربر', 'price'=>299000],
    // VIP سه‌ماهه
    'VIP_1U_3M'   => ['title'=>'نامحدود VIP | سه‌ماهه | 1 کاربر', 'price'=>439000],
    'VIP_2U_3M'   => ['title'=>'نامحدود VIP | سه‌ماهه | 2 کاربر', 'price'=>599000],
    // حجمی یک‌ماهه
    'VOL_10G_1M'  => ['title'=>'حجمی | یک‌ماهه | 10 گیگ', 'price'=>49000],
    'VOL_20G_1M'  => ['title'=>'حجمی | یک‌ماهه | 20 گیگ', 'price'=>98000],
    'VOL_30G_1M'  => ['title'=>'حجمی | یک‌ماهه | 30 گیگ', 'price'=>147000],
  ];
}

/**
 * گرفتن اطلاعات پلن برای کل ربات:
 * 1) اول از plans (DB) می‌خواند
 * 2) اگر نبود و تابع plans() تعریف شده بود، از آن استفاده می‌کند (سازگاری با گذشته)
 * 🔧 یکسان‌سازی plan_code
 */
function bot_get_plan(string $code): ?array {
  // 🔧 یکسان‌سازی
  $code = strtoupper(trim($code));
  
  // 1) دیتابیس
  $row = db_get_plan_by_code($code);
  if ($row) {
    return [
      'title'          => $row['title'],
      'price'          => (int)$row['price'],
      'category'       => $row['category'],
      'duration_label' => $row['duration_label'],
      'users'          => $row['users'],
    ];
  }

  // 2) سازگاری با plans() قدیمی اگر در config.php تعریف شده باشد
  if (function_exists('plans')) {
    $all = plans();
    if (isset($all[$code])) return $all[$code];
  }

  error_log("⚠️ bot_get_plan: Plan not found for code='{$code}'");
  return null;
}

// اضافه کردن define CURRENCY_SUFFIX
define('CURRENCY_SUFFIX', ' تومان');

function money(int $amount): string {
  return number_format($amount).CURRENCY_SUFFIX;
}

function jdate($format, $timestamp = null, $timezone = null) {
    if ($timestamp === null) $timestamp = time();
    
    // تاریخ میلادی
    $g_year = date('Y', $timestamp);
    $g_month = date('m', $timestamp);
    $g_day = date('d', $timestamp);
    
    // تبدیل میلادی به شمسی (الگوریتم دقیق)
    $g_days_in_month = array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
    $j_days_in_month = array(31, 31, 31, 31, 31, 31, 30, 30, 30, 30, 30, 29);
    
    $gy = $g_year - 1600;
    $gm = $g_month - 1;
    $gd = $g_day - 1;
    
    $g_day_no = 365 * $gy + floor(($gy + 3) / 4) - floor(($gy + 99) / 100) + floor(($gy + 399) / 400);
    
    for ($i = 0; $i < $gm; ++$i) {
        $g_day_no += $g_days_in_month[$i];
    }
    if ($gm > 1 && (($gy % 4 == 0 && $gy % 100 != 0) || ($gy % 400 == 0))) {
        $g_day_no++;
    }
    $g_day_no += $gd;
    
    $j_day_no = $g_day_no - 79;
    
    $j_np = floor($j_day_no / 12053);
    $j_day_no = $j_day_no % 12053;
    
    $jy = 979 + 33 * $j_np + 4 * floor($j_day_no / 1461);
    $j_day_no %= 1461;
    
    if ($j_day_no >= 366) {
        $jy += floor(($j_day_no - 1) / 365);
        $j_day_no = ($j_day_no - 1) % 365;
    }
    
    for ($i = 0; $i < 11 && $j_day_no >= $j_days_in_month[$i]; ++$i) {
        $j_day_no -= $j_days_in_month[$i];
    }
    $jm = $i + 1;
    $jd = $j_day_no + 1;
    
    // نام ماه‌های شمسی
    $jmonths = array(
        '', 'فروردین', 'اردیبهشت', 'خرداد', 'تیر', 'مرداد', 'شهریور',
        'مهر', 'آبان', 'آذر', 'دی', 'بهمن', 'اسفند'
    );
    
    // فرمت‌دهی خروجی
    if ($format == 'd/m') {
        $result = sprintf("%02d/%s", $jd, $jmonths[$jm]);
    } else {
        $result = sprintf("%02d/%s/%04d", $jd, $jmonths[$jm], $jy);
    }
    
    // تبدیل اعداد انگلیسی به فارسی
    $english = array('0','1','2','3','4','5','6','7','8','9');
    $persian = array('۰','۱','۲','۳','۴','۵','۶','۷','۸','۹');
    
    return str_replace($english, $persian, $result);
}

// 🔧 تنظیمات قابل تغییر آمار فروش (از bot.php)
$GLOBALS['STATS_TABLE']            = 'orders';      // نام جدول سفارش‌ها یا پرداخت‌ها (مثلاً orders یا payments)
$GLOBALS['STATS_AMOUNT_COLUMN']    = 'price';       // ستون مبلغ پرداخت (به تومان)
$GLOBALS['STATS_STATUS_COLUMN']    = 'status';      // ستون وضعیت پرداخت
$GLOBALS['STATS_SUCCESS_STATUS']   = 'APPROVED';    // مقدار وضعیت موفق (مثلاً 'APPROVED' یا 'paid')
$GLOBALS['STATS_DATE_COLUMN']      = 'approved_at'; // ستون زمان پرداخت موفق (مثلاً approved_at یا paid_at یا created_at)
$GLOBALS['STATS_WEEK_MODE']        = 1;             // شروع هفته در MySQL: 1 = دوشنبه، 0 یا 7 = یکشنبه، ... (در صورت نیاز قابل تغییر)

/**
 * خواندن آمار فروش از دیتابیس (از bot.php)
 * خروجی همیشه اعداد صحیح برمی‌گرداند (حتی اگر دیتابیس خالی باشد -> 0)
 */
function get_sales_stats(PDO $pdo): array {
  global $GLOBALS;
  $STATS_TABLE            = $GLOBALS['STATS_TABLE'];
  $STATS_AMOUNT_COLUMN    = $GLOBALS['STATS_AMOUNT_COLUMN'];
  $STATS_STATUS_COLUMN    = $GLOBALS['STATS_STATUS_COLUMN'];
  $STATS_SUCCESS_STATUS   = $GLOBALS['STATS_SUCCESS_STATUS'];
  $STATS_DATE_COLUMN      = $GLOBALS['STATS_DATE_COLUMN'];
  $STATS_WEEK_MODE        = $GLOBALS['STATS_WEEK_MODE'];

  // برای خوانایی بیشتر
  $dateExpr = $STATS_DATE_COLUMN;
  $weekMode = (int)$STATS_WEEK_MODE;

  // کوئری جمع‌بندی آمار در یک شات
  $sql = "
    SELECT
      COUNT(*) AS total_count,
      COALESCE(SUM($STATS_AMOUNT_COLUMN), 0) AS total_amount,
  
      SUM(CASE WHEN DATE($dateExpr) = CURDATE() THEN 1 ELSE 0 END) AS today_count,
      COALESCE(SUM(CASE WHEN DATE($dateExpr) = CURDATE() THEN $STATS_AMOUNT_COLUMN ELSE 0 END), 0) AS today_amount,
  
      SUM(
        CASE
          WHEN YEAR($dateExpr) = YEAR(CURDATE())
           AND MONTH($dateExpr) = MONTH(CURDATE())
          THEN 1 ELSE 0
        END
      ) AS month_count,
      COALESCE(
        SUM(
          CASE
            WHEN YEAR($dateExpr) = YEAR(CURDATE())
             AND MONTH($dateExpr) = MONTH(CURDATE())
            THEN $STATS_AMOUNT_COLUMN ELSE 0
          END
        ), 0
      ) AS month_amount,
  
      SUM(
        CASE
          WHEN YEARWEEK($dateExpr, $weekMode) = YEARWEEK(CURDATE(), $weekMode)
          THEN 1 ELSE 0
        END
      ) AS week_count,
      COALESCE(
        SUM(
          CASE
            WHEN YEARWEEK($dateExpr, $weekMode) = YEARWEEK(CURDATE(), $weekMode)
            THEN $STATS_AMOUNT_COLUMN ELSE 0
          END
        ), 0
      ) AS week_amount
    FROM $STATS_TABLE
    WHERE $STATS_STATUS_COLUMN = :status
      AND $dateExpr IS NOT NULL
  ";

  $stmt = $pdo->prepare($sql);
  $stmt->execute([':status' => $STATS_SUCCESS_STATUS]);
  $row = $stmt->fetch(PDO::FETCH_ASSOC) ?: [];

  // اگر به هر دلیلی ستون‌ها NULL یا خالی بودند، به 0 تبدیل شوند
  $defaults = [
    'total_count'  => 0,
    'total_amount' => 0,
    'today_count'  => 0,
    'today_amount' => 0,
    'week_count'   => 0,
    'week_amount'  => 0,
    'month_count'  => 0,
    'month_amount' => 0,
  ];
  foreach ($defaults as $k => $v) {
    if (!isset($row[$k]) || $row[$k] === null) {
      $row[$k] = $v;
    }
  }

  // همه چیز را به int تبدیل می‌کنیم که warning ندهد
  return [
    'total_count'  => (int)$row['total_count'],
    'total_amount' => (int)$row['total_amount'],
    'today_count'  => (int)$row['today_count'],
    'today_amount' => (int)$row['today_amount'],
    'week_count'   => (int)$row['week_count'],
    'week_amount'  => (int)$row['week_amount'],
    'month_count'  => (int)$row['month_count'],
    'month_amount' => (int)$row['month_amount'],
  ];
}

/**
 * ساخت متن فارسی آمار فروش برای نمایش به ادمین (از bot.php)
 */
function build_sales_stats_text(array $s): string {
  $txt  = "📊 آمار فروش ربات\n\n";
  $txt .= "🧾 تعداد فروش:\n";
  $txt .= "— کل اشتراک‌ها: {$s['total_count']} عدد\n";
  $txt .= "— این ماه: {$s['month_count']} عدد\n";
  $txt .= "— این هفته: {$s['week_count']} عدد\n";
  $txt .= "— امروز: {$s['today_count']} عدد\n\n";

  // فرض بر این است که تابع money() خودش جداکننده هزارگان را اعمال می‌کند
  $txt .= "💰 درآمد (تومان):\n";
  $txt .= "— مجموع کل: ".money($s['total_amount'])."\n";
  $txt .= "— این ماه: ".money($s['month_amount'])."\n";
  $txt .= "— این هفته: ".money($s['week_amount'])."\n";
  $txt .= "— امروز: ".money($s['today_amount'])."\n";

  return $txt;
}

/**
 * تابع گرفتن تعداد کل کاربران (از bot.php)
 */
function get_total_users_count() {
    global $pdo;
    $stmt = $pdo->prepare("SELECT COUNT(*) as count FROM users");
    $stmt->execute();
    $result = $stmt->fetch();
    return $result ? (int)$result['count'] : 0;
}

// اضافه کردن define CARD_NUMBER و V2_ONLY
define('CARD_NUMBER', '6104331062907218'); // بنام زحمت کش
define('V2_ONLY', true); // فقط V2Ray

/**
 * عنوان فارسی دسته پلن (از bot.php)
 */
function plan_category_label(string $cat): string {
  switch ($cat) {
    case 'VIP_1M': return '👑 VIP یک‌ماهه (نامحدود)';
    case 'VIP_3M': return '⏳ VIP سه‌ماهه (نامحدود)';
    case 'VOL_1M': return '📦 حجمی یک‌ماهه';
    default:       return $cat;
  }
}

/**
 * لیست پلن‌های یک دسته از دیتابیس (از bot.php)
 */
function db_get_plans_by_category(string $category): array {
  global $pdo;
  
  error_log("🔄 DEBUG db_get_plans_by_category: category = {$category}");
  
  $stmt = $pdo->prepare("SELECT * FROM plans WHERE category = :c AND is_active = 1 ORDER BY price ASC, id ASC");
  $stmt->execute([':c' => $category]);
  $result = $stmt->fetchAll(PDO::FETCH_ASSOC) ?: [];
  
  error_log("🔍 DEBUG: Found " . count($result) . " plans for category {$category}");
  return $result;
}

/**
 * تبدیل ورودی ادمین به اجزای duration|users|price (از bot.php)
 * فرمت: 1m|3user|320000
 */
function parse_plan_input(string $input): ?array {
  $input = trim($input);
  error_log("🔄 DEBUG parse_plan_input: input = '{$input}'");
  
  // جایگزین کردن regex در parse_plan_input
if (!preg_match('/^(\d+[a-z]+)\|(\d+)user\|(\d+)$/i', $input, $m)) {
    error_log("❌ DEBUG: regex failed for input: {$input}");
    return null;
}
  
  error_log("✅ DEBUG: regex matches: " . print_r($m, true));
  
  return [
    'duration_raw' => strtolower($m[1]),
    'users'        => (int)$m[2],
    'price'        => (int)$m[3],
  ];
}

/**
 * ساختن اطلاعات پلن از روی دسته + ورودی ادمین (از bot.php)
 * خروجی شامل category, duration_label, users, price, plan_code, title
 */
function build_plan_from_input(string $category, string $input): ?array {
  error_log("🔄 DEBUG build_plan_from_input START: category = {$category}, input = {$input}");
  
  $parsed = parse_plan_input($input);
  if (!$parsed) {
    error_log("❌ DEBUG: parse_plan_input returned null");
    
    // پیام خطای مفید برای ادمین - در مینی اپ نیازی به tg نیست، فقط null برمی‌گردانیم
    return null;
  }
  
  error_log("✅ DEBUG: parsed data = " . print_r($parsed, true));
  
  $duration = $parsed['duration_raw'];
  $users    = $parsed['users'];
  $price    = $parsed['price'];

  $plan_code = null;
  $title     = null;

  if (strpos($category, 'VIP_') === 0) {
    error_log("🔵 DEBUG: Processing VIP category");
    
    if (!preg_match('/VIP_(\d+)M/', $category, $m)) {
      error_log("❌ DEBUG: VIP category regex failed");
      return null;
    }
    
    $months = (int)$m[1];
    error_log("🔵 DEBUG: VIP months = {$months}");

    // کد: VIP_{users}U_{months}M
    $plan_code = 'VIP_'.$users.'U_'.$months.'M';
    $title = "اشتراک VIP {$months}ماهه | {$users} کاربر";

  } elseif ($category === 'VOL_1M') {
    error_log("🟢 DEBUG: Processing VOL category");
    
    if (!preg_match('/^(\d+)[gG]$/', $duration, $m)) {
      error_log("❌ DEBUG: VOL duration regex failed for: {$duration}");
      // پیام خطای مفید برای ادمین - در مینی اپ نیازی به tg نیست، فقط null برمی‌گردانیم
      return null;
    }
    
    $gb = (int)$m[1];
    error_log("🟢 DEBUG: VOL GB = {$gb}");

    $plan_code = 'VOL_'.$gb.'G_1M';
    $title = "پلن حجمی {$gb} گیگ | 1 ماهه";

  } else {
    error_log("❌ DEBUG: Unknown category: {$category}");
    return null;
  }

  $result = [
    'category'       => $category,
    'duration_label' => $duration,
    'users'          => $users,
    'price'          => $price,
    'plan_code'      => $plan_code,
    'title'          => $title,
  ];
  
  error_log("✅ DEBUG: Final result = " . print_r($result, true));
  return $result;
}

/**
 * درج/آپدیت پلن در دیتابیس (ON DUPLICATE KEY) (از bot.php)
 * اگر plan_code تکراری باشد، قیمت و مشخصاتش آپدیت می‌شود.
 */
function db_upsert_plan(array $plan): int {
  global $pdo;
  $stmt = $pdo->prepare("
    INSERT INTO plans (category,duration_label,users,price,plan_code,title,is_active)
    VALUES (:cat,:dur,:u,:pr,:code,:title,1)
    ON DUPLICATE KEY UPDATE
      category = VALUES(category),
      duration_label = VALUES(duration_label),
      users = VALUES(users),
      price = VALUES(price),
      title = VALUES(title),
      is_active = 1,
      updated_at = NOW()
  ");
  $stmt->execute([
    ':cat'   => $plan['category'],
    ':dur'   => $plan['duration_label'],
    ':u'     => $plan['users'],
    ':pr'    => $plan['price'],
    ':code'  => $plan['plan_code'],
    ':title' => $plan['title'],
  ]);

  // گرفتن id
  $id = (int)$pdo->lastInsertId();
  if ($id > 0) return $id;

  // اگر آپدیت شده بود، دوباره id را از روی plan_code می‌گیریم
  $row = db_get_plan_by_code($plan['plan_code']);
  return $row ? (int)$row['id'] : 0;
}

/**
 * تغییر قیمت پلن (از bot.php)
 */
function db_update_plan_price(int $id, int $price): bool {
  global $pdo;
  $stmt = $pdo->prepare("UPDATE plans SET price = :p, updated_at = NOW() WHERE id = :id");
  return $stmt->execute([':p'=>$price, ':id'=>$id]);
}

/**
 * حذف پلن (فیزیکی) - در bot.php غیرفعال کردن است (از bot.php)
 */
function db_delete_plan(int $id): bool {
  global $pdo;
  // حذف نرم: فقط غیرفعال کردن پلن
  $stmt = $pdo->prepare("UPDATE plans SET is_active = 0 WHERE id = :id");
  return $stmt->execute([':id' => $id]);
}

/**
 * گرفتن کدهای پلن یک دسته برای استفاده در BUY / کانفیگ پلاس (از bot.php)
 */
function get_plan_codes_by_category(string $category): array {
  global $pdo;

  error_log("🔄 DEBUG get_plan_codes_by_category: category = {$category}");
  
  $stmt = $pdo->prepare("SELECT UPPER(TRIM(plan_code)) as plan_code FROM plans WHERE category = :c AND is_active = 1 ORDER BY price ASC, id ASC");
  $stmt->execute([':c' => $category]);
  $codes = $stmt->fetchAll(PDO::FETCH_COLUMN);
  
  error_log("🔍 DEBUG: Found codes: " . implode(', ', $codes));
  
  if ($codes) return $codes;

  // 🔧 fallback - باید با فرمت دیتابیس یکسان باشد
  error_log("⚠️ WARNING: Using fallback codes for category {$category} - no DB plans found!");
  switch ($category) {
    case 'VIP_1M': return ['VIP_1U_1M','VIP_2U_1M','VIP_3U_1M'];
    case 'VIP_3M': return ['VIP_1U_3M','VIP_2U_3M'];
    case 'VOL_1M': return ['VOL_10G_1M','VOL_20G_1M','VOL_30G_1M'];
    default: return [];
  }
}

/*──────────────────────── Broadcast System Helpers */

// تابع لاگ‌گیری پیشرفته (از bot.php)
function log_broadcast($admin_id, $message, $total_users, $success_count, $failed_count, $message_type = 'text') {
    global $pdo;
    
    $stmt = $pdo->prepare("
        INSERT INTO broadcast_logs 
        (admin_id, message, total_users, success_count, failed_count, message_type, created_at) 
        VALUES (:admin_id, :message, :total_users, :success_count, :failed_count, :message_type, NOW())
    ");
    
    $stmt->execute([
        ':admin_id' => $admin_id,
        ':message' => $message,
        ':total_users' => $total_users,
        ':success_count' => $success_count,
        ':failed_count' => $failed_count,
        ':message_type' => $message_type
    ]);
    
    return $pdo->lastInsertId();
}

// تابع ارسال تک پیام - نسخه اصلاح شده (از bot.php)
function send_single_broadcast($user_id, $message_data, $message_type) {
    try {
        $params = [
            'chat_id' => $user_id,
            'parse_mode' => 'HTML',
            'disable_web_page_preview' => true
        ];
        
        $method = '';
        if ($message_type === 'text') {
            $method = 'sendMessage';
            $params['text'] = $message_data;
        } elseif ($message_type === 'photo') {
            $method = 'sendPhoto';
            $params['photo'] = $message_data['photo_file_id'];
            if (!empty($message_data['caption'])) {
                $params['caption'] = $message_data['caption'];
                $params['parse_mode'] = 'HTML';
            }
        } elseif ($message_type === 'document') {
            $method = 'sendDocument';
            $params['document'] = $message_data['document_file_id'];
            if (!empty($message_data['caption'])) {
                $params['caption'] = $message_data['caption'];
                $params['parse_mode'] = 'HTML';
            }
        } else {
            throw new Exception("نوع پیام نامعتبر: {$message_type}");
        }
        
        $result = tg($method, $params);
        
        if ($result && isset($result['ok']) && $result['ok'] === true) {
            return ['success' => true, 'message_id' => $result['result']['message_id']];
        } else {
            $error = $result['description'] ?? 'خطای نامشخص از تلگرام';
            return ['success' => false, 'error' => $error];
        }
        
    } catch (Exception $e) {
        return ['success' => false, 'error' => $e->getMessage()];
    }
}

// تابع ثبت شروع ارسال (از bot.php)
function log_broadcast_start($admin_id, $message_data, $total_users, $message_type) {
    global $pdo;
    
    $message_content = '';
    if ($message_type === 'text') {
        $message_content = $message_data;
    } elseif (in_array($message_type, ['photo', 'document'])) {
        $message_content = $message_data['caption'] ?? '';
    }
    
    $stmt = $pdo->prepare("
        INSERT INTO broadcast_logs 
        (admin_id, message, total_users, success_count, failed_count, message_type, status, created_at) 
        VALUES (:admin_id, :message, :total_users, 0, 0, :message_type, 'PROCESSING', NOW())
    ");
    
    $stmt->execute([
        ':admin_id' => $admin_id,
        ':message' => $message_content,
        ':total_users' => $total_users,
        ':message_type' => $message_type
    ]);
    
    return $pdo->lastInsertId();
}

// تابع آپدیت پیشرفت (از bot.php)
function update_broadcast_progress($log_id, $success_count, $failed_count) {
    global $pdo;
    
    $stmt = $pdo->prepare("
        UPDATE broadcast_logs 
        SET success_count = :success, failed_count = :failed, updated_at = NOW() 
        WHERE id = :id
    ");
    
    $stmt->execute([
        ':success' => $success_count,
        ':failed' => $failed_count,
        ':id' => $log_id
    ]);
}

// تابع ثبت اتمام ارسال (از bot.php)
function update_broadcast_completion($log_id, $success_count, $failed_count, $failed_users = []) {
    global $pdo;
    
    $status = $failed_count > 0 ? 'COMPLETED_WITH_ERRORS' : 'COMPLETED';
    
    $stmt = $pdo->prepare("
        UPDATE broadcast_logs 
        SET success_count = :success, failed_count = :failed, status = :status, 
            failed_users = :failed_users, completed_at = NOW() 
        WHERE id = :id
    ");
    
    $stmt->execute([
        ':success' => $success_count,
        ':failed' => $failed_count,
        ':status' => $status,
        ':failed_users' => json_encode($failed_users, JSON_UNESCAPED_UNICODE),
        ':id' => $log_id
    ]);
    
    return $stmt->rowCount();
}

// تابع پیشرفته برای ارسال پیام عمومی (از bot.php)
function advanced_broadcast_message($admin_id, $message_data, $message_type) {
    global $pdo;
    
    try {
        // شروع تراکنش برای اطمینان از یکپارچگی داده‌ها
        $pdo->beginTransaction();
        
        // 1. دریافت لیست تمام کاربران
        $users_stmt = $pdo->prepare("SELECT id FROM users WHERE id != ? ORDER BY id ASC");
        $users_stmt->execute([$admin_id]);
        $users = $users_stmt->fetchAll(PDO::FETCH_COLUMN);
        
        $total_users = count($users);
        $success_count = 0;
        $failed_count = 0;
        $failed_users = [];
        
        // 2. ثبت لاگ اولیه
        $log_id = log_broadcast_start($admin_id, $message_data, $total_users, $message_type);
        
        // 3. ارسال پیام به کاربران
        foreach ($users as $index => $user_id) {
            try {
                $result = send_single_broadcast($user_id, $message_data, $message_type);
                
                if ($result['success']) {
                    $success_count++;
                    
                    // آپدیت لاگ هر 10 کاربر
                    if ($success_count % 10 === 0) {
                        update_broadcast_progress($log_id, $success_count, $failed_count);
                    }
                } else {
                    $failed_count++;
                    $failed_users[] = [
                        'user_id' => $user_id,
                        'error' => $result['error']
                    ];
                    
                    error_log("❌ Broadcast failed for user {$user_id}: " . $result['error']);
                }
                
                // تاخیر برای رعایت محدودیت‌های تلگرام
                usleep(100000); // 0.1 ثانیه
                
            } catch (Exception $e) {
                $failed_count++;
                $failed_users[] = [
                    'user_id' => $user_id,
                    'error' => $e->getMessage()
                ];
                error_log("❌ Broadcast exception for user {$user_id}: " . $e->getMessage());
            }
        }
        
        // 4. ثبت نتایج نهایی
        $final_log = update_broadcast_completion($log_id, $success_count, $failed_count, $failed_users);
        
        // کامیت تراکنش
        $pdo->commit();
        
        return [
            'success' => true,
            'log_id' => $log_id,
            'total_users' => $total_users,
            'success_count' => $success_count,
            'failed_count' => $failed_count,
            'failed_users' => $failed_users,
            'success_rate' => $total_users > 0 ? round(($success_count / $total_users) * 100, 2) : 0
        ];
        
    } catch (Exception $e) {
        $pdo->rollBack();
        error_log("❌ Broadcast system error: " . $e->getMessage());
        
        return [
            'success' => false,
            'error' => $e->getMessage()
        ];
    }
}

// تابع ایجاد گزارش پیشرفته (از bot.php)
function create_advanced_broadcast_report($broadcast_result, $admin_id) {
    global $pdo;

    $report = "📊 **گزارش پیشرفته ارسال پیام عمومی**\n\n";
    
    $report .= "👥 **آمار کلی:**\n";
    $report .= "• کاربران کل: {$broadcast_result['total_users']} نفر\n";
    $report .= "• ✅ ارسال موفق: {$broadcast_result['success_count']} نفر\n";
    $report .= "• ❌ ارسال ناموفق: {$broadcast_result['failed_count']} نفر\n";
    $report .= "• 📈 نرخ موفقیت: {$broadcast_result['success_rate']}%\n\n";
    
    if ($broadcast_result['failed_count'] > 0) {
        $report .= "⚠️ **کاربران با خطا:**\n";
        $sample_errors = array_slice($broadcast_result['failed_users'], 0, 5);
        foreach ($sample_errors as $failed) {
            $report .= "• کاربر {$failed['user_id']}: {$failed['error']}\n";
        }
        
        if (count($broadcast_result['failed_users']) > 5) {
            $report .= "• ... و " . (count($broadcast_result['failed_users']) - 5) . " کاربر دیگر\n";
        }
        $report .= "\n";
    }
    
    $report .= "🆔 **کد پیگیری:** #{$broadcast_result['log_id']}\n";
    $report .= "⏰ **زمان اتمام:** " . date('Y/m/d H:i:s') . "\n";
    
    // Get admin username/first_name
    $admin_info_stmt = $pdo->prepare("SELECT first_name, username FROM users WHERE id = :id");
    $admin_info_stmt->execute([':id' => $admin_id]);
    $admin_user = $admin_info_stmt->fetch(PDO::FETCH_ASSOC);
    $admin_name = ($admin_user['first_name'] ?? '') . ($admin_user['username'] ? ' (@' . $admin_user['username'] . ')' : '');
    if (empty($admin_name)) $admin_name = 'سیستم';

    $report .= "👤 **ارسال کننده:** " . $admin_name;
    
    return $report;
}

// تابع نمایش لاگ‌های قبلی (از bot.php)
function get_broadcast_logs($page = 1, $limit = 10) {
    global $pdo;
    
    $offset = ($page - 1) * $limit;
    
    $stmt = $pdo->prepare("
        SELECT bl.*, u.first_name, u.last_name 
        FROM broadcast_logs bl 
        LEFT JOIN users u ON bl.admin_id = u.id 
        ORDER BY bl.created_at DESC 
        LIMIT :limit OFFSET :offset
    ");
    
    $stmt->bindValue(':limit', $limit, PDO::PARAM_INT);
    $stmt->bindValue(':offset', $offset, PDO::PARAM_INT);
    $stmt->execute();
    
    return $stmt->fetchAll(PDO::FETCH_ASSOC);
}