<?php

namespace App\Livewire\Checkout;

use App\Livewire\Cart\Concerns\InteractsWithCart;
use App\Livewire\Checkout\Forms\Details;
use Daylight\Core\Models\Enums\AddressType;
use Daylight\Core\Models\Enums\CustomerType;
use Daylight\Core\Models\Variant;
use Daylight\Core\Modules\Cart\Contracts\CalculatesShippingCosts;
use Daylight\Core\Modules\Pricing\Facades\Pricing;
use Daylight\Core\Notifications\OrderProcessingNotification;
use Daylight\Core\Services\Countries;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
use Livewire\Attributes\Computed;
use Livewire\Component;

class Form extends Component
{
    use InteractsWithCart;

    public Details $form;

    public ?int $billingAddressId = null;

    public ?int $shippingAddressId = null;

    public function updatedFormPaymentMethod()
    {
        $this->dispatch('change-payment-method');
    }

    public function updatedBillingAddressId(?int $addressId): void
    {
        if (is_null($addressId)) {
            $this->form->reset('billingAddress');

            return;
        }

        $billingAddress = $this->billingAddresses()->firstWhere('id', $addressId);

        $this->form->billingAddress = $billingAddress->only([
            'name',
            'vat_number',
            'vat_number_verified_at',
            'address_line_1',
            'address_line_2',
            'postal_code',
            'city',
            'country_id',
        ]);

        $this->updatedFormBillingAddressCountryId();
    }

    public function updatedShippingAddressId(?int $addressId): void
    {
        if (is_null($addressId)) {
            $this->form->reset('shippingAddress');

            return;
        }

        $shippingAddress = $this->shippingAddresses()->firstWhere('id', $addressId);

        $this->form->shippingAddress = $shippingAddress->only([
            'name',
            'address_line_1',
            'address_line_2',
            'postal_code',
            'city',
            'country_id',
        ]);
    }

    public function updatedFormBillingAddressCountryId(): void
    {
        if ($this->form->copyShippingAddressFromBilling) {
            $this->form->shippingAddress['country_id'] = $this->form->billingAddress['country_id'];
        }
    }

    #[Computed]
    public function billingAddresses(): ?Collection
    {
        return auth()->user()?->customer->billingAddresses;
    }

    #[Computed]
    public function shippingAddresses(): ?Collection
    {
        return auth()->user()?->customer->shippingAddresses;
    }

    public function hasExemptedVat(): bool
    {
        if ($this->billingAddressId) {
            $billingAddress = $this->billingAddresses()->firstWhere('id', $this->billingAddressId);

            return $billingAddress->hasExemptedVat();
        }

        if (
            $this->getBillingCountry()->code !== 'NL' &&
            $this->form->accountDetails['type'] === 'business' &&
            $this->form->billingAddress['vat_number_verified_at'] &&
            substr($this->form->billingAddress['vat_number'], 0, 2) === $this->getBillingCountry()->code
        ) {
            return true;
        }

        return false;
    }

    #[Computed]
    public function paymentMethods(): Collection
    {
        return collect();
    }

    private function getShippingCalculator(): CalculatesShippingCosts
    {
        return app(CalculatesShippingCosts::class);
    }

    public function shippingCosts($force = false): int
    {
        if (! $force && $this->form->shippingMethod === 'pickup') {
            return 0;
        }

        return $this->getShippingCalculator()
            ->setBillingCountry($this->getBillingCountry())
            ->setShippingCountry($this->getShippingCountry())
            ->forCountry($this->getShippingCountry())
            ->calculateTotalShippingCost();
    }

    public function formattedShippingCosts(): float
    {
        return round($this->shippingCosts() / 100, 2);
    }

    public function taxes(): Collection
    {
        if ($this->hasExemptedVat()) {
            return collect([
                [
                    'rate' => 0,
                    'amount' => 0,
                    'name' => __('VAT'),
                ],
            ]);
        }

        $variants = $this->cart()->instance()->variants
            ->groupBy('tax_class_id')
            ->map(function ($variants, $class) {
                $taxRate = $this->getBillingCountry()->taxRates->where('tax_class_id', $class)->first();

                $subtotal = $variants->reduce(function ($carry, Variant $variant) {
                    return intval($carry) + ($variant->pricing()->quantity($variant->pivot->quantity)->get()->matched->getRawOriginal('price') * $variant->pivot->quantity);
                }, 0);

                $tax = $subtotal * ($taxRate->rate / 100);

                return [
                    'rate' => $taxRate->rate,
                    'amount' => $tax,
                    'name' => $taxRate->name,
                ];
            });

        if ($this->form->shippingMethod === 'pickup') {
            return $variants;
        }

        return collect([
            ...$variants,
            ...$this->getShippingCalculator()->calculateTotalShippingTax(),
        ])
            ->groupBy('rate')
            ->map(function ($taxes) {
                return [
                    'rate' => $taxes->first()['rate'],
                    'amount' => $taxes->sum('amount'),
                    'name' => $taxes->first()['name'],
                ];
            });
    }

    public function total(): int
    {
        return $this->cart()->subtotal() + $this->shippingCosts() + $this->taxes()->sum('amount');
    }

    public function formattedTotals(): float
    {
        return round($this->total() / 100, 2);
    }

    public function submit()
    {
        $this->form->validate();

        // Save phone number to user
        auth()->user()->update([
            'phone' => $this->form->accountDetails['phone'] ?? auth()->user()->phone,
        ]);

        $order = DB::transaction(function () {
            $order = auth()->user()->customer->orders()->create([
                'user_id' => auth()->id(),

                'shipping_method' => $this->form->shippingMethod,
                'payment_method' => $this->form->paymentMethod,

                'notes' => $this->form->notes,

                'subtotal' => $this->cart()->subtotal(),
                'shipping' => $this->shippingCosts(),
                'tax' => $this->taxes()->sum('amount'),
                'total' => $this->total(),

                'status' => $this->form->paymentMethod === 'invoice'
                    ? 'awaiting_payment'
                    : 'pending',

                'payment_gateway_id' => null,
                'payment_gateway_status' => null,

                'tax_breakdown' => $this->taxes()->values()->toArray(),
            ]);

            $this->cart()->instance()->variants->each(function ($item) use ($order) {
                $order->items()->create([
                    'variant_id' => $item->id,
                    'sku' => $item->sku,
                    'name' => $item->product->name,
                    'quantity' => $item->pivot->quantity,
                    'price' => Pricing::for($item)
                        ->quantity($item->pivot->quantity)
                        ->get()
                        ->matched
                        ->getRawOriginal('price'),
                ]);
            });

            $order->addresses()->create([
                'type' => AddressType::BILLING,
                ...$this->form->billingAddress,
            ]);

            $order->addresses()->create([
                'type' => AddressType::SHIPPING,
                ...$this->form->shippingAddress,
            ]);

            $order->updates()->create([
                'content' => __('Order created'),
            ]);

            return $order;
        });

        $this->cart()->removeAll();
        $this->cart()->destroy();

        if ($this->form->paymentMethod === 'invoice') {
            auth()->user()->notify(
                new OrderProcessingNotification($order)
            );

            $order->update([
                'status' => 'awaiting_payment',
                'confirmation_send_at' => now(),
            ]);

            return redirect()->translatedRoute('checkout.status', ['orderUuid' => $order->uuid]);
        }

        dd('Redirect to payment gateway', $order);
    }

    public function mount(): void
    {
        auth()->user()?->loadMissing([
            'customer.shippingAddresses',
            'customer.billingAddresses',
        ]);

        $this->form->accountDetails['email'] = auth()->user()?->email;
        $this->form->accountDetails['phone'] = auth()->user()?->phone;
        $this->form->accountDetails['name'] = auth()->user()?->name;
        $this->form->accountDetails['last_name'] = auth()->user()?->last_name;

        $this->form->accountDetails['type'] = auth()->user()?->customer->type === CustomerType::COMPANY
            ? 'business'
            : 'individual';

        if ($this->billingAddresses() && $this->billingAddresses()->isNotEmpty()) {
            $this->billingAddressId = $this->billingAddresses()->sortByDesc('default')->first()->id;

            $this->updatedBillingAddressId($this->billingAddressId);
        }

        $this->form->shippingAddress = $this->form->billingAddress;
        $this->form->copyShippingAddressFromBilling = true;

        $this->form->paymentMethod = 'invoice';
    }

    public function render()
    {
        return view('livewire.checkout.form', [
            'countries' => Countries::all(),
        ]);
    }
}
