<?php

namespace App\Livewire;

use App\Models\CashTransaction;
use App\Models\Category;
use App\Models\Partner;
use App\Models\Inventory;
use App\Models\Location;
use App\Models\PaymentMethod;
use App\Models\PosSession;
use App\Models\Product;
use App\Models\Sale;
use App\Models\SaleItem;
use App\Models\PurchaseOrder;
use App\Models\PurchaseOrderItem;
use App\Models\Setting;
use App\Services\AccountingService;
use App\Services\FifoService;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Livewire\Attributes\Computed;
use Livewire\WithPagination;
use Livewire\Component;

class PointOfSale extends Component
{
    use WithPagination;
    // Search & Filtering
    public string $search = '';
    public ?int $categoryFilter = null;
    
    // Cart
    public array $cart = [];
    public ?int $partnerId = null;
    public string $discount = '0';
    public string $discountType = 'fixed';
    public int $paymentMethodId = 1;
    public string $amountReceived = '';
    public array $salePayments = []; // [ ['method_id' => 1, 'amount' => 100, 'name' => 'Cash'] ]
    public ?int $selectedPaymentMethodId = null;
    public string $paymentInputAmount = '';
    public string $notes = '';
    public bool $isCredit = false; // Credit sale flag (default OFF)
    public ?int $sellerId = null; // Seller assignment

    // UI State
    public bool $showPaymentModal = false;
    public bool $showReceiptModal = false;
    public bool $showPartnerModal = false; // Renamed from showCustomerModal
    public bool $showSessionModal = false;
    public bool $showCloseSessionModal = false;
    public bool $showCashDrawerModal = false;
    public bool $showSettlementModal = false;
    public ?Sale $lastSale = null;
    public ?PosSession $currentSession = null;

    // Session Close
    public string $closingCash = '0';
    public array $sessionSummary = [];

    // Cash Drawer
    public string $cashType = 'in'; // in or out
    public string $cashAmount = '';
    public string $cashReason = '';

    // Settlement
    public ?int $settlementPartnerId = null;
    public string $settlementAmount = '';
    public ?int $settlementPaymentMethodId = null;
    public string $settlementNotes = '';

    // New Partner
    public bool $showNewPartnerModal = false;
    public string $newPartnerName = '';
    public string $newPartnerPhone = '';

    // Quick PO
    public bool $showQuickPoModal = false;
    public ?int $poSupplierId = null;
    public string $poProductName = '';
    public string $poProductSku = ''; // Optional
    public string $poProductCost = '';
    public string $poProductPrice = '';
    public string $poProductQty = '1';
    public ?int $poCategoryId = null;

    // New Supplier (Quick PO)
    public bool $showNewSupplierModal = false;
    public string $newSupplierName = '';
    public string $newSupplierPhone = '';

    // Discount Modal Interface
    public bool $showDiscountModal = false;
    public string $discountInputPassword = '';
    public bool $discountAuthorized = false;
    public ?int $discountTargetIndex = null; // null = Global
    public string $discountInputAmount = '';
    public string $discountInputType = 'fixed'; // fixed or percent

    protected $listeners = ['refreshCart' => '$refresh', 'openSession'];

    public function openDiscountModal($index = null)
    {
        $this->reset(['discountInputPassword', 'discountAuthorized', 'discountInputAmount', 'discountInputType']);
        $this->discountTargetIndex = ($index === '' || $index === null) ? null : (int)$index;
        
        // Load existing if any
        if ($this->discountTargetIndex !== null && isset($this->cart[$this->discountTargetIndex])) {
            $this->discountInputAmount = (string)$this->cart[$this->discountTargetIndex]['discount'];
            $this->discountInputType = $this->cart[$this->discountTargetIndex]['discount_type'] ?? 'fixed';
        } elseif ($this->discountTargetIndex === null) {
            $this->discountInputAmount = $this->discount;
            $this->discountInputType = $this->discountType;
        }

        $this->showDiscountModal = true;
    }

    public function authorizeDiscount()
    {
        $storedPassword = Setting::get('pos_discount_password', '1234');
        if ($this->discountInputPassword === $storedPassword) {
            $this->discountAuthorized = true;
        } else {
            $this->addError('discountInputPassword', 'Incorrect password.');
        }
    }

    public function commitDiscount()
    {
        $amount = (float)$this->discountInputAmount;
        $type = $this->discountInputType;

        if ($this->discountTargetIndex !== null) {
            $this->applyItemDiscount($this->discountTargetIndex, $amount, $type);
        } else {
            $this->applyGlobalDiscount($amount, $type);
        }

        $this->showDiscountModal = false;
        $this->reset(['discountInputPassword', 'discountAuthorized']);
    }

    public function mount()
    {
        $this->currentSession = PosSession::where('user_id', Auth::id())
            ->where('status', 'open')
            ->first();
        
        // Default seller to current user
        $this->sellerId = Auth::id();
    }

    // === SESSION MANAGEMENT ===

    public function openSession(float $openingBalance = 0)
    {
        $this->currentSession = PosSession::create([
            'user_id' => Auth::id(),
            'branch_id' => Auth::user()->branch_id ?? 1,
            'opening_cash' => $openingBalance,
            'status' => 'open',
            'opened_at' => now(),
        ]);

        // Create Journal Entry for Opening Balance
        try {
            $accountingService = app(\App\Services\AccountingService::class);
            $accountingService->createSessionOpenJournalEntry($this->currentSession);
        } catch (\Exception $e) {
            \Log::error('Failed to create session open journal entry: ' . $e->getMessage());
        }

        $this->showSessionModal = false;
    }

    public function showCloseSession()
    {
        if (!$this->currentSession) return;

        // Calculate session summary
        $this->calculateSessionSummary();
        $this->closingCash = '';
        $this->showCloseSessionModal = true;
    }

    protected function calculateSessionSummary()
    {
        $sessionId = $this->currentSession->id;

        // Query SalePayment table directly for accurate payment method totals
        $paymentSummary = \App\Models\SalePayment::query()
            ->join('sales', 'sale_payments.sale_id', '=', 'sales.id')
            ->join('payment_methods', 'sale_payments.payment_method_id', '=', 'payment_methods.id')
            ->where('sales.pos_session_id', $sessionId)
            ->whereIn('sales.status', ['completed', 'partial'])
            ->selectRaw('
                payment_methods.code, 
                payment_methods.id as method_id,
                SUM(sale_payments.amount) as total_amount, 
                COUNT(DISTINCT sales.id) as sale_count
            ')
            ->groupBy('payment_methods.code', 'payment_methods.id')
            ->get()
            ->keyBy('code');

        // Get totals for each payment method
        $cashSales = $paymentSummary->get('cash');
        $cardSales = $paymentSummary->get('card');
        
        // Calculate total sales and total paid
        $totalSales = Sale::where('pos_session_id', $sessionId)
            ->whereIn('status', ['completed', 'partial'])
            ->sum('total');
            
        $totalPaid = Sale::where('pos_session_id', $sessionId)
            ->whereIn('status', ['completed', 'partial'])
            ->sum('paid');
        
        // Credit sales = Total - Paid (unpaid balance)
        $creditAmount = $totalSales - $totalPaid;
        
        // Count of sales with unpaid balance
        $creditSalesCount = Sale::where('pos_session_id', $sessionId)
            ->whereIn('status', ['completed', 'partial'])
            ->whereRaw('total > paid')
            ->count();

        // Cash transactions
        $cashInTransactions = CashTransaction::where('pos_session_id', $sessionId)
            ->where('type', 'in')
            ->get();

        $cashOutTransactions = CashTransaction::where('pos_session_id', $sessionId)
            ->where('type', 'out')
            ->get();

        $cashInSum = $cashInTransactions->sum('amount');
        $cashOutSum = $cashOutTransactions->sum('amount');

        // Calculate expected cash (only actual cash payments, not total sales)
        $expectedCash = $this->currentSession->opening_cash
            + ($cashSales?->total_amount ?? 0)
            + $cashInSum
            - $cashOutSum;

        $this->sessionSummary = [
            'total_sales' => $totalSales,
            'sales_count' => Sale::where('pos_session_id', $sessionId)
                ->whereIn('status', ['completed', 'partial'])
                ->count(),
            'cash_sales' => $cashSales?->total_amount ?? 0,
            'cash_sales_count' => $cashSales?->sale_count ?? 0,
            'card_sales' => $cardSales?->total_amount ?? 0,
            'card_sales_count' => $cardSales?->sale_count ?? 0,
            'credit_sales' => $creditAmount,
            'credit_sales_count' => $creditSalesCount,
            'cash_in' => $cashInSum,
            'cash_in_transactions' => $cashInTransactions,
            'cash_out' => $cashOutSum,
            'cash_out_transactions' => $cashOutTransactions,
            'opening_balance' => $this->currentSession->opening_cash,
            'expected_cash' => $expectedCash,
        ];
    }

    public function closeSession()
    {
        if (!$this->currentSession) return;

        $this->validate([
            'closingCash' => 'required|numeric|min:0',
        ]);

        $closingCash = floatval($this->closingCash);
        $expectedCash = $this->sessionSummary['expected_cash'];
        $difference = $closingCash - $expectedCash;

        $this->currentSession->update([
            'actual_cash' => $closingCash,
            'expected_cash' => $expectedCash,
            'difference' => $difference,
            'total_sales' => $this->sessionSummary['total_sales'],
            'total_cash_sales' => $this->sessionSummary['cash_sales'],
            'total_card_sales' => $this->sessionSummary['card_sales'],
            'total_credit_sales' => $this->sessionSummary['credit_sales'],
            'cash_in' => $this->sessionSummary['cash_in'],
            'cash_out' => $this->sessionSummary['cash_out'],
            'status' => 'closed',
            'closed_at' => now(),
        ]);

        // Create journal entry for session close
        try {
            $accountingService = app(AccountingService::class);
            $entry = $accountingService->createSessionCloseJournalEntry($this->currentSession);
            
            if ($entry) {
                 session()->flash('success', __('Session closed and Journal Entry created.'));
            } else {
                 session()->flash('success', __('Session closed successfully used (No transactions to record).'));
            }

        } catch (\Exception $e) {
            \Log::error('Failed to create session close journal entry: ' . $e->getMessage());
            session()->flash('error', __('Session closed but Journal Entry FAILED: ') . $e->getMessage());
        }

        // Note: We don't null currentSession immediately so the user can see/print the receipt
        // $this->currentSession = null; 
        // $this->showCloseSessionModal = false;
        $this->cart = [];
    }

    public function dismissClosedSession()
    {
        $this->currentSession = null;
        $this->showCloseSessionModal = false;
        $this->closingCash = '';
    }

    // === CASH DRAWER ===

    public function showCashDrawer(string $type)
    {
        $this->cashType = $type;
        $this->cashAmount = '';
        $this->cashReason = '';
        $this->showCashDrawerModal = true;
    }

    public function processCashTransaction()
    {
        $amount = floatval($this->cashAmount);

        if ($amount <= 0) {
            session()->flash('error', __('Please enter a valid amount.'));
            return;
        }

        if (empty($this->cashReason)) {
            session()->flash('error', __('Please enter a reason.'));
            return;
        }

        $transaction = CashTransaction::create([
            'pos_session_id' => $this->currentSession->id,
            'user_id' => Auth::id(),
            'type' => $this->cashType,
            'amount' => $amount,
            'reason' => $this->cashReason,
        ]);

        // Create journal entry for cash transaction
        try {
            $accountingService = app(AccountingService::class);
            $accountingService->createCashTransactionJournalEntry($transaction);
        } catch (\Exception $e) {
            \Log::warning('Failed to create cash transaction journal entry: ' . $e->getMessage());
        }

        $this->showCashDrawerModal = false;
        session()->flash('success', __('Cash transaction recorded.'));
    }

    // === CART MANAGEMENT ===

    public function addToCart(int $productId)
    {
        $product = Product::with('inventory')->find($productId);
        
        if (!$product || !$product->is_active) {
            session()->flash('error', __('Product not available.'));
            return;
        }

        $branchId = Auth::user()->branch_id ?? 1;
        
        // Get selling locations from settings
        $sellingLocsSetting = Setting::get('pos_selling_locations');
        $sellingLocs = $sellingLocsSetting ? json_decode($sellingLocsSetting, true) : [];
        
        $stock = $product->getStockForBranch($branchId, $sellingLocs);

        // Check stock ONLY if inventory tracking is enabled
        if ($product->track_inventory) {
            $existingIndex = $this->findCartItem($productId);
            $currentQty = $existingIndex !== null ? $this->cart[$existingIndex]['quantity'] : 0;
            
            if ($currentQty + 1 > $stock && !Setting::get('allow_negative_stock', false)) {
                session()->flash('error', __('Insufficient stock in selected selling locations.'));
                return;
            }
        }

        $existingIndex = $this->findCartItem($productId);

        if ($existingIndex !== null) {
            $this->cart[$existingIndex]['quantity']++;
            $this->recalculateCartItem($existingIndex);
        } else {
            $this->cart[] = [
                'product_id' => $product->id,
                'name' => $product->localized_name,
                'sku' => $product->sku,
                'price' => $product->selling_price,
                'original_price' => $product->selling_price,
                // Ensure cost is never null, default to 0 if missing. 
                // CRITICAL: verify Product model attribute is cost_price
                'cost' => $product->cost_price ?? 0,
                'quantity' => 1,
                'discount' => 0,
                'discount_type' => 'fixed',
                'total' => $product->selling_price,
                'max_stock' => $product->track_inventory ? $stock : 999999,
                'warranty_months' => $product->warranty_period ?? 0,
                'warranty_date' => $product->warranty_period 
                    ? now()->addMonths($product->warranty_period)->format('Y-m-d') 
                    : null,
                'repair_notes' => '',
                'is_service' => $product->is_service ?? false,
            ];
        }

        // Add Linked Product (e.g. Part for a Service)
        if ($product->linked_product_id) {
            $this->addToCart($product->linked_product_id);
        }
    }

    public function updateCartNote(int $index, string $note)
    {
        if (!isset($this->cart[$index])) return;
        $this->cart[$index]['repair_notes'] = $note;
    }

    public function scanBarcode(string $barcode)
    {
        $product = Product::where('barcode', $barcode)
            ->orWhere('sku', $barcode)
            ->first();

        if ($product) {
            $this->addToCart($product->id);
        } else {
            session()->flash('error', __('Product not found.'));
        }
    }

    protected function findCartItem(int $productId): ?int
    {
        foreach ($this->cart as $index => $item) {
            if ($item['product_id'] === $productId) {
                return $index;
            }
        }
        return null;
    }

    public function updateCartQuantity(int $index, int $quantity)
    {
        if (!isset($this->cart[$index])) return;

        if ($quantity <= 0) {
            $this->removeCartItem($index);
            return;
        }

        if ($quantity > $this->cart[$index]['max_stock']) {
            session()->flash('error', __('Insufficient stock.'));
            return;
        }

        $this->cart[$index]['quantity'] = $quantity;
        $this->recalculateCartItem($index);
    }

    public function updateCartPrice(int $index, float $price)
    {
        if (!isset($this->cart[$index])) return;
        $this->cart[$index]['price'] = max(0, $price);
        $this->recalculateCartItem($index);
    }

    public function applyItemDiscount(int $index, float $amount, string $type = 'fixed')
    {
        if (!isset($this->cart[$index])) return;
        
        $this->cart[$index]['discount'] = max(0, $amount);
        $this->cart[$index]['discount_type'] = $type;
        $this->recalculateCartItem($index);
    }

    public function applyGlobalDiscount(float $amount, string $type = 'fixed')
    {
        $this->discount = (string) max(0, $amount);
        $this->discountType = $type;
    }

    public function updateWarrantyDate(int $index, string $date)
    {
        if (!isset($this->cart[$index])) return;
        $this->cart[$index]['warranty_date'] = $date ?: null;
    }

    protected function recalculateCartItem(int $index)
    {
        $item = $this->cart[$index];
        $subtotal = $item['quantity'] * $item['price'];
        
        $discountAmount = 0;
        if (isset($item['discount_type']) && $item['discount_type'] === 'percent') {
            $discountAmount = ($subtotal * ($item['discount'] ?? 0)) / 100;
        } else {
            $discountAmount = min($item['discount'] ?? 0, $subtotal);
        }

        $this->cart[$index]['total'] = $subtotal - $discountAmount;
    }

    public function validateDiscountPassword(string $password): bool
    {
        $storedPassword = Setting::get('pos_discount_password', '1234');
        return $password === $storedPassword;
    }

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

    public function clearCart()
    {
        $this->cart = [];
        $this->partnerId = null;
        $this->discount = '0';
        $this->notes = '';
        $this->isCredit = false;
    }

    // === CALCULATIONS ===

    public function getSubtotalProperty(): float
    {
        return array_sum(array_column($this->cart, 'total'));
    }

    public function getDiscountAmountProperty(): float
    {
        $subtotal = $this->getSubtotalProperty();
        $discountValue = floatval($this->discount);

        if ($this->discountType === 'percent') {
            return ($subtotal * $discountValue) / 100;
        }

        return min($discountValue, $subtotal);
    }

    public function getTotalProperty(): float
    {
        return $this->getSubtotalProperty() - $this->getDiscountAmountProperty();
    }

    public function getChangeProperty(): float
    {
        if ($this->isCredit) return 0;
        
        $totalPaid = collect($this->salePayments)->sum('amount');
        return max(0, $totalPaid - $this->getTotalProperty());
    }

    // === PAYMENT MANAGEMENT ===

    public function addPayment()
    {
        $this->validate([
            'selectedPaymentMethodId' => 'required|exists:payment_methods,id',
            'paymentInputAmount' => 'required|numeric|min:0.01',
        ]);

        $method = PaymentMethod::find($this->selectedPaymentMethodId);
        $amount = (float) $this->paymentInputAmount;

        // Check remaining amount
        $total = $this->getTotalProperty();
        $currentPaid = collect($this->salePayments)->sum('amount');
        $remaining = max(0, $total - $currentPaid);

        // Allow overpayment only for Cash (to calculate change), strict for others?
        // For simplicity, allow adding any amount, change will be calculated on total.
        
        $this->salePayments[] = [
            'method_id' => $method->id,
            'name' => $method->name,
            'amount' => $amount,
        ];

        $this->reset(['selectedPaymentMethodId', 'paymentInputAmount']);
        
        // Auto-select remaining amount if any
        $newPaid = $currentPaid + $amount;
        if ($newPaid < $total) {
            $this->paymentInputAmount = (string) ($total - $newPaid);
        }
    }

    public function removePayment(int $index)
    {
        unset($this->salePayments[$index]);
        $this->salePayments = array_values($this->salePayments);
    }

    // === PAYMENT ===

    public function showPayment()
    {
        if (empty($this->cart)) {
            session()->flash('error', __('Cart is empty.'));
            return;
        }

        $this->salePayments = [];
        $total = $this->getTotalProperty();
        
        // Auto-fill default payment (Cash) with full amount
        $defaultMethod = PaymentMethod::where('is_default', true)->first();
        if ($defaultMethod) {
            $this->selectedPaymentMethodId = $defaultMethod->id;
            $this->paymentInputAmount = (string) $total;
        }

        $this->showPaymentModal = true;
    }

    public function toggleCredit()
    {
        $this->isCredit = !$this->isCredit;
        
        if ($this->isCredit) {
            // Credit sale requires partner
            if (!$this->partnerId) {
                $this->showPartnerModal = true;
                $this->isCredit = false;
                session()->flash('error', __('Please select a partner for credit sale.'));
                return;
            }
            $this->amountReceived = '0';
        } else {
            // Recalculate default cash amount
            $total = $this->getTotalProperty();
            $this->salePayments = [];
            $defaultMethod = PaymentMethod::where('is_default', true)->first();
            if ($defaultMethod) {
                $this->selectedPaymentMethodId = $defaultMethod->id;
                $this->paymentInputAmount = (string) $total;
            }
        }
    }

    public function processPayment()
    {
        if (empty($this->cart)) {
            session()->flash('error', __('Cart is empty.'));
            return;
        }

        $total = $this->getTotalProperty();
        $received = collect($this->salePayments)->sum('amount');
        
        // Determine if this is a credit/partial sale
        // If received < total, it's effectively a credit sale for the remainder
        if ($received < $total) {
             // If not explicitly toggled as credit, but payment is partial
             // We can auto-enable credit mode IF a partner is selected
             if ($this->partnerId) {
                 $this->isCredit = true;
             } else {
                 session()->flash('error', __('Insufficient payment. Please select a customer to Pay Later/Partial Pay.'));
                 return;
             }
        }

        // Credit sale requires partner
        if ($this->isCredit && !$this->partnerId) {
            session()->flash('error', __('Credit sale requires a partner.'));
            return;
        }

        DB::beginTransaction();

        try {
            // Calculate remaining balance (unpaid amount)
            $remaining = $total - $received;
            
            // Determine payment_method_id:
            // - Single payment: use that method's ID
            // - Multiple payments or no payments: set to null
            $paymentMethodId = null;
            if (count($this->salePayments) === 1) {
                $paymentMethodId = $this->salePayments[0]['method_id'];
            }
            
            // is_credit is TRUE if there's any unpaid balance
            $hasUnpaidBalance = ($remaining > 0);
            
            // Create Sale
            $sale = Sale::create([
                'sale_number' => Sale::generateSaleNumber(),
                'partner_id' => $this->partnerId,
                'branch_id' => Auth::user()->branch_id ?? 1,
                'pos_session_id' => $this->currentSession?->id,
                'user_id' => Auth::id(),
                'seller_id' => $this->sellerId,
                'payment_method_id' => $paymentMethodId, // null for multi-payment or no payment
                'subtotal' => $this->getSubtotalProperty(),
                'discount' => $this->getDiscountAmountProperty(),
                'total' => $total,
                'paid' => $received, // Total amount paid
                'change' => ($received > $total) ? $received - $total : 0,
                'is_credit' => $hasUnpaidBalance, // True if unpaid balance exists
                'notes' => $this->notes,
                'status' => ($received >= $total) ? 'completed' : 'partial',
            ]);

            // Create Sale Items and Update Inventory
            $branchId = Auth::user()->branch_id ?? 1;
            
            foreach ($this->cart as $item) {
                // Calculate absolute discount amount for storage
                $discountStored = 0;
                $subtotalItem = $item['quantity'] * $item['price'];
                if (isset($item['discount_type']) && $item['discount_type'] === 'percent') {
                     $discountStored = ($subtotalItem * ($item['discount'] ?? 0)) / 100;
                } else {
                     $discountStored = $item['discount'] ?? 0;
                }

                // Determine cost using FIFO when inventory is tracked
                $product = Product::find($item['product_id']);
                $fifoCost = $item['cost'] ?? 0;

                if ($product && $product->track_inventory) {
                    $qtyRemaining = $item['quantity'];
                    $totalFifoCost = 0;
                    
                    // Get selling locations or fallback to default
                    $sellingLocsSetting = Setting::get('pos_selling_locations');
                    $sellingLocs = $sellingLocsSetting ? json_decode($sellingLocsSetting, true) : [];
                    
                    if (empty($sellingLocs)) {
                        $defaultLocation = Location::where('branch_id', $branchId)
                            ->active()->where('is_default', true)->first();
                        $sellingLocs = $defaultLocation ? [$defaultLocation->id] : [];
                    }

                    foreach ($sellingLocs as $locationId) {
                        if ($qtyRemaining <= 0) break;

                        // Check stock at this location
                        $inventory = Inventory::where('product_id', $item['product_id'])
                            ->where('branch_id', $branchId)
                            ->where('location_id', $locationId)
                            ->first();

                        if (!$inventory || $inventory->quantity <= 0) continue;

                        $consumeQty = min($qtyRemaining, $inventory->quantity);

                        // Consume FIFO lots for this location
                        $fifoResult = FifoService::consumeLots(
                            $item['product_id'],
                            $branchId,
                            $consumeQty,
                            $locationId
                        );

                        // Track cost (weighted average or last FIFO cost)
                        if ($fifoResult['avg_cost'] > 0) {
                            $totalFifoCost += ($fifoResult['avg_cost'] * $consumeQty);
                        } else {
                            $totalFifoCost += ($item['cost'] * $consumeQty);
                        }

                        // Decrement location inventory
                        $inventory->decrement('quantity', $consumeQty);
                        $qtyRemaining -= $consumeQty;
                    }

                    // Handle remaining quantity if negative stock is allowed or if locations were exhausted
                    if ($qtyRemaining > 0) {
                        // If we still have quantity left, deduct from the first selling location (or default)
                        $fallbackLocId = $sellingLocs[0] ?? null;
                        if ($fallbackLocId) {
                            $inventory = Inventory::findOrCreateForProduct($item['product_id'], $branchId, $fallbackLocId);
                            $inventory->decrement('quantity', $qtyRemaining);
                            $totalFifoCost += ($item['cost'] * $qtyRemaining);
                        }
                    }

                    $fifoCost = ($item['quantity'] > 0) ? ($totalFifoCost / $item['quantity']) : $item['cost'];
                }

                SaleItem::create([
                    'sale_id' => $sale->id,
                    'product_id' => $item['product_id'],
                    'quantity' => $item['quantity'],
                    'unit_price' => $item['price'],
                    'cost_price' => $fifoCost,
                    'discount' => $discountStored,
                    'total' => $item['total'],
                    'warranty_date' => $item['warranty_date'],
                    'repair_notes' => $item['repair_notes'] ?? null,
                ]);
            }

            // Update partner balance if there is a remaining amount
            // Remaining = Total - Paid
            $remaining = $total - $received;
            if ($remaining > 0 && $this->partnerId) {
                Partner::where('id', $this->partnerId)
                    ->increment('current_balance', $remaining);
            }

            // Record Sale Payments FIRST (so they exist for journal entry)
            foreach ($this->salePayments as $payment) {
                \App\Models\SalePayment::create([
                    'sale_id' => $sale->id,
                    'payment_method_id' => $payment['method_id'],
                    'amount' => $payment['amount'],
                ]);
            }

            // Create Journal Entry for Sale (AFTER payments are recorded)
            try {
                $accountingService = app(\App\Services\AccountingService::class);
                $accountingService->createSaleJournalEntry($sale);
            } catch (\Exception $e) {
                \Log::error('Failed to create sale journal entry: ' . $e->getMessage());
                // Don't fail the sale, just log it. 
            }

            DB::commit();

            $this->lastSale = $sale->load(['items.product', 'partner', 'paymentMethod']);
            $this->showPaymentModal = false;
            $this->showReceiptModal = true;
            $this->clearCart();

        } catch (\Exception $e) {
            DB::rollBack();
            session()->flash('error', __('Error processing sale: ') . $e->getMessage());
        }
    }

    // === SETTLEMENT ===

    public function showSettlement()
    {
        if (!$this->partnerId) {
            session()->flash('error', __('Please select a partner.'));
            return;
        }

        $partner = Partner::find($this->partnerId);
        if ($partner->current_balance <= 0) {
            session()->flash('error', __('Partner has no outstanding balance.'));
            return;
        }

        $this->settlementAmount = (string) $partner->current_balance;
        $this->showSettlementModal = true;
    }

    // === PARTNER SELECTION ===

    public function selectPartner(int $partnerId)
    {
        $this->partnerId = $partnerId;
        $this->showPartnerModal = false;
    }

    public function saveNewPartner()
    {
        $this->validate([
            'newPartnerName' => 'required|string|max:255',
            'newPartnerPhone' => 'nullable|string|max:20',
        ]);

        // Find default customer type (first one with is_customer_group = true)
        $type = \App\Models\PartnerType::where('is_customer_group', true)->first();
        // Fallback if no specific customer group found, use any
        if (!$type) {
             $type = \App\Models\PartnerType::first(); 
        }

        $partner = Partner::create([
            'name' => $this->newPartnerName,
            'phone' => $this->newPartnerPhone,
            'partner_type_id' => $type?->id,
            'branch_id' => Auth::user()->branch_id ?? 1,
            'is_active' => true,
            'current_balance' => 0
        ]);

        $this->partnerId = $partner->id;
        $this->showNewPartnerModal = false;
        $this->showPartnerModal = false; // Close selection modal too
        session()->flash('success', __('Customer created and selected.'));
        
        // Reset form
        $this->newPartnerName = '';
        $this->newPartnerPhone = '';
    }

    public function saveNewSupplier()
    {
        $this->validate([
            'newSupplierName' => 'required|string|max:255',
            'newSupplierPhone' => 'nullable|string|max:20',
        ]);

        // Find default supplier type
        $type = \App\Models\PartnerType::where('is_supplier_group', true)->first();
        if (!$type) {
             $type = \App\Models\PartnerType::first(); 
        }

        $partner = Partner::create([
            'name' => $this->newSupplierName,
            'phone' => $this->newSupplierPhone,
            'partner_type_id' => $type?->id,
            'branch_id' => Auth::user()->branch_id ?? 1,
            'is_active' => true,
            'current_balance' => 0
        ]);

        $this->poSupplierId = $partner->id;
        $this->showNewSupplierModal = false;
        session()->flash('success', __('Supplier created and selected.'));
        
        // Reset form
        $this->newSupplierName = '';
        $this->newSupplierPhone = '';
    }

    public function saveQuickPo()
    {
        $this->validate([
            'poSupplierId' => 'required|exists:partners,id',
            'poProductName' => 'required|string|max:255',
            'poProductCost' => 'required|numeric|min:0',
            'poProductPrice' => 'required|numeric|min:0',
            'poProductQty' => 'required|integer|min:1',
            'poCategoryId' => 'required|exists:categories,id', // Required for product creation
        ]);

        DB::beginTransaction();

        try {
            // 1. Create Product
            $product = Product::create([
                'name' => $this->poProductName,
                'sku' => $this->poProductSku ?: Product::generateSku(),
                'category_id' => $this->poCategoryId,
                'cost_price' => $this->poProductCost,
                'selling_price' => $this->poProductPrice,
                'track_inventory' => true, // Enforce physical product
                'is_active' => true,
                'branch_id' => Auth::user()->branch_id ?? 1,
            ]);

            // 2. Create Purchase Order (Received)
            $qty = (int)$this->poProductQty;
            $cost = (float)$this->poProductCost;
            $total = $qty * $cost;

            $po = PurchaseOrder::create([
                'po_number' => PurchaseOrder::generatePoNumber(),
                'partner_id' => $this->poSupplierId, // Using partner_id as it's the FK in PurchaseOrder
                'branch_id' => Auth::user()->branch_id ?? 1,
                'created_by' => Auth::id(),
                'received_by' => Auth::id(),
                'status' => 'completed', // Immediate receive (Completed)
                'payment_status' => 'unpaid', // Keeping as unpaid/due
                'subtotal' => $total,
                'total' => $total,
                'order_date' => now(),
                'received_date' => now(),
            ]);

            // 3. Create PO Item
            PurchaseOrderItem::create([
                'purchase_order_id' => $po->id,
                'product_id' => $product->id,
                'quantity' => $qty,
                'cost_price' => $cost,
                'total' => $total,
            ]);

            // 4. Update Inventory
            Inventory::updateOrCreate(
                [
                    'product_id' => $product->id,
                    'branch_id' => Auth::user()->branch_id ?? 1,
                ],
                [
                    'quantity' => DB::raw("quantity + $qty"),
                    'last_restocked_at' => now(),
                ]
            );

            // 5. Create Journal Entry
            $accountingService = app(AccountingService::class);
            $accountingService->createPurchaseJournalEntry($po, $total);

            DB::commit();

            $this->showQuickPoModal = false;
            session()->flash('success', __('Quick PO created! Product added and inventory updated.'));
            
            // Reset Form
            $this->reset(['poSupplierId', 'poProductName', 'poProductSku', 'poProductCost', 'poProductPrice', 'poProductQty', 'poCategoryId']);

        } catch (\Exception $e) {
            DB::rollBack();
            session()->flash('error', __('Error creating Quick PO: ') . $e->getMessage());
        }
    }

    public function clearPartner()
    {
        $this->partnerId = null;
        $this->isCredit = false;
    }

    public function printReceipt()
    {
        $this->dispatch('print-receipt');
    }

    // === PARTNER SETTLEMENT ===

    public function openSettlementModal($partnerId)
    {
        $partner = Partner::find($partnerId);
        if (!$partner || $partner->current_balance <= 0) {
            session()->flash('error', __('No outstanding balance for this partner.'));
            return;
        }

        $this->settlementPartnerId = $partnerId;
        $this->settlementAmount = (string)$partner->current_balance; // Pre-fill with full balance
        $this->settlementPaymentMethodId = 1; // Default to first payment method
        $this->settlementNotes = '';
        $this->showSettlementModal = true;
    }

    public function processSettlement()
    {
        $partner = Partner::find($this->settlementPartnerId);
        if (!$partner) {
            session()->flash('error', __('Partner not found.'));
            return;
        }

        $amount = floatval($this->settlementAmount);
        if ($amount <= 0 || $amount > $partner->current_balance) {
            session()->flash('error', __('Invalid payment amount.'));
            return;
        }

        DB::beginTransaction();

        try {
            // Create payment record
            $payment = \App\Models\PartnerPayment::create([
                'partner_id' => $this->settlementPartnerId,
                'branch_id' => Auth::user()->branch_id ?? 1,
                'user_id' => Auth::id(),
                'payment_method_id' => $this->settlementPaymentMethodId,
                'amount' => $amount,
                'notes' => $this->settlementNotes,
                'payment_date' => today(),
                'status' => 'completed',
            ]);

            // Update partner balance
            $partner->decrement('current_balance', $amount);

            // Create journal entry
            try {
                $accountingService = app(AccountingService::class);
                $accountingService->createPartnerPaymentJournalEntry($payment);
            } catch (\Exception $e) {
                \Log::error('Failed to create partner payment journal entry: ' . $e->getMessage());
            }

            DB::commit();

            $this->showSettlementModal = false;
            session()->flash('success', __('Payment recorded successfully.'));
            $this->reset(['settlementPartnerId', 'settlementAmount', 'settlementPaymentMethodId', 'settlementNotes']);

        } catch (\Exception $e) {
            DB::rollBack();
            session()->flash('error', __('Error processing payment: ') . $e->getMessage());
        }
    }

    public function closeSettlementModal()
    {
        $this->showSettlementModal = false;
        $this->reset(['settlementPartnerId', 'settlementAmount', 'settlementPaymentMethodId', 'settlementNotes']);
    }

    public function closeReceipt()
    {
        $this->showReceiptModal = false;
        $this->lastSale = null;
    }

    #[Computed]
    public function products()
    {
        return Product::query()
            ->with('category')
            ->active()
            ->when($this->search, function ($query) {
                $query->where(function ($q) {
                    $q->where('name', 'like', '%' . $this->search . '%')
                      ->orWhere('sku', 'like', '%' . $this->search . '%')
                      ->orWhere('barcode', 'like', '%' . $this->search . '%');
                });
            })
            ->when($this->categoryFilter, function ($query) {
                $query->where('category_id', $this->categoryFilter);
            })
            ->latest()
            ->paginate(20);
    }

    #[Computed]
    public function categories()
    {
        return Category::active()->orderBy('sort_order')->get();
    }

    #[Computed]
    public function partners()
    {
        return Partner::customers()->orderBy('name')->get();
    }

    #[Computed]
    public function suppliers()
    {
        return Partner::suppliers()->orderBy('name')->get();
    }

    #[Computed]
    public function paymentMethods()
    {
        return PaymentMethod::active()->orderBy('sort_order')->get();
    }

    #[Computed]
    public function selectedPartner()
    {
        return $this->partnerId
            ? Partner::find($this->partnerId)
            : null;
    }

    #[Computed]
    public function allUsers()
    {
        return \App\Models\User::orderBy('name')->get();
    }

    // === RENDER ===

    public function render()
    {
        return view('livewire.pos.index', [
            'shopName' => Setting::get('shop_name', 'Shop'),
            'shopPhone' => Setting::get('shop_phone', ''),
            'shopAddress' => Setting::get('shop_address', ''),
            'defaultCurrency' => Setting::get('default_currency', 'EGP'),
        ]);
    }
}
