<?php

namespace App\Livewire\Store;

use App\Enums\CustomerType;
use App\Enums\OrderStatus;
use App\Enums\PaymentMethod;
use App\Models\Cart as CartModel;
use App\Models\DeliveryArea;
use App\Models\GuestCustomer;
use App\Models\Order;
use App\Models\OrderItem;
use App\Models\Payment;
use App\Enums\PaymentStatus;
use Illuminate\Support\Facades\DB;
use Livewire\Attributes\Layout;
use Livewire\Attributes\On;
use Livewire\Attributes\Title;
use Livewire\Component;

#[Layout('layouts.store')]
#[Title('Checkout')]
class Checkout extends Component
{
    // ── Data Customer ─────────────────────────────────────────────────────
    public string $name    = '';
    public string $phone   = '';
    public string $address = '';

    // ── Pengiriman & Pembayaran ───────────────────────────────────────────
    public string $deliveryAreaId   = '';
    public string $paymentMethod    = '';
    public string $customerNotes    = '';

    // ── State ─────────────────────────────────────────────────────────────
    public bool   $orderPlaced          = false;
    public string $orderNumber          = '';
    public string $placedPaymentMethod  = ''; // disimpan saat placeOrder() untuk halaman sukses

    // ── Lifecycle ─────────────────────────────────────────────────────────

    /**
     * Dipanggil dari JS setelah localStorage di-load.
     * Hanya isi field yang masih kosong (prioritas: DB > localStorage).
     */
    #[On('guest-profile:loaded')]
    public function fillFromLocalStorage(array $data): void
    {
        if (empty($this->name)    && ! empty($data['name']))           $this->name          = $data['name'];
        if (empty($this->phone)   && ! empty($data['phone']))          $this->phone         = $data['phone'];
        if (empty($this->address) && ! empty($data['address']))        $this->address       = $data['address'];
        if (empty($this->deliveryAreaId) && ! empty($data['deliveryAreaId'])) {
            $this->deliveryAreaId = $data['deliveryAreaId'];
        }
        if (empty($this->customerNotes) && ! empty($data['customerNotes'])) {
            $this->customerNotes = $data['customerNotes'];
        }
    }

    public function mount(): void
    {
        // Redirect ke keranjang jika kosong
        $items = CartModel::forSession(session()->getId())->get();
        if ($items->isEmpty()) {
            $this->redirect(route('store.cart'));
            return;
        }

        // Pre-fill dari guest_customer jika sudah pernah checkout
        $guest = GuestCustomer::forSession(session()->getId())->latest()->first();
        if ($guest) {
            $this->name    = $guest->name;
            $this->phone   = $guest->phone;
            $this->address = $guest->address;
        }
    }

    // ── Validation ───────────────────────────────────────────────────────

    protected function rules(): array
    {
        return [
            'name'           => ['required', 'string', 'max:150'],
            'phone'          => ['required', 'string', 'max:20'],
            'address'        => ['required', 'string', 'min:10'],
            'deliveryAreaId' => ['nullable', 'exists:delivery_areas,id'],
            'paymentMethod'  => ['required', 'in:transfer,qris,cod'],
            'customerNotes'  => ['nullable', 'string', 'max:500'],
        ];
    }

    protected function messages(): array
    {
        return [
            'name.required'           => 'Nama lengkap wajib diisi.',
            'phone.required'          => 'Nomor HP wajib diisi.',
            'address.required'        => 'Alamat pengiriman wajib diisi.',
            'address.min'             => 'Alamat terlalu pendek, mohon isi lebih lengkap.',
            'deliveryAreaId.exists'   => 'Area pengiriman tidak valid.',
            'paymentMethod.required'  => 'Pilih metode pembayaran.',
            'paymentMethod.in'        => 'Metode pembayaran tidak valid.',
        ];
    }

    // ── Computed ─────────────────────────────────────────────────────────

    public function getSelectedAreaProperty(): ?DeliveryArea
    {
        if (! $this->deliveryAreaId) return null;
        return DeliveryArea::find($this->deliveryAreaId);
    }

    // ── Actions ──────────────────────────────────────────────────────────

    /**
     * Buat pesanan dari keranjang.
     * Satu order untuk satu checkout (semua mitra dalam satu order).
     * Backend Admin yang memproses per mitra.
     */
    public function placeOrder(): void
    {
        $this->validate();

        $sessionId = session()->getId();
        $items     = CartModel::with(['product.partner'])->forSession($sessionId)->get();

        if ($items->isEmpty()) {
            $this->addError('address', 'Keranjang sudah kosong.');
            return;
        }

        $deliveryArea   = $this->deliveryAreaId ? DeliveryArea::findOrFail($this->deliveryAreaId) : null;
        $paymentMethod  = PaymentMethod::from($this->paymentMethod);

        $shipping     = new \App\Services\ShippingCalculator();
        $deliveryCost = $shipping->calculate($deliveryArea, $items);

        $subtotal     = $items->sum('subtotal');
        $grandTotal   = $subtotal + $deliveryCost;

        try {
        DB::transaction(function () use (
            $items, $deliveryArea, $deliveryCost, $paymentMethod,
            $subtotal, $grandTotal, $sessionId
        ) {
            // 1. Simpan / update guest customer
            $guest = GuestCustomer::updateOrCreate(
                ['session_id' => $sessionId],
                [
                    'name'    => $this->name,
                    'phone'   => $this->phone,
                    'address' => $this->address,
                ]
            );

            // B-01 fix: validasi stok di dalam transaction dengan lock
            // Mencegah race condition antara cek stok dan pembuatan order
            foreach ($items as $cartItem) {
                if ($cartItem->product->isOutOfStock()) {
                    throw new \RuntimeException(
                        '"' . $cartItem->product->name . '" stok sudah habis. '
                        . 'Silakan hapus produk tersebut dari keranjang.'
                    );
                }
            }

            // 2. Generate order number: TBB-YYYYMMDD-XXXX
            // F-01 fix: pakai lockForUpdate agar COUNT aman dari concurrent request
            $datePart    = now()->format('Ymd');
            $countToday  = Order::whereDate('created_at', today())->lockForUpdate()->count() + 1;
            $orderNumber = 'TBB-' . $datePart . '-' . str_pad($countToday, 4, '0', STR_PAD_LEFT);

            // 3. Buat order
            $order = Order::create([
                'order_number'              => $orderNumber,
                'customer_type'             => CustomerType::Guest,
                'guest_customer_id'         => $guest->id,
                'customer_name'             => $this->name,
                'customer_phone'            => $this->phone,
                'delivery_address_snapshot' => $this->address,
                'delivery_area_id'          => $deliveryArea?->id,
                'delivery_cost'             => $deliveryCost,
                'subtotal'                  => $subtotal,
                'grand_total'               => $grandTotal,
                'discount_amount'           => 0,
                'status'                    => OrderStatus::Pending,
                'payment_method'            => $paymentMethod,
                'customer_notes'            => $this->customerNotes ?: null,
                'payment_deadline'          => $paymentMethod !== PaymentMethod::Cod
                    ? now()->addHours(24)
                    : null,
            ]);

            // 4. Buat order items (snapshot harga saat checkout)
            foreach ($items as $cartItem) {
                $product = $cartItem->product;
                OrderItem::create([
                    'order_id'         => $order->id,
                    'product_id'       => $product->id,
                    'product_name'     => $product->name,
                    'product_image'    => $product->image,
                    'buy_price'        => $product->buy_price,
                    'sell_price'       => $product->sell_price,
                    'commission_type'  => $product->commission_type,
                    'commission_value' => $product->commission_value,
                    'quantity'         => $cartItem->quantity,
                    'subtotal'         => $cartItem->subtotal,
                    'notes'            => $cartItem->notes ?: null,
                ]);
            }

            // 5. Buat payment record (pending)
            // method sinkron dengan orders.payment_method — keduanya dari enum PaymentMethod yang sama
            Payment::create([
                'order_id' => $order->id,
                'method'   => $paymentMethod,
                'status'   => PaymentStatus::Pending,
                'amount'   => $grandTotal,
            ]);

            // 6. Kosongkan keranjang
            CartModel::forSession($sessionId)->delete();

            // 7. Simpan order number dan metode pembayaran untuk halaman sukses
            $this->orderNumber         = $orderNumber;
            $this->placedPaymentMethod = $this->paymentMethod;
            $this->orderPlaced         = true;

            // 8. Dispatch event SETELAH commit — hanya berjalan sekali jika
            //    transaction berhasil. Jika rollback, callback ini tidak dijalankan.
            DB::afterCommit(function () use ($order) {
                \App\Events\OrderPlaced::dispatch($order);
            });
        });
        } catch (\RuntimeException $e) {
            $this->addError('address', $e->getMessage());
            return;
        }

        // Sync badge keranjang setelah checkout berhasil
        if ($this->orderPlaced) {
            $this->dispatch('cart-updated');

            // Simpan data ke localStorage agar tidak perlu isi ulang
            $this->dispatch('guest-profile:save', data: [
                'name'           => $this->name,
                'phone'          => $this->phone,
                'address'        => $this->address,
                'deliveryAreaId' => $this->deliveryAreaId,
                'customerNotes'  => $this->customerNotes,
            ]);
        }
    }

    // ── Render ────────────────────────────────────────────────────────────

    public function render()
    {
        $items         = CartModel::with(['product.partner'])->forSession(session()->getId())->get();
        $groupedItems  = $items->groupBy(fn ($item) => $item->product->partner_id);
        $subtotal      = $items->sum('subtotal');
        $deliveryAreas    = DeliveryArea::active()->get();
        $selectedArea     = $this->selectedArea;
        $shipping         = new \App\Services\ShippingCalculator();
        $deliveryCost     = $shipping->calculate($selectedArea, $items);
        $defaultCostValue = $shipping->defaultCost;
        $usingDefaultCost = $shipping->isUsingDefaultCost($selectedArea) && $deliveryAreas->isNotEmpty();
        $grandTotal       = $subtotal + $deliveryCost;
        $paymentMethods = PaymentMethod::cases();

        // Data instruksi pembayaran — untuk halaman sukses
        $bankAccounts         = json_decode(\App\Models\Setting::get('bank_accounts', '[]'), true) ?? [];
        $qrisImage            = \App\Models\Setting::get('qris_image');
        $transferInstruction  = \App\Models\Setting::get('transfer_instruction', '');
        $qrisInstruction      = \App\Models\Setting::get('qris_instruction', '');

        return view('livewire.store.checkout', compact(
            'items', 'groupedItems', 'subtotal',
            'deliveryAreas', 'selectedArea', 'deliveryCost', 'grandTotal',
            'usingDefaultCost', 'defaultCostValue',
            'paymentMethods',
            'bankAccounts', 'qrisImage', 'transferInstruction', 'qrisInstruction'
        ));
    }
}
