<?php

namespace App\Services;

use App\Models\PurchaseOrder;
use App\Models\Grn;
use App\Models\GrnItem;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Auth;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;

class PurchaseOrderService
{
    /**
     * Recompute PO status from GRNs (accepted quantities)
     */
    public function recomputeStatus(PurchaseOrder $purchaseOrder): void
    {
        $ordered = (float) $purchaseOrder->items()->sum('quantity');
        $received = (float) $purchaseOrder->grns()->with('items')->get()
            ->sum(fn ($grn) => (float) $grn->items->sum(fn ($gi) => (float) ($gi->accepted_quantity ?? $gi->received_quantity ?? 0)));

        $new = $purchaseOrder->status;
        if ($ordered > 0 && $received >= $ordered) {
            $new = 'fully_received';
        } elseif ($received > 0 && $received < $ordered) {
            $new = 'partially_received';
        }

        if ($new !== $purchaseOrder->status) {
            $purchaseOrder->update(['status' => $new]);
        }

        // Cascade to PR
        if ($purchaseOrder->purchaseRequest) {
            app(\App\Services\PurchaseRequestService::class)->recomputeStatus($purchaseOrder->purchaseRequest);
        }
    }
    /**
     * Convert PO to GRN with outstanding items
     */
    public function convertToGrn(PurchaseOrder $purchaseOrder, array $receivedItems, bool $allowOverReceive = false): Grn
    {
        if ($purchaseOrder->status === 'cancelled') {
            throw new \Exception('Cannot create GRN for cancelled Purchase Order');
        }

        if (empty($receivedItems)) {
            throw new \Exception('No items received');
        }

        $grn = null;

        DB::transaction(function () use ($purchaseOrder, $receivedItems, $allowOverReceive, &$grn) {
            // Generate GRN number
            $grnNumber = $this->generateGrnNumber();

            $grn = Grn::create([
                'grn_number' => $grnNumber,
                'purchase_order_id' => $purchaseOrder->id,
                'received_by_id' => Auth::id(),
                'received_date' => now()->toDateString(),
                'status' => 'pending_qc',
                'notes' => 'Created from PO: ' . $purchaseOrder->po_number,
            ]);

            $totalReceived = 0;

            foreach ($receivedItems as $itemId => $receivedData) {
                $poItem = $purchaseOrder->items()->where('item_id', $itemId)->first();

                if (!$poItem) {
                    throw new \Exception("Item not found in Purchase Order");
                }

                $receivedQty = $receivedData['received_qty'] ?? 0;
                $acceptedQty = $receivedData['accepted_qty'] ?? $receivedQty;
                $rejectedQty = $receivedData['rejected_qty'] ?? 0;
                $lotNo = $receivedData['lot_no'] ?? null;
                $expiryDate = $receivedData['expiry_date'] ?? null;

                // Validate quantities
                $remainingQty = $poItem->ordered_qty - $poItem->received_qty;

                if ($receivedQty > $remainingQty && !$allowOverReceive) {
                    throw new \Exception("Received quantity ({$receivedQty}) exceeds remaining quantity ({$remainingQty}) for item: {$poItem->item->name}");
                }
                if ($acceptedQty + $rejectedQty !== $receivedQty) {

                    throw new \Exception("Accepted + Rejected quantity must equal received quantity for item: {$poItem->item->name}");
                }

                // Create GRN item
                GrnItem::create([
                    'grn_id' => $grn->id,
                    'purchase_order_item_id' => $poItem->id,
                    'item_id' => $poItem->item_id,
                    'item_variation_id' => $poItem->item_variation_id,
                    'received_quantity' => $receivedQty,
                    'accepted_quantity' => $acceptedQty,
                    'rejected_quantity' => $rejectedQty,
                    'lot_no' => $lotNo,
                    'expiry_date' => $expiryDate,
                    'notes' => $receivedData['notes'] ?? null,
                ]);

                // Update PO item received quantity
                $poItem->increment('received_qty', $receivedQty);

                $totalReceived += $receivedQty;
            }

            // Update PO status based on received quantities
            $this->updatePurchaseOrderStatus($purchaseOrder);
        });

        return $grn;
    }

    /**
     * Generate unique GRN number
     */
    private function generateGrnNumber(): string
    {
        $prefix = 'GRN';
        $year = now()->format('Y');
        $month = now()->format('m');

        $lastGrn = Grn::where('grn_number', 'like', "{$prefix}{$year}{$month}%")
            ->orderBy('grn_number', 'desc')
            ->first();

        if ($lastGrn) {
            $lastNumber = (int) substr($lastGrn->grn_number, -4);
            $newNumber = $lastNumber + 1;
        } else {
            $newNumber = 1;
        }

        return $prefix . $year . $month . str_pad($newNumber, 4, '0', STR_PAD_LEFT);
    }

    /**
     * Update PO status based on received quantities
     */
    private function updatePurchaseOrderStatus(PurchaseOrder $purchaseOrder): void
    {
        $totalOrdered = $purchaseOrder->items->sum('ordered_qty');
        $totalReceived = $purchaseOrder->items->sum('received_qty');

        if ($totalReceived >= $totalOrdered) {
            $purchaseOrder->update(['status' => 'completed']);
        } elseif ($totalReceived > 0) {
            $purchaseOrder->update(['status' => 'partially_received']);
        }
    }

    /**
     * Get outstanding items for PO
     */
    public function getOutstandingItems(PurchaseOrder $purchaseOrder): array
    {
        $outstandingItems = [];

        foreach ($purchaseOrder->items as $poItem) {
            $remainingQty = $poItem->ordered_qty - $poItem->received_qty;

            if ($remainingQty > 0) {
                $outstandingItems[] = [
                    'po_item_id' => $poItem->id,
                    'item_id' => $poItem->item_id,
                    'item_name' => $poItem->item->name,
                    'ordered_qty' => $poItem->ordered_qty,
                    'received_qty' => $poItem->received_qty,
                    'remaining_qty' => $remainingQty,
                    'uom' => $poItem->uom->name ?? 'N/A',
                ];
            }
        }

        return $outstandingItems;
    }

    /**
     * Validate PO can be converted to GRN
     */
    public function validateForGrnConversion(PurchaseOrder $purchaseOrder): array
    {
        $errors = [];

        if ($purchaseOrder->status === 'cancelled') {
            $errors[] = 'Cannot create GRN for cancelled Purchase Order';
        }

        if ($purchaseOrder->status === 'completed') {
            $errors[] = 'Purchase Order is already completed';
        }

        $outstandingItems = $this->getOutstandingItems($purchaseOrder);
        if (empty($outstandingItems)) {
            $errors[] = 'No outstanding items to receive';
        }

        return $errors;
    }

    	public static function generatePONumber(): string
	{
		$numberService = app(\App\Services\NumberGenerationService::class);
		return $numberService->generatePONumber();
	}

    public function searchPurchaseOrders(string $search = '',$status = null): array
    {
        try {
            $query = PurchaseOrder::query();
            if (!empty($status)) {
    $query->whereIn('status', $status);
}


            if (!empty($search)) {
                $query->where(function($q) use ($search) {
                    $q->where('po_number', 'like', "%{$search}%")
                    // ->where('status','!=','closed')
                      ->orWhereHas('supplier', function($supplierQuery) use ($search) {
                          $supplierQuery->where('name', 'like', "%{$search}%");
                      });
                });
            }

            $pos = $query->orderBy('order_date', 'desc')
                ->limit(20)
                ->get();

            return $pos->map(function ($po) {
    return [
        'id' => $po->id,
        'text' => $po->po_number,  // only PO number for dropdown
        'po_number' => $po->po_number,
    ];
})->toArray();


        } catch (\Exception $e) {
            dd($e->getMessage(),$e->getLine(),$e->getFile());
            Log::error('Error searching Purchase Orders', [
                'search' => $search,
                'error' => $e->getMessage()
            ]);
            throw $e;
        }
    }
}
