<?php

namespace App\Livewire\PurchaseOrders;

use App\Models\Inventory;
use App\Models\Location;
use App\Models\ProductStock;
use App\Models\PurchaseOrder;
use App\Models\PurchaseOrderItem;
use App\Models\Setting;
use App\Services\AccountingService;
use App\Services\FifoService;
use Illuminate\Support\Facades\DB;
use Livewire\Component;

class ReceivePurchaseOrder extends Component
{
    public int $orderId;
    public PurchaseOrder $order;

    public array $receivingItems = [];
    public string $receiving_notes = '';
    public string $receiving_date = '';

    public bool $showConfirmModal = false;

    public function mount(int $id)
    {
        $this->orderId = $id;
        $this->order = PurchaseOrder::with(['items.product', 'partner'])->findOrFail($id);
        $this->receiving_date = now()->format('Y-m-d');

        if (!in_array($this->order->status, ['ordered', 'partial'])) {
            session()->flash('error', __('This order cannot be received.'));
            return redirect()->route('purchases.index');
        }

        $this->loadItems();
    }

    protected function loadItems()
    {
        $this->receivingItems = [];
        foreach ($this->order->items as $item) {
            $remaining = $item->quantity - $item->received_qty;
            $this->receivingItems[] = [
                'id' => $item->id,
                'product_id' => $item->product_id,
                'product_name' => $item->product->localized_name,
                'sku' => $item->product->sku,
                'ordered_quantity' => $item->quantity,
                'received_qty' => $item->received_qty,
                'remaining' => $remaining,
                'receiving_now' => $remaining, // Default to remaining
                'cost_price' => $item->cost_price,
                'batch_no' => $item->batch_no ?? '',
                'expiry_date' => $item->expiry_date ? $item->expiry_date->format('Y-m-d') : '',
            ];
        }
    }

    public function getTotalReceivingProperty()
    {
        return array_sum(array_column($this->receivingItems, 'receiving_now'));
    }

    public function getTotalValueProperty()
    {
        $total = 0;
        foreach ($this->receivingItems as $item) {
            $total += floatval($item['receiving_now']) * floatval($item['cost_price']);
        }
        return $total;
    }

    public function confirmReceive()
    {
        // Validate at least one item is being received
        $hasItems = false;
        foreach ($this->receivingItems as $item) {
            if ($item['receiving_now'] > 0) {
                $hasItems = true;
                break;
            }
        }

        if (!$hasItems) {
            session()->flash('error', __('Please enter quantity for at least one item.'));
            return;
        }

        $this->showConfirmModal = true;
    }

    public function receive()
    {
        try {
            DB::beginTransaction();

            $branchId = auth()->user()->branch_id ?? 1;
            $locationId = $this->order->location_id;
            $allCompleted = true;

            foreach ($this->receivingItems as $item) {
                $receivingQty = floatval($item['receiving_now']);
                if ($receivingQty <= 0) continue;

                // Update PO item received quantity
                $poItem = PurchaseOrderItem::find($item['id']);
                $newReceived = $poItem->received_qty + $receivingQty;
                $poItem->update(['received_qty' => $newReceived]);

                // Check if item is fully received
                if ($newReceived < $poItem->quantity) {
                    $allCompleted = false;
                }

                // Ensure location ID is set
                $targetLocationId = $locationId ?? Location::defaultLocation($branchId)?->id;

                // Update inventory
                // Function will return inventory record for the specific location
                $inventory = Inventory::findOrCreateForProduct($item['product_id'], $branchId, $targetLocationId);
                
                // Update global product cost price (weighted average) using total stock across all locations
                $product = $poItem->product;
                $currentGlobalStock = Inventory::where('product_id', $item['product_id'])->sum('quantity');
                $currentValue = $inventory->avg_cost * $currentGlobalStock; // Approximation, ideally should be sum of (qty * cost) per record
                
                // Better approach for global Average Cost:
                // New Global Avg Cost = ((Current Total Stock * Current Cost) + (New Qty * New Cost)) / (Current Total Stock + New Qty)
                
                $totalCurrentValue = $currentGlobalStock > 0 ? ($currentGlobalStock * $product->cost_price) : 0;
                $newValue = $receivingQty * floatval($item['cost_price']);
                $totalGlobalStock = $currentGlobalStock + $receivingQty;
                
                if ($totalGlobalStock > 0) {
                    $newGlobalCost = ($totalCurrentValue + $newValue) / $totalGlobalStock;
                    $product->update(['cost_price' => $newGlobalCost]);
                }

                // Add stock to the specific inventory record
                $inventory->addStock($receivingQty, floatval($item['cost_price']));

                // Create FIFO lot
                FifoService::addLot([
                    'product_id'  => $item['product_id'],
                    'branch_id'   => $branchId,
                    'location_id' => $targetLocationId,
                    'cost_price'  => floatval($item['cost_price']),
                    'quantity'    => $receivingQty,
                    'batch_no'    => $item['batch_no'] ?: null,
                    'expiry_date' => $item['expiry_date'] ?: null,
                    'source_type' => 'purchase_order',
                    'source_id'   => $this->order->id,
                ]);
            }

            // Update PO status
            $newStatus = $allCompleted ? 'completed' : 'partial';
            $this->order->update([
                'status' => $newStatus,
                'received_date' => now(),
            ]);

            // Record receiving history (could be a separate table)
            // For now, we just update the notes
            if ($this->receiving_notes) {
                $existingNotes = $this->order->notes ?? '';
                $newNote = "\n[" . now()->format('Y-m-d H:i') . "] " . __('Received') . ": " . $this->receiving_notes;
                $this->order->update(['notes' => $existingNotes . $newNote]);
            }

            // Create Journal Entry
            $receivedValue = 0;
            foreach ($this->receivingItems as $item) {
                $receivingQty = floatval($item['receiving_now']);
                if ($receivingQty > 0) {
                    $receivedValue += $receivingQty * $item['cost_price'];
                }
            }

            if ($receivedValue > 0) {
                try {
                    $accountingService = app(AccountingService::class);
                    $accountingService->createPurchaseJournalEntry($this->order, $receivedValue);
                    
                    // Update Supplier Balance (Liability increases)
                    // Assuming positive balance = We owe them / They owe us?
                    // Standard: + = Debit (They owe us), - = Credit (We owe them). 
                    // BUT in this system 'current_balance' seems to depend on usage.
                    // If we assume single column:
                    // Supplier Payment (Liability decrease): decrements.
                    // So PO Receive (Liability increase) should INCREMENT.
                    // Wait, if Payment (giving money) decrements, then creating debt should increment?
                    // Example: Bal 0. Receive 100. Bal 100 (We owe 100). Pay 100. Bal 0.
                    // This creates a positive balance for Payables. 
                    // Let's stick to this as it matches CreateSale logic (Customer buys -> Bal increases).
                    
                     if ($this->order->partner_id) {
                         \App\Models\Partner::where('id', $this->order->partner_id)
                            ->decrement('current_balance', $receivedValue);
                    }

                } catch (\Exception $e) {
                    // Log error but don't fail the transaction
                    \Log::error('Failed to create PO journal/balance update: ' . $e->getMessage());
                }
            }

            DB::commit();

            session()->flash('success', __('Items received successfully.'));
            return redirect()->route('purchases.show', $this->orderId);

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

        $this->showConfirmModal = false;
    }

    public function render()
    {
        return view('livewire.purchase-orders.receive', [
            'currency' => Setting::get('default_currency', 'EGP'),
        ]);
    }
}
