<?php

namespace App\Livewire\Forms\Studio\Manage;

use App\Enums\OrderChannel;
use App\Enums\OrderStatus;
use App\Enums\PaymentMethod;
use App\Enums\PaymentStatus;
use App\Models\Order;
use App\Models\Payment;
use App\Models\User;
use App\Models\Voucher;
use App\Rules\UnsignedInteger;
use App\Traits\Order\WithDiscount;
use App\Traits\Order\WithOrderItem;
use App\Traits\Order\WithUpdateStock;
use App\Traits\WithMediaHandler;
use Illuminate\Support\Facades\DB;
use Illuminate\Validation\Rule;
use Livewire\Form;

class OrderForm extends Form
{
    use WithDiscount, WithMediaHandler, WithOrderItem, WithUpdateStock;

    public ?Order $order = null;

    public string $outlet_id = '';

    public string $channel = '1';

    public string $status = '4';

    public string $payment_method = '1';

    public string $perfume_id = '';

    public string $bottle_id = '';

    public string $quality_id = '';

    public string $bottle_size = '';

    public string $product_id = '';

    public string $quantity_product = '';

    public string $item_id = '';

    public string $quantity_edit = '';

    public string $discount = '';

    public string $member_id = '';

    public string $voucher_id = '';

    public function rules(): array
    {
        return [
            'outlet_id' => ['required', Rule::exists('outlets', 'id')],
            'channel' => ['required', Rule::in(OrderChannel::values())],
            'status' => ['required', Rule::in(OrderStatus::values())],
            'payment_method' => ['required', Rule::in(PaymentMethod::values())],
            'discount' => ['nullable', new UnsignedInteger],
            'member_id' => ['nullable', Rule::exists('customers', 'id')],
            'voucher_id' => ['nullable', Rule::exists('vouchers', 'id')],
        ];
    }

    public function validationAttributes(): array
    {
        return [
            'payment_method' => 'metode pembayaran',
            'discount' => 'diskon',
            'member_id' => 'member',
            'voucher_id' => 'voucher',
        ];
    }

    public function store()
    {
        $this->validate();

        $items = $this->loadOrderItems();

        // Generate a unique invoice number based on today's paid order count
        $todayCount = Order::whereDate('created_at', now())->paid()->count() + 1;
        $invoiceNumber = 'INV'.now()->format('Ymd').str_pad($todayCount, 4, '0', STR_PAD_LEFT);

        // Calculate total cost of goods sold (COGS) — internal purchase cost
        $cogs = $items->sum(fn ($item) => $item->cogs * $item->quantity);

        // Calculate subtotal before any global discount
        $subtotal = $items->sum(fn ($item) => $item->unit_price * $item->quantity);

        $manualDiscount = replaceCurrency($this->discount);

        // Apply manual discount
        $afterManual = $subtotal - $manualDiscount;

        $voucherDiscount = $this->calculateDiscount($afterManual);

        if (is_array($voucherDiscount)) {
            return $voucherDiscount;
        }

        // Calculate total discount
        $discount = $voucherDiscount + $manualDiscount;

        // Calculate total (subtotal - manual discount - voucher discount)
        $total = $afterManual - $voucherDiscount;

        $pointsEarned = (int) floor($total / 5000);

        // Wrap the entire operation in a database transaction
        // Ensures atomicity — if any step fails, all changes are rolled back
        try {
            DB::transaction(function () use ($invoiceNumber, $cogs, $subtotal, $discount, $total, $items, $pointsEarned) {
                $member = User::whereHas('customer', fn ($q) => $q->where('id', $this->member_id))
                    ->with(['membership' => fn ($q) => $q->lockForUpdate()])
                    ->first();

                $order = Order::create([
                    'outlet_id' => $this->outlet_id,
                    'user_id' => auth()->id(),
                    'voucher_id' => $this->voucher_id == '' ? null : $this->voucher_id,
                    'customer_id' => $this->member_id == '' ? null : $this->member_id,
                    'invoice_number' => $invoiceNumber,
                    'cogs' => $cogs,
                    'subtotal' => $subtotal,
                    'discount' => $discount,
                    'total' => $total,
                    'channel' => $this->channel,
                    'status' => $this->status,
                    'payment_method' => $this->payment_method,
                    'ordered_at' => now(),
                ]);

                foreach ($items as $item) {
                    // Deduct item stock from the outlet inventory
                    $result = $this->decreaseOutletStock($order->outlet, $item);

                    if ($result && ! $result['status']) {
                        throw new \Exception($result['message']);
                    }

                    // Attach all order items to the newly created order
                    $item->order_id = $order->id;
                    $item->save();
                }

                // Automatically record payment for the order
                Payment::create([
                    'order_id' => $order->id,
                    'user_id' => auth()->id(),
                    'method' => $this->payment_method,
                    'amount' => $total,
                    'status' => PaymentStatus::PAID->value,
                ]);

                // Deduct voucher quantity
                if ($this->voucher_id) {
                    $userVoucher = DB::table('user_voucher')
                        ->where('user_id', $member->id)
                        ->where('voucher_id', $this->voucher_id)
                        ->lockForUpdate()
                        ->first();

                    if ($userVoucher) {
                        if ($userVoucher->quantity > 1) {
                            DB::table('user_voucher')
                                ->where('id', $userVoucher->id)
                                ->update([
                                    'quantity' => $userVoucher->quantity - 1,
                                    'updated_at' => now(),
                                ]);
                        } else {
                            DB::table('user_voucher')
                                ->where('id', $userVoucher->id)
                                ->delete();
                        }
                    }
                }

                // Update member tier points
                if ($member && $member->membership) {
                    $member->membership()->update([
                        'tier_points' => DB::raw("tier_points + $pointsEarned"),
                        'reward_points' => DB::raw("reward_points + $pointsEarned"),
                        'last_transaction_at' => now(),
                    ]);
                }
            });
        } catch (\Exception $e) {
            return [
                'status' => false,
                'message' => $e->getMessage(),
            ];
        }

        return ['status' => true];
    }
}
