<?php

namespace App\Services\Order;

use App\Models\Invoice;
use App\Models\License;
use App\Models\Order;
use App\Models\OrderItem;
use App\Models\TaxRule;
use App\Models\User;
use App\Services\License\LicenseGeneratorService;
use App\Services\Security\AuditService;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;

class OrderService
{
    public function __construct(
        private LicenseGeneratorService $generator,
        private AuditService $audit,
    ) {}

    public function createOrder(User $user, array $items, array $billing = []): Order
    {
        return DB::transaction(function () use ($user, $items, $billing) {
            $subtotal = collect($items)->sum(fn($i) => $i['price'] * $i['quantity']);

            // Calculate tax based on the customer's country + state
            $taxAmount  = 0;
            $taxRate    = 0;
            if (setting('tax_enabled', '0') === '1' && $user->country) {
                $taxResult = TaxRule::calculate($subtotal, $user->country, $user->state ?? null);
                $taxAmount = $taxResult['tax_amount'];
                $taxRate   = $taxResult['total_rate'];
            }

            $currency = \App\Models\Currency::default();

            $order = Order::create([
                'order_number'   => $this->generateOrderNumber(),
                'user_id'        => $user->id,
                'status'         => 'pending',
                'subtotal'       => $subtotal,
                'tax'            => $taxAmount,
                'discount'       => 0,
                'total'          => round($subtotal + $taxAmount, 2),
                'currency'       => $currency?->code ?? setting('default_currency', 'USD'),
                'billing_details'=> array_merge($billing, [
                    'tax_rate'    => $taxRate,
                    'tax_country' => $user->country,
                    'tax_state'   => $user->state,
                ]),
            ]);

            foreach ($items as $item) {
                OrderItem::create([
                    'order_id'     => $order->id,
                    'product_id'   => $item['product_id'],
                    'license_type' => $item['license_type'],
                    'price'        => $item['price'],
                    'quantity'     => $item['quantity'],
                    'subtotal'     => $item['price'] * $item['quantity'],
                ]);
            }

            $this->audit->log('order.created', $order, [], ['total' => $order->total]);

            return $order->load('items');
        });
    }

    public function markPaid(Order $order, string $paymentId, string $method = 'manual'): Order
    {
        return DB::transaction(function () use ($order, $paymentId, $method) {
            $order->update([
                'status'         => 'paid',
                'payment_id'     => $paymentId,
                'payment_method' => $method,
                'paid_at'        => now(),
            ]);

            // Generate licenses for each item
            foreach ($order->items as $item) {
                for ($q = 0; $q < $item->quantity; $q++) {
                    $this->generator->generateFromOrderItem($item, $order->user);
                }
            }

            // Create invoice
            $this->createInvoice($order);

            $this->audit->log('order.paid', $order);

            return $order->refresh();
        });
    }

    private function createInvoice(Order $order): Invoice
    {
        $lineItems = $order->items->map(fn($i) => [
            'name'     => $i->product->name,
            'type'     => $i->license_type,
            'qty'      => $i->quantity,
            'price'    => $i->price,
            'subtotal' => $i->subtotal,
        ])->toArray();

        return Invoice::create([
            'invoice_number'  => 'INV-' . strtoupper(Str::random(8)),
            'order_id'        => $order->id,
            'user_id'         => $order->user_id,
            'status'          => 'paid',
            'amount'          => $order->total,
            'tax_amount'      => $order->tax,
            'currency'        => $order->currency,
            'line_items'      => $lineItems,
            'billing_address' => $order->billing_details,
            'issued_at'       => now(),
            'paid_at'         => now(),
        ]);
    }

    private function generateOrderNumber(): string
    {
        return 'ORD-' . date('Ymd') . '-' . strtoupper(Str::random(6));
    }
}
