<?php

namespace App\Services;

use App\Models\Order;
use App\Models\OrderItem;
use App\Models\OrderStatusHistory;
use App\Models\PaymentTransaction;
use App\Models\Product;
use App\Models\User;
use Illuminate\Support\Facades\DB;
use RuntimeException;

class UserOrderService
{
    public function __construct(private readonly WalletService $walletService)
    {
    }

    public function placeOrder(
        User $user,
        Product $product,
        int $quantity,
        string $paymentMethod
    ): Order {
        if (! $product->is_active) {
            throw new RuntimeException('Product is not active.');
        }

        if ($quantity < 1) {
            throw new RuntimeException('Quantity must be at least 1.');
        }

        if ((int) $product->stock < $quantity) {
            throw new RuntimeException('Requested quantity is not available in stock.');
        }

        if (! in_array($paymentMethod, ['wallet', 'upi', 'cod'], true)) {
            throw new RuntimeException('Unsupported payment method.');
        }

        $lineTotal = round((float) $product->dp_price * $quantity, 2);
        $lineBv = round((float) $product->bv * $quantity, 4);
        $status = $paymentMethod === 'wallet' ? 'paid' : 'pending_payment';
        $paymentStatus = $paymentMethod === 'wallet' ? 'paid' : 'unpaid';

        return DB::transaction(function () use ($user, $product, $quantity, $paymentMethod, $lineTotal, $lineBv, $status, $paymentStatus): Order {
            $order = Order::query()->create([
                'order_number' => 'US'.strtoupper(bin2hex(random_bytes(4))),
                'user_id' => $user->id,
                'order_type' => 'user',
                'status' => $status,
                'payment_status' => $paymentStatus,
                'subtotal' => $lineTotal,
                'discount' => 0,
                'tax' => 0,
                'shipping' => 0,
                'total' => $lineTotal,
                'total_bv' => $lineBv,
                'payment_method' => $paymentMethod,
                'shipping_address' => trim(implode(', ', array_filter([
                    $user->address,
                    $user->city,
                    $user->state,
                    $user->pincode,
                ]))),
            ]);

            OrderItem::query()->create([
                'order_id' => $order->id,
                'product_id' => $product->id,
                'product_name' => $product->name,
                'sku' => $product->sku,
                'quantity' => $quantity,
                'unit_price' => (float) $product->dp_price,
                'unit_bv' => (float) $product->bv,
                'gst_percent' => (float) $product->gst_percent,
                'line_total' => $lineTotal,
                'line_bv' => $lineBv,
            ]);

            if ($paymentMethod === 'wallet') {
                $this->walletService->debit(
                    $user->id,
                    'repurchase',
                    $lineTotal,
                    'user_order',
                    $order->id,
                    [
                        'reference' => 'USR-ORD-'.$order->id,
                        'display_reference' => $order->order_number,
                        'narration' => 'User order paid from shopping wallet',
                    ]
                );
            }

            PaymentTransaction::query()->create([
                'user_id' => $user->id,
                'order_id' => $order->id,
                'gateway' => $paymentMethod,
                'merchant_order_ref' => $order->order_number,
                'amount' => $lineTotal,
                'payment_for' => 'order',
                'status' => $paymentMethod === 'wallet' ? 'success' : 'pending',
            ]);

            OrderStatusHistory::query()->create([
                'order_id' => $order->id,
                'status' => $status,
                'changed_by' => $user->id,
                'notes' => 'Order placed by user',
            ]);

            return $order;
        });
    }

    public function cancelOrder(User $user, Order $order): Order
    {
        if ((int) $order->user_id !== (int) $user->id) {
            throw new RuntimeException('You cannot cancel this order.');
        }

        if (! in_array($order->status, ['pending_payment', 'paid'], true)) {
            throw new RuntimeException('This order cannot be cancelled at current status.');
        }

        return DB::transaction(function () use ($user, $order): Order {
            if ($order->payment_method === 'wallet' && $order->payment_status === 'paid') {
                $alreadyRefunded = \App\Models\WalletTransaction::query()
                    ->where('user_id', $order->user_id)
                    ->where('source_type', 'user_order_refund')
                    ->where('source_id', $order->id)
                    ->where('direction', 'credit')
                    ->exists();

                if (! $alreadyRefunded) {
                    $this->walletService->credit(
                        $order->user_id,
                        'repurchase',
                        (float) $order->total,
                        'user_order_refund',
                        $order->id,
                        [
                            'reference' => 'USR-ORD-RFD-'.$order->id,
                            'display_reference' => $order->order_number,
                            'narration' => 'Order cancelled, wallet refunded',
                        ]
                    );
                }
                $order->payment_status = 'refunded';
            }

            $order->status = 'cancelled';
            $order->cancelled_at = now();
            $order->save();

            OrderStatusHistory::query()->create([
                'order_id' => $order->id,
                'status' => 'cancelled',
                'changed_by' => $user->id,
                'notes' => 'Cancelled by user',
            ]);

            return $order;
        });
    }
}

