<?php
namespace App\Core;

use RuntimeException;

class OrderService {
    public static function create(array $customer, array $cart, array $payload): int {
        if (empty($cart['items'])) throw new RuntimeException('Your cart is empty.');
        $name = trim((string)($customer['name'] ?? $payload['customer_name'] ?? ''));
        $phone = trim((string)($customer['phone'] ?? $payload['customer_phone'] ?? ''));
        $email = trim((string)($customer['email'] ?? $payload['customer_email'] ?? ''));
        $address = trim((string)($payload['delivery_address'] ?? ''));
        if ($name === '' || $phone === '' || $address === '') throw new RuntimeException('Name, phone and delivery address are required.');
        if ($email !== '' && !filter_var($email, FILTER_VALIDATE_EMAIL)) throw new RuntimeException('Invalid email address.');

        $paymentMethod = (string)($payload['payment_method'] ?? 'cod');
        if (!array_key_exists($paymentMethod, PaymentGateway::methods())) $paymentMethod = 'cod';
        $districtId = !empty($payload['district_id']) ? (int)$payload['district_id'] : null;
        $areaId = !empty($payload['area_id']) ? (int)$payload['area_id'] : null;
        $couponCode = strtoupper(trim((string)($payload['coupon_code'] ?? '')));
        $referralCode = trim((string)($_SESSION['affiliate_referral_code'] ?? $payload['referral_code'] ?? ''));
        $affiliate = $referralCode !== '' ? Database::safeFetchOne('SELECT id FROM affiliate_members WHERE referral_code=? AND status="active" LIMIT 1', [$referralCode]) : null;
        $affiliateMemberId = (int)($affiliate['id'] ?? 0) ?: null;

        return (int)Database::transaction(function() use ($customer, $cart, $payload, $name, $phone, $email, $address, $paymentMethod, $districtId, $areaId, $couponCode, $affiliateMemberId) {
            $validatedItems = [];
            $subtotal = 0.0;
            $vendorSubtotals = [];
            foreach ($cart['items'] as $item) {
                $productId = (int)($item['product']['id'] ?? 0);
                $variantId = !empty($item['variant_id']) ? (int)$item['variant_id'] : null;
                $qty = max(1, (int)($item['qty'] ?? 1));
                $product = Database::fetchOne('SELECT * FROM products WHERE id=? AND status="published" FOR UPDATE', [$productId]);
                if (!$product) throw new RuntimeException('A product in your cart is no longer available.');
                $variant = null;
                if ($variantId) {
                    $variant = Database::fetchOne('SELECT * FROM product_variants WHERE id=? AND product_id=? FOR UPDATE', [$variantId, $productId]);
                    if (!$variant) throw new RuntimeException('A selected product option is no longer available.');
                }
                $stock = (int)($variant['stock'] ?? $product['stock']);
                if ($qty > $stock) throw new RuntimeException($product['name'] . ' has only ' . $stock . ' item(s) available.');
                $price = (float)($variant['price'] ?? ($product['sale_price'] ?: $product['regular_price']));
                $lineTotal = $price * $qty;
                $subtotal += $lineTotal;
                $vendorKey = (int)($product['vendor_id'] ?? 0);
                $vendorSubtotals[$vendorKey] = ($vendorSubtotals[$vendorKey] ?? 0) + $lineTotal;
                $validatedItems[] = compact('product', 'variant', 'variantId', 'qty', 'price');
            }

            $quote = ShippingEngine::quote($subtotal, 1, $districtId, $areaId);
            $shipping = (float)$quote['shipping_charge'];
            $discount = 0.0;
            $coupon = null;
            if ($couponCode !== '') {
                $coupon = Database::fetchOne('SELECT * FROM coupons WHERE UPPER(code)=? AND status="active" AND (starts_at IS NULL OR starts_at<=NOW()) AND (ends_at IS NULL OR ends_at>=NOW()) LIMIT 1 FOR UPDATE', [$couponCode]);
                if (!$coupon) throw new RuntimeException('Coupon is invalid or expired.');
                if (!empty($coupon['usage_limit']) && db_count('coupon_usages', 'coupon_id=?', [(int)$coupon['id']]) >= (int)$coupon['usage_limit']) throw new RuntimeException('Coupon usage limit has been reached.');
                $eligibleSubtotal = empty($coupon['vendor_id']) ? $subtotal : (float)($vendorSubtotals[(int)$coupon['vendor_id']] ?? 0);
                if ($eligibleSubtotal <= 0) throw new RuntimeException('This coupon does not apply to the products in your cart.');
                if ($eligibleSubtotal < (float)($coupon['min_order_amount'] ?? 0)) throw new RuntimeException('Coupon minimum order amount is ' . money($coupon['min_order_amount']) . '.');
                $discount = ($coupon['discount_type'] ?? '') === 'percentage' ? round($eligibleSubtotal * ((float)$coupon['discount_value'] / 100), 2) : (float)$coupon['discount_value'];
                $discount = min($eligibleSubtotal, max(0, $discount));
            }
            $total = max(0, round($subtotal + $shipping - $discount, 2));
            $orderNo = 'PH-' . date('Ymd') . '-' . strtoupper(substr(bin2hex(random_bytes(4)), 0, 8));
            $paymentStatus = $paymentMethod === 'wallet' ? 'paid' : 'pending';
            $paidAmount = 0.0;
            $dueAmount = $total;

            if ($paymentMethod === 'wallet') {
                $userId = (int)($customer['id'] ?? 0);
                if ($userId < 1 || !WalletService::debit($userId, 'purchase', $total, 'Marketplace order payment')) {
                    throw new RuntimeException('Insufficient purchase-wallet balance.');
                }
                $paidAmount = $total;
                $dueAmount = 0.0;
            }

            Database::execute(
                'INSERT INTO orders (order_no,customer_id,affiliate_member_id,customer_name,customer_email,customer_phone,subtotal,discount_amount,reward_discount,shipping_charge,vat_amount,total_amount,paid_amount,due_amount,payment_method,payment_status,order_status,delivery_address,order_note,created_at,updated_at) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,NOW(),NOW())',
                [$orderNo,$customer['id']??null,$affiliateMemberId,$name,$email,$phone,$subtotal,$discount,0,$shipping,0,$total,$paidAmount,$dueAmount,$paymentMethod,$paymentStatus,'pending',$address,trim((string)($payload['order_note']??''))]
            );
            $orderId = Database::lastInsertId();

            foreach ($validatedItems as $row) {
                $product = $row['product'];
                $variant = $row['variant'];
                $qty = $row['qty'];
                $price = $row['price'];
                $purchasePrice = (float)($product['purchase_price'] ?? 0);
                $commission = 0.0;
                Database::execute(
                    'INSERT INTO order_items (order_id,product_id,vendor_id,product_name,sku,qty,unit_price,purchase_price,total_price,commission_amount,created_at) VALUES (?,?,?,?,?,?,?,?,?,?,NOW())',
                    [$orderId,$product['id'],$product['vendor_id']??null,$product['name'],$variant['sku']??$product['sku'],$qty,$price,$purchasePrice,$qty*$price,$commission]
                );
                if ($row['variantId']) {
                    Database::execute('UPDATE product_variants SET stock=stock-?, updated_at=NOW() WHERE id=?', [$qty,$row['variantId']]);
                }
                Database::execute('UPDATE products SET stock=GREATEST(stock-?,0), sold_count=sold_count+?, updated_at=NOW() WHERE id=?', [$qty,$qty,$product['id']]);
                Database::safeExecute('INSERT INTO stock_ledgers (product_id,variant_id,vendor_id,movement_type,quantity,balance_after,note,created_by,created_at) VALUES (?,?,?,?,?,?,?,?,NOW())', [$product['id'],$row['variantId'],$product['vendor_id']??null,'order_sale',-$qty,max(0,(int)$product['stock']-$qty),'Order '.$orderNo,$customer['id']??null]);
            }

            Database::execute('INSERT INTO order_status_history (order_id,status,note,created_by,created_at) VALUES (? ,"pending","Order placed",?,NOW())', [$orderId,$customer['id']??null]);
            if ($coupon) Database::execute('INSERT INTO coupon_usages (coupon_id,user_id,order_id,discount_amount,created_at) VALUES (?,?,?,?,NOW())', [$coupon['id'],$customer['id']??null,$orderId,$discount]);
            if ($paymentStatus === 'paid') {
                Database::safeExecute('INSERT INTO payments (order_id,gateway,transaction_id,amount,status,raw_response,created_at) VALUES (?,?,?,?,?,?,NOW())', [$orderId,'wallet','WALLET-'.$orderNo,$total,'paid',json_encode(['source'=>'purchase_wallet'])]);
            }
            Security::logActivity((int)($customer['id'] ?? 0) ?: null, 'order_created', ['order_id'=>$orderId,'order_no'=>$orderNo,'total'=>$total]);
            $_SESSION['last_order_id'] = $orderId;
            $_SESSION['last_order_no'] = $orderNo;
            unset($_SESSION['affiliate_referral_code']);
            return $orderId;
        });
    }
}
