<?php
/**
 * Plans Management - OpenVPN | L2TP
 * مدیریت پلن‌ها با دسته‌بندی پویا از دیتابیس
 */

namespace GemAcc;

use PDO;

class Plans
{
    private PDO $pdo;

    public function __construct(PDO $pdo)
    {
        $this->pdo = $pdo;
    }

    public function getActiveCategories(): array
    {
        $stmt = $this->pdo->query("\n            SELECT * FROM plan_categories\n            WHERE is_active = 1 AND deleted_at IS NULL\n            ORDER BY months ASC, traffic_type DESC, traffic_limit_gb ASC, display_order ASC, sort_order ASC, id ASC\n        ");
        return $stmt->fetchAll(PDO::FETCH_ASSOC);
    }

    /** گرفتن همه پلن‌های فعال همراه دسته فعال */
    public function getActive(): array
    {
        $stmt = $this->pdo->query("\n            SELECT p.*, pc.service_type AS category_service_type, pc.service_name AS category_service_name, pc.name AS category_name, pc.code AS category_code, pc.months AS category_months, pc.traffic_type AS category_traffic_type, pc.traffic_limit_gb AS category_traffic_limit_gb\n            FROM plans p\n            INNER JOIN plan_categories pc ON pc.id = p.category_id\n            WHERE p.is_active = 1\n              AND p.deleted_at IS NULL\n              AND pc.is_active = 1\n              AND pc.deleted_at IS NULL\n            ORDER BY pc.months ASC, pc.traffic_type DESC, pc.traffic_limit_gb ASC, p.display_order ASC, p.sort_order ASC, p.id ASC\n        ");
        return $stmt->fetchAll(PDO::FETCH_ASSOC);
    }

    /** گرفتن همه پلن‌ها برای ادمین */
    public function getAll(): array
    {
        $stmt = $this->pdo->query("\n            SELECT p.*, pc.service_type AS category_service_type, pc.service_name AS category_service_name, pc.name AS category_name, pc.code AS category_code, pc.months AS category_months, pc.traffic_type AS category_traffic_type, pc.traffic_limit_gb AS category_traffic_limit_gb\n            FROM plans p\n            LEFT JOIN plan_categories pc ON pc.id = p.category_id\n            ORDER BY COALESCE(pc.months, p.months), COALESCE(pc.traffic_type,p.traffic_type) DESC, COALESCE(pc.traffic_limit_gb,p.traffic_limit_gb), p.display_order, p.id\n        ");
        return $stmt->fetchAll(PDO::FETCH_ASSOC);
    }

    /** گرفتن پلن‌های فعال یک دسته با code */
    public function getByDuration(string $duration): array
    {
        $stmt = $this->pdo->prepare("\n            SELECT p.*, pc.service_type AS category_service_type, pc.service_name AS category_service_name, pc.name AS category_name, pc.code AS category_code, pc.months AS category_months, pc.traffic_type AS category_traffic_type, pc.traffic_limit_gb AS category_traffic_limit_gb\n            FROM plans p\n            INNER JOIN plan_categories pc ON pc.id = p.category_id\n            WHERE pc.code = ?\n              AND p.is_active = 1\n              AND p.deleted_at IS NULL\n              AND pc.is_active = 1\n              AND pc.deleted_at IS NULL\n            ORDER BY p.display_order ASC, p.sort_order ASC, COALESCE(p.traffic_limit_gb,0), p.user_count ASC, p.seats ASC, p.id ASC\n        ");
        $stmt->execute([$duration]);
        return $stmt->fetchAll(PDO::FETCH_ASSOC);
    }

    public function getCategoryByCode(string $code): ?array
    {
        $stmt = $this->pdo->prepare("SELECT * FROM plan_categories WHERE code = ? AND is_active = 1 AND deleted_at IS NULL LIMIT 1");
        $stmt->execute([$code]);
        return $stmt->fetch(PDO::FETCH_ASSOC) ?: null;
    }

    /** گرفتن پلن با آیدی */
    public function getById(int $id): ?array
    {
        $stmt = $this->pdo->prepare("\n            SELECT p.*, pc.service_type AS category_service_type, pc.service_name AS category_service_name, pc.name AS category_name, pc.code AS category_code, pc.months AS category_months, pc.traffic_type AS category_traffic_type, pc.traffic_limit_gb AS category_traffic_limit_gb\n            FROM plans p\n            LEFT JOIN plan_categories pc ON pc.id = p.category_id\n            WHERE p.id = ?\n            LIMIT 1\n        ");
        $stmt->execute([$id]);
        return $stmt->fetch(PDO::FETCH_ASSOC) ?: null;
    }

    public function getByDurationAndSeats(string $duration, int $seats): ?array
    {
        $stmt = $this->pdo->prepare("\n            SELECT p.* FROM plans p\n            INNER JOIN plan_categories pc ON pc.id = p.category_id\n            WHERE pc.code = ? AND (p.seats = ? OR p.user_count = ?)\n            LIMIT 1\n        ");
        $stmt->execute([$duration, $seats, $seats]);
        return $stmt->fetch(PDO::FETCH_ASSOC) ?: null;
    }

    public function upsert(string $duration, int $seats, int $price, string $title): int
    {
        $cat = $this->getCategoryByCode($duration);
        if (!$cat) {
            return 0;
        }
        $code = $duration . '_' . $seats . '_' . time();
        $stmt = $this->pdo->prepare("\n            INSERT INTO plans (category_id, code, title, duration, months, seats, user_count, price, is_active)\n            VALUES (:category_id, :code, :title, :duration, :months, :seats, :user_count, :price, 1)\n        ");
        $stmt->execute([
            ':category_id' => (int)$cat['id'],
            ':code' => $code,
            ':title' => $title,
            ':duration' => $duration,
            ':months' => (int)$cat['months'],
            ':seats' => $seats,
            ':user_count' => $seats,
            ':price' => $price,
        ]);
        return (int)$this->pdo->lastInsertId();
    }

    public function updatePrice(int $id, int $price): bool
    {
        $stmt = $this->pdo->prepare("UPDATE plans SET price = ?, updated_at = NOW() WHERE id = ?");
        return $stmt->execute([$price, $id]);
    }

    public function toggle(int $id, bool $active): bool
    {
        $stmt = $this->pdo->prepare("UPDATE plans SET is_active = ?, updated_at = NOW() WHERE id = ?");
        return $stmt->execute([$active ? 1 : 0, $id]);
    }


    public static function normalizeServiceType(string $raw, string $hint = ''): string
    {
        $s = function_exists('mb_strtolower') ? mb_strtolower(trim($raw), 'UTF-8') : strtolower(trim($raw));
        $h = function_exists('mb_strtolower') ? mb_strtolower(trim($hint), 'UTF-8') : strtolower(trim($hint));
        if (in_array($s, ['windscribe','ws','ویندسکرایب'], true) || str_contains($h, 'windscribe') || str_contains($h, 'ویندسکرایب')) return 'windscribe';
        if (in_array($s, ['expressvpn','express','اکسپرس','express vpn'], true) || str_contains($h, 'express') || str_contains($h, 'اکسپرس')) return 'expressvpn';
        if (in_array($s, ['v2ray','v2','vmess','vless','trojan','ویتوری','وی تو ری','وی‌تو‌ری'], true) || str_contains($h, 'v2ray') || str_contains($h, 'vmess') || str_contains($h, 'vless') || str_contains($h, 'trojan') || str_contains($h, 'ویتوری') || str_contains($h, 'وی تو ری') || str_contains($h, 'وی‌تو‌ری')) return 'v2ray';
        return 'openvpn_l2tp';
    }

    public static function serviceLabel(array $row): string
    {
        $custom = trim((string)($row['service_name'] ?? $row['category_service_name'] ?? ''));
        $type = self::normalizeServiceType((string)($row['service_type'] ?? $row['protocol'] ?? $row['category_service_type'] ?? 'openvpn_l2tp'), $custom . ' ' . (string)($row['name'] ?? $row['category_name'] ?? $row['title'] ?? ''));
        if ($custom !== '') return $custom;
        return $type === 'windscribe' ? 'Windscribe' : ($type === 'expressvpn' ? 'ExpressVPN' : ($type === 'v2ray' ? 'V2Ray' : 'OpenVPN | L2TP'));
    }

    public function getActiveServiceGroups(): array
    {
        $groups = [];
        foreach ($this->getActiveCategories() as $cat) {
            $type = self::normalizeServiceType((string)($cat['service_type'] ?? ''), (string)($cat['service_name'] ?? '').' '.(string)($cat['name'] ?? ''));
            if (!isset($groups[$type])) $groups[$type] = ['type'=>$type, 'label'=>self::serviceLabel($cat), 'count'=>0];
            $groups[$type]['count']++;
        }
        $order = ['openvpn_l2tp'=>1,'windscribe'=>2,'v2ray'=>3,'expressvpn'=>4];
        uasort($groups, fn($a,$b)=>(($order[$a['type']]??99)<=>($order[$b['type']]??99)));
        return array_values($groups);
    }

    public function buildServiceKeyboard(): array
    {
        $icons = ['openvpn_l2tp'=>'🧊','windscribe'=>'🟦','v2ray'=>'⚡','expressvpn'=>'🚀'];
        $buttons = [];
        foreach ($this->getActiveServiceGroups() as $g) {
            $buttons[] = [[
                'text'=>($icons[$g['type']] ?? '🛡️').' '.$g['label'],
                'callback_data'=>'BUY_SERVICE_'.$g['type'],
            ]];
        }
        if (!$buttons) $buttons[] = [['text'=>'❌ فعلاً سرویسی برای فروش ثبت نشده','callback_data'=>'NO_PLANS']];
        $buttons[] = [['text'=>'◀️ بازگشت به منو','callback_data'=>'BACK_MAIN']];
        return ['inline_keyboard'=>$buttons];
    }

    public function buildCategoryKeyboardForService(string $serviceType): array
    {
        $serviceType = self::normalizeServiceType($serviceType);
        $buttons = [];
        foreach ($this->getActiveCategories() as $cat) {
            $catType = self::normalizeServiceType((string)($cat['service_type'] ?? ''), (string)($cat['service_name'] ?? '').' '.(string)($cat['name'] ?? ''));
            if ($catType !== $serviceType) continue;
            $traffic = (($cat['traffic_type'] ?? 'unlimited') === 'limited') ? ('حجمی '.(int)($cat['traffic_limit_gb'] ?? 0).' گیگ') : 'نامحدود';
            $buttons[] = [['text'=>'📅 '.(string)$cat['name'].' | '.$traffic, 'callback_data'=>'BUY_DURATION_'.(string)$cat['code']]];
        }
        if (!$buttons) $buttons[] = [['text'=>'❌ پلنی برای این سرویس فعال نیست','callback_data'=>'BUY']];
        $buttons[] = [['text'=>'◀️ انتخاب سرویس','callback_data'=>'BUY'], ['text'=>'🏠 منوی اصلی','callback_data'=>'BACK_MAIN']];
        return ['inline_keyboard'=>$buttons];
    }

    /** ساخت کیبورد انتخاب دسته پلن از دیتابیس */
    public function buildDurationKeyboard(): array
    {
        $cats = $this->getActiveCategories();
        $buttons = [];
        foreach ($cats as $cat) {
            $svc = self::serviceLabel($cat);
            $traffic = (($cat['traffic_type'] ?? 'unlimited') === 'limited') ? ('حجمی ' . (int)($cat['traffic_limit_gb'] ?? 0) . ' گیگ') : 'نامحدود';
            $label = '📅 ' . $cat['name'] . ' - ' . $svc . ' - ' . $traffic;
            $buttons[] = [[
                'text' => $label,
                'callback_data' => 'BUY_DURATION_' . $cat['code'],
            ]];
        }
        if (!$buttons) {
            $buttons[] = [[
                'text' => '❌ فعلاً پلنی برای فروش ثبت نشده',
                'callback_data' => 'NO_PLANS',
            ]];
        }
        $buttons[] = [['text' => '◀️ بازگشت به منو', 'callback_data' => 'BACK_MAIN']];
        return ['inline_keyboard' => $buttons];
    }

    /** ساخت کیبورد انتخاب پلن‌های زیرمجموعه دسته */
    public function buildSeatsKeyboard(string $duration): array
    {
        $plans = $this->getByDuration($duration);
        $buttons = [];
        foreach ($plans as $plan) {
            $count = (int)($plan['user_count'] ?: $plan['seats'] ?: 1);
            $svcType = self::normalizeServiceType((string)($plan['service_type'] ?? $plan['protocol'] ?? $plan['category_service_type'] ?? ''), (string)($plan['title'] ?? ''));
            $svc = self::serviceLabel($plan);
            $traffic = (($plan['traffic_type'] ?? $plan['category_traffic_type'] ?? 'unlimited') === 'limited') ? ('حجمی ' . (int)($plan['traffic_limit_gb'] ?? $plan['category_traffic_limit_gb'] ?? 0) . ' گیگ') : 'نامحدود';
            $capacityLabel = $svcType === 'v2ray' ? '⚡ یک کانفیگ' : $this->getSeatsLabel($count);
            $label = $capacityLabel . ' | ' . $svc . ' | ' . $traffic . ' | ' . number_format((int)$plan['price']) . ' تومان';
            $buttons[] = [['text' => $label, 'callback_data' => "BUY_PLAN_{$plan['id']}"]];
        }
        if (!$buttons) {
            $buttons[] = [['text' => '❌ پلنی در این دسته وجود ندارد', 'callback_data' => 'BUY']];
        }
        $buttons[] = [
            ['text' => '◀️ تغییر دسته', 'callback_data' => 'BUY'],
            ['text' => '🏠 منوی اصلی', 'callback_data' => 'BACK_MAIN'],
        ];
        return ['inline_keyboard' => $buttons];
    }

    public function getSeatsLabel(int $seats): string
    {
        switch ($seats) {
            case 1:  return '👤 ۱ کاربره';
            case 2:  return '👥 ۲ کاربره';
            case 3:  return '👥 ۳ کاربره';
            case 5:  return '👨‍👩‍👧‍👦 ۵ کاربره';
            case 15: return '🏢 ۱۵ کاربره';
            default: return "👥 {$seats} کاربره";
        }
    }

    public static function getDurationLabel(string $duration): string
    {
        if (preg_match('/^(\\d+)M$/', $duration, $m)) {
            $n = (int)$m[1];
            return $n === 12 ? 'یک‌ساله' : $n . ' ماهه';
        }
        return $duration;
    }

    public static function getDurationEmoji(string $duration): string
    {
        return '📅';
    }
}
