<?php

namespace App\Services;

use App\Models\Order;
use App\Models\OrderItem;
use App\Models\PaymentMethod;
use App\Models\ProductVariant;
use App\Models\User;
use App\Notifications\NewOrderNotification;
use Illuminate\Support\Facades\DB;

class CheckoutService
{
    protected CartService $cartService;
    protected PointsService $pointsService;
    protected SupplierSyncService $supplierSyncService;

    public function __construct(
        CartService $cartService,
        PointsService $pointsService,
        SupplierSyncService $supplierSyncService,
    ) {
        $this->cartService = $cartService;
        $this->pointsService = $pointsService;
        $this->supplierSyncService = $supplierSyncService;
    }

    public function placeOrder(
        User $user,
        int $paymentMethodId,
        float $paymentFee,
        int $pointsToRedeem = 0,
        ?string $notes = null,
        float $shippingCost = 0,
        ?int $shippingAddressId = null,
        ?string $shippingGovernorate = null,
        ?string $shippingAddressSnapshot = null,
        ?string $paymentReceiptPath = null,
    ): Order {
        $summary = $pointsToRedeem > 0
            ? $this->cartService->recalculateWithRedemption($user, $pointsToRedeem)
            : $this->cartService->recalculate();

        if ($summary->isEmpty()) {
            throw new \RuntimeException('السلة فارغة');
        }

        $netAfterPoints = $summary->subtotal - $summary->discountFromPoints;
        $grandTotal = round($netAfterPoints + $shippingCost + $paymentFee, 2);

        return DB::transaction(function () use ($user, $paymentMethodId, $paymentFee, $notes, $summary, $shippingCost, $shippingAddressId, $shippingGovernorate, $shippingAddressSnapshot, $grandTotal, $paymentReceiptPath) {
            $pm = PaymentMethod::find($paymentMethodId);
            $isCod = $pm && strtolower($pm->slug ?? '') === 'cash';
            $paymentStatus = $isCod ? 'confirmed' : 'pending';

            $order = Order::create([
                'user_id' => $user->id,
                'status' => Order::STATUS_PENDING,
                'payment_method' => $pm?->slug,
                'payment_method_id' => $paymentMethodId,
                'payment_fee' => $paymentFee,
                'payment_receipt' => $paymentReceiptPath,
                'payment_status' => $paymentStatus,
                'subtotal' => $summary->subtotal,
                'points_redeemed' => $summary->pointsRedeemed,
                'discount_from_points' => $summary->discountFromPoints,
                'shipping_cost' => $shippingCost,
                'extra_charges' => 0,
                'total' => $grandTotal,
                'total_profit' => $summary->totalProfit,
                'points_earned' => $summary->pointsEarned,
                'notes' => $notes,
                'shipping_address_id' => $shippingAddressId,
                'shipping_governorate' => $shippingGovernorate,
                'shipping_address_snapshot' => $shippingAddressSnapshot,
            ]);

            foreach ($summary->items as $item) {
                $isOnDemand = $item['fulfillment_type'] === 'on_demand';

                OrderItem::create([
                    'order_id' => $order->id,
                    'variant_id' => $item['variant_id'],
                    'quantity' => $item['quantity'],
                    'unit_price' => $item['unit_price'],
                    'cost_price' => $item['cost_price'],
                    'fulfillment_status' => 'awaiting_supplier',
                ]);

                if (! $isOnDemand) {
                    ProductVariant::where('id', $item['variant_id'])
                        ->decrement('stock', $item['quantity']);
                }
            }

            if ($summary->pointsRedeemed > 0) {
                $this->pointsService->redeemPoints($user, $order, $summary->pointsRedeemed);
            }

            $posCreated = $this->supplierSyncService->createPurchaseOrders($order);

            if ($posCreated > 0) {
                $order->update(['status' => Order::STATUS_PENDING_SUPPLIER]);
            } else {
                $order->items()->update(['fulfillment_status' => 'ready']);
                $order->update(['status' => Order::STATUS_PROCESSING]);
            }

            $this->cartService->clear();

            $freshOrder = $order->fresh();

            $adminsAndSales = User::where('is_admin', true)
                ->whereHas('roles', fn ($q) => $q->whereIn('name', ['admin', 'sales_agent']))
                ->get();

            foreach ($adminsAndSales as $staff) {
                $staff->notify(new NewOrderNotification($freshOrder));
            }

            return $freshOrder;
        });
    }
}
