<?php

namespace App\Livewire\POS;

use App\Domain\Financial\Models\InvoiceItem;
use App\Domain\Financial\Services\CashSessionService;
use App\Domain\Inventory\Models\Product;
use App\Domain\Participant\Models\Participant;
use App\Domain\POS\Enums\POSItemType;
use App\Domain\POS\Enums\POSPaymentMethod;
use App\Domain\POS\Services\POSService;
use App\Domain\Shared\Exceptions\DomainException;
use Livewire\Attributes\Layout;
use Livewire\Attributes\Title;
use Livewire\Component;

#[Layout('layouts.app')]
#[Title('نقطة البيع')]
class POSTerminal extends Component
{
    // Cart state
    public array $cart = [];
    public ?int $participantId = null;
    public string $participantName = '';
    public bool $participantIsFree = false;
    public string $participantSearch = '';
    public string $couponCode = '';
    public string $paymentMethod = 'cash';
    public string $notes = '';

    // Split payment
    public array $splitPayments = [];
    public string $splitMethod = 'cash';
    public float $splitAmount = 0;

    // Manual item
    public string $manualItemName = '';
    public float $manualItemPrice = 0;
    public int $manualItemQty = 1;

    // Partial payment (deposit)
    public bool $useDeposit = false;
    public float $depositAmount = 0;

    // UI state
    public bool $showCheckout = false;
    public bool $showReceipt = false;
    public ?string $lastReceiptNumber = null;
    public ?int $lastTransactionTotal = null;
    public ?int $lastTransactionPaid = null;
    public ?string $lastTransactionUuid = null;

    // Cash session
    public bool $hasOpenSession = false;

    // Participant search results
    public array $searchResults = [];

    // Essential product warnings (product was already purchased this year)
    public array $essentialWarnings = [];

    public function mount(CashSessionService $cashSessionService): void
    {
        $this->authorize('pos.sell');

        $session = $cashSessionService->getOpenSession(auth()->user());
        $this->hasOpenSession = $session !== null;
    }

    public function updatedParticipantSearch(): void
    {
        if (mb_strlen($this->participantSearch) < 2) {
            $this->searchResults = [];
            return;
        }

        $this->searchResults = Participant::whereHas('person', fn ($q) => $q->where('name_ar', 'ilike', "%{$this->participantSearch}%")
              ->orWhere('phone', 'like', "%{$this->participantSearch}%")
        )->with('person')->limit(10)->get()
            ->map(fn ($p) => ['id' => $p->id, 'name' => $p->person->name_ar, 'phone' => $p->person->phone ?? ''])
            ->toArray();
    }

    public function selectParticipant(int $id): void
    {
        $participant = Participant::with('person')->findOrFail($id);
        $this->participantId = $participant->id;
        $this->participantName = $participant->person->name_ar;
        $this->participantIsFree = (bool) $participant->is_free;
        $this->participantSearch = '';
        $this->searchResults = [];
    }

    public function clearParticipant(): void
    {
        $this->participantId = null;
        $this->participantName = '';
        $this->participantIsFree = false;
        $this->searchResults = [];
        $this->essentialWarnings = [];
    }

    public function addProduct(int $productId): void
    {
        $product = Product::findOrFail($productId);

        // Check if essential product was already purchased this year by this participant
        if ($product->is_essential && $this->participantId) {
            $this->checkEssentialProductHistory($product);
        }

        $existingIndex = collect($this->cart)->search(fn ($item) => $item['item_type'] === POSItemType::Product->value && $item['item_id'] === $product->id);

        if ($existingIndex !== false) {
            $this->updateQuantity($existingIndex, $this->cart[$existingIndex]['quantity'] + 1);
            return;
        }

        $unitPrice = $product->selling_price;

        $this->cart[] = [
            'item_type' => POSItemType::Product->value,
            'item_id' => $product->id,
            'item_name_ar' => $product->name_ar,
            'quantity' => 1,
            'unit_price' => $unitPrice,
            'base_price' => $unitPrice,
            'discount_amount' => 0,
            'line_total' => $unitPrice,
            'pricing_snapshot' => [],
            'metadata' => ['product_id' => $product->id, 'sku' => $product->sku],
        ];
    }

    private function checkEssentialProductHistory(Product $product): void
    {
        $yearStart = now()->startOfYear();
        $productType = 'App\\Domain\\Inventory\\Models\\Product';

        $previousPurchase = InvoiceItem::where('itemable_type', $productType)
            ->where('itemable_id', $product->id)
            ->where('created_at', '>=', $yearStart)
            ->whereHas('invoice', fn ($q) => $q
                ->where('billable_type', 'App\\Domain\\Participant\\Models\\Participant')
                ->where('billable_id', $this->participantId)
                ->whereNotIn('status', ['cancelled', 'draft'])
            )
            ->orderByDesc('created_at')
            ->first();

        if ($previousPurchase) {
            $this->essentialWarnings[$product->id] = [
                'product_name' => $product->name_ar,
                'purchased_at' => $previousPurchase->created_at->format('Y-m-d'),
                'participant_name' => $this->participantName,
            ];
            $this->dispatch('essential-product-warning', productId: $product->id);
        }
    }

    public function dismissEssentialWarning(int $productId): void
    {
        unset($this->essentialWarnings[$productId]);
    }

    public function addManualItem(): void
    {
        if (empty($this->manualItemName) || $this->manualItemPrice <= 0) {
            session()->flash('error', __('يرجى إدخال اسم العنصر والسعر'));
            return;
        }

        $unitPrice = (int) round($this->manualItemPrice * 100);

        $this->cart[] = [
            'item_type' => POSItemType::Other->value,
            'item_id' => null,
            'item_name_ar' => $this->manualItemName,
            'quantity' => max(1, $this->manualItemQty),
            'unit_price' => $unitPrice,
            'base_price' => $unitPrice,
            'discount_amount' => 0,
            'line_total' => $unitPrice * max(1, $this->manualItemQty),
            'pricing_snapshot' => [],
            'metadata' => [],
        ];

        $this->manualItemName = '';
        $this->manualItemPrice = 0;
        $this->manualItemQty = 1;
    }

    public function removeItem(int $index): void
    {
        unset($this->cart[$index]);
        $this->cart = array_values($this->cart);
    }

    public function updateQuantity(int $index, int $quantity): void
    {
        if ($quantity <= 0) {
            $this->removeItem($index);
            return;
        }
        $this->cart[$index]['quantity'] = $quantity;
        $this->cart[$index]['line_total'] = $this->cart[$index]['unit_price'] * $quantity;
        $this->cart[$index]['discount_amount'] = (int) (($this->cart[$index]['base_price'] - $this->cart[$index]['unit_price']) * $quantity);
    }

    public function getCartTotal(): int
    {
        return collect($this->cart)->sum(fn ($item) => (int) $item['line_total']);
    }

    public function getCartDiscount(): int
    {
        return collect($this->cart)->sum(fn ($item) => (int) $item['discount_amount']);
    }

    public function getCartSubtotal(): int
    {
        return collect($this->cart)->sum(fn ($item) => (int) $item['base_price'] * (int) $item['quantity']);
    }

    public function getServiceFee(): int
    {
        $service = app(\App\Domain\Shared\Services\PlatformFeeService::class);
        if (!$service->customerPays()) {
            return 0;
        }
        return $service->calculate($this->getCartTotal());
    }

    public function getCartGrandTotal(): int
    {
        return $this->getCartTotal() + $this->getServiceFee();
    }

    public function addSplitPayment(): void
    {
        if ($this->splitAmount <= 0) {
            return;
        }

        $this->splitPayments[] = [
            'method' => $this->splitMethod,
            'amount' => (int) round($this->splitAmount * 100),
            'reference' => null,
        ];

        $this->splitAmount = 0;
    }

    public function removeSplitPayment(int $index): void
    {
        unset($this->splitPayments[$index]);
        $this->splitPayments = array_values($this->splitPayments);
    }

    public function getSplitTotal(): int
    {
        return collect($this->splitPayments)->sum(fn ($sp) => (int) $sp['amount']);
    }

    public function cartAllowsDeposit(): bool
    {
        foreach ($this->cart as $item) {
            if (($item['item_type'] ?? '') === POSItemType::Product->value && isset($item['item_id'])) {
                $product = Product::find($item['item_id']);
                if ($product && $product->allows_partial_payment) {
                    return true;
                }
            }
        }
        return false;
    }

    public function getMinimumDepositPercent(): int
    {
        $maxPercent = 10;
        foreach ($this->cart as $item) {
            if (($item['item_type'] ?? '') === POSItemType::Product->value && isset($item['item_id'])) {
                $product = Product::find($item['item_id']);
                if ($product && $product->allows_partial_payment) {
                    $maxPercent = max($maxPercent, $product->minimum_deposit_percent);
                }
            }
        }
        return $maxPercent;
    }

    public function getMinimumDepositAmount(): int
    {
        $grandTotal = $this->getCartGrandTotal();
        return (int) ceil($grandTotal * $this->getMinimumDepositPercent() / 100);
    }

    public function updatedUseDeposit(): void
    {
        if ($this->useDeposit) {
            $this->depositAmount = round($this->getMinimumDepositAmount() / 100, 2);
        } else {
            $this->depositAmount = 0;
        }
    }

    public function openCheckout(): void
    {
        if (empty($this->cart)) {
            session()->flash('error', __('السلة فارغة'));
            return;
        }
        $this->showCheckout = true;
    }

    public function closeCheckout(): void
    {
        $this->showCheckout = false;
    }

    public function checkout(POSService $posService): void
    {
        if (empty($this->cart)) {
            session()->flash('error', __('السلة فارغة'));
            return;
        }

        // Validate deposit amount if using deposit
        if ($this->useDeposit && $this->cartAllowsDeposit()) {
            $depositPiasters = (int) round($this->depositAmount * 100);
            $minDeposit = $this->getMinimumDepositAmount();
            $grandTotal = $this->getCartGrandTotal();

            if ($depositPiasters < $minDeposit) {
                session()->flash('error', __('مبلغ المقدم أقل من الحد الأدنى'));
                return;
            }
            if ($depositPiasters >= $grandTotal) {
                session()->flash('error', __('مبلغ المقدم يجب أن يكون أقل من الإجمالي'));
                return;
            }
        }

        // Validate split total (must cover grand total including service fee)
        if ($this->paymentMethod === 'split' && !$this->useDeposit) {
            $splitTotal = $this->getSplitTotal();
            $grandTotal = $this->getCartGrandTotal();
            if ($splitTotal < $grandTotal) {
                session()->flash('error', __('المبلغ المدفوع أقل من الإجمالي'));
                return;
            }
        }

        try {
            $participant = $this->participantId ? Participant::find($this->participantId) : null;

            $depositPiasters = null;
            if ($this->useDeposit && $this->cartAllowsDeposit()) {
                $depositPiasters = (int) round($this->depositAmount * 100);
            }

            $transaction = $posService->processTransaction(
                cartItems: $this->cart,
                cashier: auth()->user(),
                branchId: auth()->user()->branch_id ?? 0,
                paymentMethod: $this->paymentMethod,
                participant: $participant,
                couponCode: $this->couponCode ?: null,
                splitPayments: $this->paymentMethod === 'split' ? $this->splitPayments : null,
                notes: $this->notes ?: null,
                depositAmount: $depositPiasters,
            );

            $this->lastReceiptNumber = $transaction->receipt_number;
            $this->lastTransactionTotal = $transaction->total_amount;
            $this->lastTransactionPaid = $depositPiasters ?? $transaction->total_amount;
            $this->lastTransactionUuid = $transaction->uuid;
            $this->showReceipt = true;

            // Reset cart
            $this->cart = [];
            $this->couponCode = '';
            $this->notes = '';
            $this->splitPayments = [];
            $this->useDeposit = false;
            $this->depositAmount = 0;
            $this->showCheckout = false;

            session()->flash('success', __('تمت العملية بنجاح'));
        } catch (DomainException $e) {
            session()->flash('error', $e->getMessage());
        }
    }

    public function closeReceipt(): void
    {
        $this->showReceipt = false;
        $this->lastReceiptNumber = null;
        $this->lastTransactionTotal = null;
        $this->lastTransactionPaid = null;
        $this->lastTransactionUuid = null;
    }

    public function newTransaction(): void
    {
        $this->cart = [];
        $this->participantId = null;
        $this->participantName = '';
        $this->couponCode = '';
        $this->paymentMethod = 'cash';
        $this->notes = '';
        $this->splitPayments = [];
        $this->useDeposit = false;
        $this->depositAmount = 0;
        $this->showCheckout = false;
        $this->showReceipt = false;
        $this->lastReceiptNumber = null;
        $this->lastTransactionTotal = null;
        $this->lastTransactionPaid = null;
        $this->lastTransactionUuid = null;
    }

    public function render()
    {
        $branchId = auth()->user()->branch_id ?? null;

        $products = Product::where('is_active', true)
            ->when($branchId, fn ($q) => $q->where(function ($sub) use ($branchId) {
                $sub->where('branch_id', $branchId)->orWhereNull('branch_id');
            }))
            ->orderBy('name_ar')
            ->get();

        return view('livewire.pos.pos-terminal', [
            'products' => $products,
            'cartTotal' => $this->getCartTotal(),
            'cartDiscount' => $this->getCartDiscount(),
            'cartSubtotal' => $this->getCartSubtotal(),
            'serviceFee' => $this->getServiceFee(),
            'cartGrandTotal' => $this->getCartGrandTotal(),
            'paymentMethods' => POSPaymentMethod::cases(),
            'allowsDeposit' => $this->cartAllowsDeposit(),
            'minimumDepositAmount' => $this->getMinimumDepositAmount(),
            'minimumDepositPercent' => $this->getMinimumDepositPercent(),
        ]);
    }
}
