<?php

namespace App\Livewire\POS;

use App\Domain\Financial\Services\CashSessionService;
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\Pricing\Services\PricingService;
use App\Domain\Shared\Exceptions\DomainException;
use App\Domain\Training\Models\TrainingProgram;
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 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;

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

    // Cash session
    public bool $hasOpenSession = false;

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

    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->participantSearch = '';
        $this->searchResults = [];
    }

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

    public function addProgram(int $programId, PricingService $pricingService): void
    {
        $program = TrainingProgram::findOrFail($programId);
        $participant = $this->participantId ? Participant::find($this->participantId) : null;

        try {
            $priceResult = $pricingService->calculate(
                priceable: $program,
                participant: $participant,
                branchId: auth()->user()->branch_id ?? null,
                couponCode: $this->couponCode ?: null,
            );

            $this->cart[] = [
                'item_type' => POSItemType::Program->value,
                'item_id' => $program->id,
                'item_name_ar' => $program->name_ar,
                'quantity' => 1,
                'unit_price' => $priceResult->finalAmount,
                'base_price' => $priceResult->baseAmount,
                'discount_amount' => $priceResult->totalDiscount,
                'line_total' => $priceResult->finalAmount,
                'pricing_snapshot' => $priceResult->toArray(),
                'metadata' => ['program_id' => $program->id],
            ];
        } catch (DomainException $e) {
            session()->flash('error', $e->getMessage());
        }
    }

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

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

            $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,
            );

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

            // Reset cart
            $this->cart = [];
            $this->couponCode = '';
            $this->notes = '';
            $this->splitPayments = [];
            $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->lastTransactionUuid = null;
    }

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

    public function render()
    {
        $programs = TrainingProgram::where('status', 'active')->orderBy('name_ar')->get();

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