<?php
/**
 * Order Class
 * Handles order operations
 */

require_once __DIR__ . '/Database.php';
require_once __DIR__ . '/Cart.php';
require_once __DIR__ . '/Product.php';
require_once __DIR__ . '/User.php';
require_once __DIR__ . '/B2B.php';
require_once __DIR__ . '/Loyalty.php';

class Order {
    private $db;
    private $cart;
    private $product;
    private $user;
    private $b2b;
    private $loyalty;

    public function __construct() {
        $this->db = Database::getInstance();
        $this->cart = new Cart();
        $this->product = new Product();
        $this->user = new User();
        $this->b2b = new B2B();
        $this->loyalty = new Loyalty();
    }

    /**
     * Generate unique order number
     */
    private function generateOrderNumber() {
        do {
            $orderNumber = 'ORD-' . date('Ymd') . '-' . strtoupper(substr(uniqid(), -6));
            $exists = $this->db->fetchOne(
                "SELECT id FROM orders WHERE order_number = ?",
                [$orderNumber]
            );
        } while ($exists);

        return $orderNumber;
    }

    /**
     * Create order from cart
     */
    public function createOrder($cartId, $userId, $data) {
        $cart = $this->db->fetchOne("SELECT * FROM cart WHERE id = ?", [$cartId]);
        if (!$cart) {
            return ['success' => false, 'message' => 'Cart not found'];
        }

        $cartItems = $this->cart->getCartItems($cartId);
        if (empty($cartItems)) {
            return ['success' => false, 'message' => 'Cart is empty'];
        }

        // Calculate totals using B2B class (handles product-specific prices and group discounts)
        $subtotal = 0;
        foreach ($cartItems as $item) {
            $product = $this->product->getProductById($item['product_id']);
            if ($product) {
                // Use B2B class to calculate final price
                $price = $this->b2b->calculateProductPrice($product, $userId);
            } else {
                $price = $item['price_at_add'];
            }
            $subtotal += $price * $item['quantity'];
        }

        $discount = 0;
        $loyaltyPointsUsed = 0;

        // Apply coupon if provided
        if (!empty($data['coupon_code'])) {
            $coupon = $this->validateCoupon($data['coupon_code'], $subtotal);
            if ($coupon) {
                $discountType = $coupon['discount_type'] ?? $coupon['type'] ?? 'fixed';
                $discountValue = $coupon['discount_value'] ?? $coupon['value'] ?? 0;
                
                if ($discountType === 'percentage') {
                    $discount = ($subtotal * $discountValue) / 100;
                    if ($coupon['max_discount']) {
                        $discount = min($discount, $coupon['max_discount']);
                    }
                } elseif ($discountType === 'free_shipping') {
                    // Free shipping is handled separately
                    $discount = 0;
                } else {
                    $discount = $discountValue;
                }
            }
        }

        // Apply loyalty points if provided
        if (!empty($data['loyalty_points']) && $userId) {
            $userPoints = $this->loyalty->getUserPoints($userId);
            $pointsToUse = min($data['loyalty_points'], $userPoints);
            if ($pointsToUse > 0) {
                $loyaltyDiscount = $this->loyalty->pointsToDiscount($pointsToUse);
                $discount += $loyaltyDiscount;
                $loyaltyPointsUsed = $pointsToUse;
            }
        }

        $shippingCost = $data['shipping_cost'] ?? 0;
        $total = $subtotal - $discount + $shippingCost;

        $this->db->beginTransaction();

        try {
            // Create order
            $orderNumber = $this->generateOrderNumber();
            $this->db->execute(
                "INSERT INTO orders (order_number, user_id, order_type, billing_address_id, shipping_address_id,
                 subtotal, discount, shipping_cost, total, payment_method, coupon_code, loyalty_points_used, notes)
                 VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
                [
                    $orderNumber,
                    $userId,
                    $data['order_type'] ?? 'physical',
                    $data['billing_address_id'] ?? null,
                    $data['shipping_address_id'] ?? null,
                    $subtotal,
                    $discount,
                    $shippingCost,
                    $total,
                    $data['payment_method'] ?? 'cash_on_delivery',
                    $data['coupon_code'] ?? null,
                    $loyaltyPointsUsed,
                    $data['notes'] ?? null
                ]
            );

            $orderId = $this->db->lastInsertId();

            // Add order items
            foreach ($cartItems as $item) {
                $product = $this->product->getProductById($item['product_id']);
                if ($product) {
                    // Use B2B class to calculate final price
                    $price = $this->b2b->calculateProductPrice($product, $userId);
                } else {
                    $price = $item['price_at_add'];
                }

                $this->db->execute(
                    "INSERT INTO order_items (order_id, product_id, product_name, quantity, price, subtotal, is_gift)
                     VALUES (?, ?, ?, ?, ?, ?, ?)",
                    [
                        $orderId,
                        $item['product_id'],
                        $item['name'],
                        $item['quantity'],
                        $price,
                        $price * $item['quantity'],
                        $item['is_gift'] ?? 0
                    ]
                );

                // Update stock
                $this->product->updateStock($item['product_id'], $item['quantity']);
            }

            // Use loyalty points if applicable
            if ($loyaltyPointsUsed > 0 && $userId) {
                $this->loyalty->usePoints($userId, $loyaltyPointsUsed, $orderId, 'Points used for order');
            }

            // Add loyalty points for purchase
            if ($userId) {
                $pointsEarned = $this->loyalty->calculatePointsFromOrder($total);
                if ($pointsEarned > 0) {
                    $this->loyalty->addPoints($userId, $pointsEarned, $orderId, 'Points earned from order');
                }
            }

            // Update coupon usage
            if (!empty($data['coupon_code'])) {
                $this->db->execute(
                    "UPDATE coupons SET used_count = used_count + 1 WHERE code = ?",
                    [$data['coupon_code']]
                );
            }

            // Clear cart
            $this->cart->clearCart($cartId);

            $this->db->commit();

            return ['success' => true, 'order_id' => $orderId, 'order_number' => $orderNumber];
        } catch (Exception $e) {
            $this->db->rollback();
            return ['success' => false, 'message' => 'Order creation failed: ' . $e->getMessage()];
        }
    }

    /**
     * Get order by ID
     */
    public function getOrderById($orderId) {
        return $this->db->fetchOne(
            "SELECT o.*, u.first_name, u.last_name, u.email, u.phone
             FROM orders o
             LEFT JOIN users u ON o.user_id = u.id
             WHERE o.id = ?",
            [$orderId]
        );
    }

    /**
     * Get order by order number
     */
    public function getOrderByNumber($orderNumber) {
        return $this->db->fetchOne(
            "SELECT o.*, u.first_name, u.last_name, u.email, u.phone
             FROM orders o
             LEFT JOIN users u ON o.user_id = u.id
             WHERE o.order_number = ?",
            [$orderNumber]
        );
    }

    /**
     * Get order items
     */
    public function getOrderItems($orderId) {
        return $this->db->fetchAll(
            "SELECT oi.*, p.slug, p.image
             FROM order_items oi
             LEFT JOIN products p ON oi.product_id = p.id
             WHERE oi.order_id = ?
             ORDER BY oi.id",
            [$orderId]
        );
    }

    /**
     * Get user orders
     */
    public function getUserOrders($userId, $page = 1, $perPage = 20) {
        $offset = ($page - 1) * $perPage;
        return $this->db->fetchAll(
            "SELECT * FROM orders WHERE user_id = ? ORDER BY created_at DESC LIMIT ? OFFSET ?",
            [$userId, $perPage, $offset]
        );
    }

    /**
     * Get user orders count
     */
    public function getUserOrdersCount($userId) {
        $result = $this->db->fetchOne(
            "SELECT COUNT(*) as count FROM orders WHERE user_id = ?",
            [$userId]
        );
        return $result['count'] ?? 0;
    }

    /**
     * Update order status
     */
    public function updateOrderStatus($orderId, $status) {
        return $this->db->execute(
            "UPDATE orders SET order_status = ?, updated_at = NOW() WHERE id = ?",
            [$status, $orderId]
        );
    }

    /**
     * Validate coupon
     */
    public function validateCoupon($code, $subtotal) {
        $coupon = $this->db->fetchOne(
            "SELECT *, discount_type as type, discount_value as value, min_order_value as min_purchase 
             FROM coupons WHERE code = ? AND is_active = 1",
            [$code]
        );

        if (!$coupon) {
            return false;
        }

        // Add backward compatibility aliases
        if (!isset($coupon['type'])) {
            $coupon['type'] = $coupon['discount_type'] ?? 'fixed';
        }
        if (!isset($coupon['value'])) {
            $coupon['value'] = $coupon['discount_value'] ?? 0;
        }
        if (!isset($coupon['min_purchase'])) {
            $coupon['min_purchase'] = $coupon['min_order_value'] ?? 0;
        }

        // Check validity dates
        $now = date('Y-m-d H:i:s');
        if ($coupon['valid_from'] && $coupon['valid_from'] > $now) {
            return false;
        }
        if ($coupon['valid_until'] && $coupon['valid_until'] < $now) {
            return false;
        }

        // Check usage limit
        if ($coupon['usage_limit'] && $coupon['used_count'] >= $coupon['usage_limit']) {
            return false;
        }

        // Check minimum purchase
        $minPurchase = $coupon['min_order_value'] ?? $coupon['min_purchase'] ?? 0;
        if ($minPurchase && $subtotal < $minPurchase) {
            return false;
        }

        return $coupon;
    }
}
?>

