<?php
/**
 * Orders Management
 * مدیریت سفارشات و پرداخت‌ها
 */

namespace GemAcc;

use PDO;

class Orders
{
    private PDO $pdo;
    private Credentials $credentials;
    
    public function __construct(PDO $pdo)
    {
        $this->pdo = $pdo;
        $this->credentials = new Credentials($pdo);
    }
    
    /**
     * ایجاد سفارش جدید
     */
    public function create(
        int $userId,
        string $duration,
        int $requestedSeats,
        int $price,
        string $paymentMethod = 'CARD',
        ?string $receiptFileId = null,
        ?string $receiptText = null
    ): int {
        $stmt = $this->pdo->prepare("
            INSERT INTO orders (user_id, duration, requested_seats, price, payment_method, status, receipt_file_id, receipt_text)
            VALUES (:user_id, :duration, :seats, :price, :method, 'PENDING', :receipt_file, :receipt_text)
        ");
        
        $stmt->execute([
            ':user_id'      => $userId,
            ':duration'     => $duration,
            ':seats'        => $requestedSeats,
            ':price'        => $price,
            ':method'       => $paymentMethod,
            ':receipt_file' => $receiptFileId,
            ':receipt_text' => $receiptText,
        ]);
        
        return (int)$this->pdo->lastInsertId();
    }
    
    /**
     * تایید سفارش و تخصیص صندلی
     * @return array ['success' => bool, 'credential' => array|null, 'message' => string]
     */
    public function approve(int $orderId): array
    {
        $order = $this->getById($orderId);
        if (!$order) return ['success' => false, 'credential' => null, 'message' => 'سفارش یافت نشد'];
        if ($order['status'] !== 'PENDING') return ['success' => false, 'credential' => null, 'message' => 'این سفارش قبلاً پردازش شده است'];
        $needed = max(1, (int)$order['requested_seats']);
        try {
            $credential = $this->credentials->allocateSeats((string)$order['duration'], $needed);
            if (!$credential) {
                $this->addToQueue($orderId, $order['user_id'], $order['duration'], $needed, (int)($order['plan_id'] ?? 0), (int)($order['category_id'] ?? 0), (string)($order['traffic_type'] ?? 'unlimited'), $order['traffic_limit_gb'] ?? null);
                $this->updateStatus($orderId, 'QUEUED');
                return ['success'=>false,'credential'=>null,'message'=>'موجودی کافی نیست. سفارش به صف انتظار اضافه شد.','queued'=>true];
            }
            $this->recordDelivery($orderId, $order['user_id'], (int)$credential['id'], $needed);
            $this->updateStatus($orderId, 'DELIVERED');
            $this->pdo->prepare("UPDATE orders SET approved_at = NOW(), delivered_at = NOW(), delivered_accounts=1, delivery_status='delivered' WHERE id = ?")->execute([$orderId]);
            return ['success'=>true,'credential'=>$credential,'credentials'=>[$credential],'message'=>'سفارش با موفقیت تحویل داده شد'];
        } catch (\Throwable $e) {
            error_log('approve error: '.$e->getMessage());
            return ['success'=>false,'credential'=>null,'message'=>'خطا در تحویل سفارش'];
        }
    }

    /**
     * رد سفارش
     */
    public function reject(int $orderId, ?string $reason = null): bool
    {
        $stmt = $this->pdo->prepare("
            UPDATE orders SET status = 'REJECTED', rejected_at = NOW() WHERE id = ? AND status = 'PENDING'
        ");
        return $stmt->execute([$orderId]) && $stmt->rowCount() > 0;
    }
    
    /**
     * لغو سفارش و استرداد به کیف پول
     * @return array ['success' => bool, 'refunded' => bool, 'message' => string]
     */
    public function cancel(int $orderId): array
    {
        $order = $this->getById($orderId);
        if (!$order) {
            return ['success' => false, 'refunded' => false, 'message' => 'سفارش یافت نشد'];
        }
        
        // فقط سفارشات PENDING و QUEUED قابل لغو هستند
        if (!in_array($order['status'], ['PENDING', 'QUEUED'])) {
            return ['success' => false, 'refunded' => false, 'message' => 'این سفارش قابل لغو نیست'];
        }
        
        $this->pdo->beginTransaction();
        
        try {
            // بروزرسانی وضعیت سفارش
            $stmt = $this->pdo->prepare("UPDATE orders SET status = 'CANCELLED' WHERE id = ?");
            $stmt->execute([$orderId]);
            
            // حذف از صف انتظار (اگر بود)
            $this->removeFromQueue($orderId);
            
            $refunded = false;
            
            // اگر پرداخت با کیف پول بود، استرداد کن
            if ($order['payment_method'] === 'WALLET') {
                // افزایش موجودی کاربر
                $stmt = $this->pdo->prepare("UPDATE users SET balance = balance + ? WHERE id = ?");
                $stmt->execute([$order['price'], $order['user_id']]);
                
                // ثبت تراکنش استرداد
                $stmt = $this->pdo->prepare("
                    INSERT INTO wallet_transactions (user_id, amount, type, status, description)
                    VALUES (?, ?, 'REFUND', 'COMPLETED', ?)
                ");
                $stmt->execute([$order['user_id'], $order['price'], "استرداد سفارش لغو شده #{$orderId}"]);
                
                $refunded = true;
            }
            
            $this->pdo->commit();
            
            return [
                'success'  => true,
                'refunded' => $refunded,
                'amount'   => $order['price'],
                'user_id'  => $order['user_id'],
                'message'  => $refunded ? 'سفارش لغو و مبلغ به کیف پول برگردانده شد' : 'سفارش لغو شد',
            ];
            
        } catch (\Exception $e) {
            $this->pdo->rollBack();
            error_log("Order cancel error: " . $e->getMessage());
            return ['success' => false, 'refunded' => false, 'message' => 'خطا در لغو سفارش'];
        }
    }
    
    /**
     * بروزرسانی وضعیت
     */
    public function updateStatus(int $orderId, string $status): bool
    {
        $stmt = $this->pdo->prepare("UPDATE orders SET status = ? WHERE id = ?");
        return $stmt->execute([$status, $orderId]);
    }
    
    /**
     * ثبت تحویل
     */
    public function recordDelivery(int $orderId, int $userId, int $credentialId, int $seatsAllocated): int
    {
        $st = $this->pdo->prepare("SELECT * FROM credentials WHERE id=? LIMIT 1");
        $st->execute([$credentialId]);
        $credMeta = $st->fetch(PDO::FETCH_ASSOC) ?: [];
        $raw = strtolower(trim((string)($credMeta['protocol'] ?? 'openvpn_l2tp')));
        $serviceType = in_array($raw, ['windscribe','expressvpn','v2ray'], true) ? $raw : 'openvpn_l2tp';
        $username = (string)($credMeta['username'] ?? $credMeta['email'] ?? '');
        $password = (string)($credMeta['password'] ?? '');
        $configText = (string)($credMeta['config_text'] ?? '');
        $qrFileId = (string)($credMeta['qr_code_file_id'] ?? '');
        $qrPath = (string)($credMeta['qr_code_path'] ?? '');
        $trafficType = (string)($credMeta['traffic_type'] ?? 'unlimited');
        $trafficLimitGb = $credMeta['traffic_limit_gb'] ?? null;

        $stmt = $this->pdo->prepare("INSERT INTO deliveries (order_id,user_id,credential_id,username,password,config_text,qr_code_file_id,qr_code_path,service_type,traffic_type,traffic_limit_gb,seats_allocated,status,delivered_at) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,'delivered',NOW())");
        $stmt->execute([$orderId,$userId,$credentialId,$username,$password,$configText ?: null,$qrFileId ?: null,$qrPath ?: null,$serviceType,$trafficType,$trafficType==='limited'?$trafficLimitGb:null,max(1,$seatsAllocated)]);
        $deliveryId = (int)$this->pdo->lastInsertId();

        try {
            $isShared = $serviceType === 'windscribe';
            if ($isShared) {
                $max = max(1, (int)($credMeta['max_seats'] ?? 15));
                $used = max(0, (int)($credMeta['used_seats'] ?? 0));
                $isFull = $used >= $max ? 1 : 0;
                $this->pdo->prepare("UPDATE credentials SET sold_to_user_id=COALESCE(sold_to_user_id,?),order_id=COALESCE(order_id,?),is_sold=?,status=?,sold_at=COALESCE(sold_at,NOW()),delivered_at=NOW(),updated_at=NOW() WHERE id=?")
                    ->execute([$userId,$orderId,$isFull,$isFull?'sold':'partial',$credentialId]);
            } else {
                $this->pdo->prepare("UPDATE credentials SET assigned_user_id=?,assigned_order_id=?,sold_to_user_id=?,order_id=?,max_seats=1,used_seats=1,is_sold=1,status='sold',sold_at=COALESCE(sold_at,NOW()),delivered_at=NOW(),updated_at=NOW() WHERE id=?")
                    ->execute([$userId,$orderId,$userId,$orderId,$credentialId]);
            }
        } catch (\Throwable $e) { error_log('recordDelivery credential update: '.$e->getMessage()); }

        $this->pdo->prepare("UPDATE users SET total_purchases=total_purchases+1 WHERE id=?")->execute([$userId]);
        return $deliveryId;
    }

    /**
     * اضافه به صف انتظار
     */
    public function addToQueue(int $orderId, int $userId, string $duration, int $requestedSeats, int $planId = 0, int $categoryId = 0, string $trafficType = 'unlimited', $trafficLimitGb = null): int
    {
        $stmt = $this->pdo->prepare("
            INSERT INTO waiting_queue (order_id, user_id, plan_id, category_id, duration, requested_seats, traffic_type, traffic_limit_gb)
            VALUES (?, ?, ?, ?, ?, ?, ?, ?)
        ");
        $stmt->execute([$orderId, $userId, $planId ?: null, $categoryId ?: null, $duration, $requestedSeats, $trafficType, $trafficLimitGb]);
        
        return (int)$this->pdo->lastInsertId();
    }
    
    /**
     * حذف از صف انتظار
     */
    public function removeFromQueue(int $orderId): bool
    {
        $stmt = $this->pdo->prepare("DELETE FROM waiting_queue WHERE order_id = ?");
        return $stmt->execute([$orderId]);
    }
    
    /**
     * پردازش صف انتظار
     * @return array ['processed' => int, 'still_waiting' => int]
     */
    public function processQueue(): array
    {
        $processed = 0;
        $stillWaiting = 0;
        
        $stmt = $this->pdo->query("
            SELECT wq.*, o.price FROM waiting_queue wq
            JOIN orders o ON wq.order_id = o.id
            ORDER BY wq.created_at ASC
        ");
        
        $queueItems = $stmt->fetchAll(PDO::FETCH_ASSOC);
        
        foreach ($queueItems as $item) {
            $credential = $this->credentials->allocateSeats($item['duration'], $item['requested_seats']);
            
            if ($credential) {
                // تحویل دادن
                $this->recordDelivery($item['order_id'], $item['user_id'], $credential['id'], $item['requested_seats']);
                $this->updateStatus($item['order_id'], 'DELIVERED');
                $this->removeFromQueue($item['order_id']);
                
                $processed++;
            } else {
                $stillWaiting++;
            }
        }
        
        return ['processed' => $processed, 'still_waiting' => $stillWaiting];
    }
    
    /**
     * گرفتن سفارش با آیدی
     */
    public function getById(int $orderId): ?array
    {
        $stmt = $this->pdo->prepare("
            SELECT o.*, u.first_name, u.username
            FROM orders o
            LEFT JOIN users u ON o.user_id = u.id
            WHERE o.id = ?
        ");
        $stmt->execute([$orderId]);
        return $stmt->fetch(PDO::FETCH_ASSOC) ?: null;
    }
    
    /**
     * گرفتن سفارشات کاربر
     */
    public function getUserOrders(int $userId, int $limit = 10, int $page = 1): array
    {
        $offset = ($page - 1) * $limit;
        
        $stmt = $this->pdo->prepare("
            SELECT * FROM orders WHERE user_id = ? ORDER BY created_at DESC LIMIT ? OFFSET ?
        ");
        $stmt->bindValue(1, $userId, PDO::PARAM_INT);
        $stmt->bindValue(2, $limit, PDO::PARAM_INT);
        $stmt->bindValue(3, $offset, PDO::PARAM_INT);
        $stmt->execute();
        
        return $stmt->fetchAll(PDO::FETCH_ASSOC);
    }
    
    /**
     * گرفتن تعداد سفارشات کاربر
     */
    public function getUserOrdersCount(int $userId): int
    {
        $stmt = $this->pdo->prepare("SELECT COUNT(*) FROM orders WHERE user_id = ?");
        $stmt->execute([$userId]);
        return (int)$stmt->fetchColumn();
    }
    
    /**
     * گرفتن سفارشات در انتظار (برای ادمین)
     */
    public function getPendingOrders(int $limit = 50): array
    {
        try { if (function_exists('gemaccStarsAutoCancelExpired')) gemaccStarsAutoCancelExpired($this->pdo, 25); } catch (\Throwable $e) { error_log('[stars_auto_cancel_orders_model] '.$e->getMessage()); }
        $stmt = $this->pdo->prepare("
            SELECT o.*, u.first_name, u.username
            FROM orders o
            LEFT JOIN users u ON o.user_id = u.id
            WHERE o.status IN ('PENDING','QUEUED')
              AND NOT (
                  UPPER(COALESCE(o.payment_method,''))='STARS'
                  AND LOWER(COALESCE(o.payment_status,''))<>'paid'
              )
              AND NOT EXISTS (
                  SELECT 1 FROM crypto_payments cp
                  WHERE cp.order_id=o.id
                    AND cp.provider='Plisio'
                    AND cp.payment_type='order'
                    AND cp.status NOT IN ('PAID','FAILED','REJECTED','CANCELLED')
              )
            ORDER BY o.created_at ASC
            LIMIT ?
        ");
        $stmt->bindValue(1, $limit, PDO::PARAM_INT);
        $stmt->execute();
        
        return $stmt->fetchAll(PDO::FETCH_ASSOC);
    }
    
    /**
     * گرفتن تحویل‌های کاربر (سرویس‌های من)
     */
    public function getUserDeliveries(int $userId, int $limit = 10, int $page = 1): array
    {
        $offset = ($page - 1) * $limit;
        
        $stmt = $this->pdo->prepare("
            SELECT d.*, c.email, c.password, c.duration, o.price, o.created_at as order_date
            FROM deliveries d
            JOIN credentials c ON d.credential_id = c.id
            JOIN orders o ON d.order_id = o.id
            WHERE d.user_id = ?
            ORDER BY d.delivered_at DESC
            LIMIT ? OFFSET ?
        ");
        $stmt->bindValue(1, $userId, PDO::PARAM_INT);
        $stmt->bindValue(2, $limit, PDO::PARAM_INT);
        $stmt->bindValue(3, $offset, PDO::PARAM_INT);
        $stmt->execute();
        
        return $stmt->fetchAll(PDO::FETCH_ASSOC);
    }
    
    /**
     * گرفتن تعداد تحویل‌های کاربر
     */
    public function getUserDeliveriesCount(int $userId): int
    {
        $stmt = $this->pdo->prepare("SELECT COUNT(*) FROM deliveries WHERE user_id = ?");
        $stmt->execute([$userId]);
        return (int)$stmt->fetchColumn();
    }
    
    /**
     * آمار فروش
     */
    public function getSalesStats(): array
    {
        $stmt = $this->pdo->query("
            SELECT 
                COUNT(*) as total_orders,
                SUM(CASE WHEN status = 'DELIVERED' THEN 1 ELSE 0 END) as delivered_count,
                SUM(CASE WHEN status = 'PENDING' THEN 1 ELSE 0 END) as pending_count,
                SUM(CASE WHEN status = 'DELIVERED' THEN price ELSE 0 END) as total_revenue,
                SUM(CASE WHEN status = 'DELIVERED' AND DATE(delivered_at) = CURDATE() THEN 1 ELSE 0 END) as today_count,
                SUM(CASE WHEN status = 'DELIVERED' AND DATE(delivered_at) = CURDATE() THEN price ELSE 0 END) as today_revenue
            FROM orders
        ");
        
        return $stmt->fetch(PDO::FETCH_ASSOC) ?: [];
    }
    
    /**
     * گرفتن صف انتظار
     */
    public function getWaitingQueue(): array
    {
        $stmt = $this->pdo->query("
            SELECT wq.*, o.price, u.first_name, u.username
            FROM waiting_queue wq
            JOIN orders o ON wq.order_id = o.id
            JOIN users u ON wq.user_id = u.id
            ORDER BY wq.created_at ASC
        ");
        
        return $stmt->fetchAll(PDO::FETCH_ASSOC);
    }
}

