<?php

namespace App\Services;

use App\Models\PurchaseOrder;
use App\Repositories\Eloquent\PurchaseOrderRepository;
use Illuminate\Support\Facades\DB;

class PurchaseOrderService
{
    public function __construct(
        protected PurchaseOrderRepository $purchaseOrderRepository,
        protected InventoryService $inventoryService,
        protected LoggingService $loggingService
    ) {}

    public function getAll()
    {
        $this->loggingService->logInfo('Fetching all purchase orders');
        return $this->purchaseOrderRepository->all();
    }

    public function getForBranch(int $branchId)
    {
        $this->loggingService->logInfo('Fetching purchase orders for branch', ['branch_id' => $branchId]);
        return $this->purchaseOrderRepository->getForBranch($branchId);
    }

    public function getByStatus(int $branchId, string $status)
    {
        $this->loggingService->logInfo('Fetching purchase orders by status', [
            'branch_id' => $branchId,
            'status' => $status
        ]);
        return $this->purchaseOrderRepository->getByStatus($branchId, $status);
    }

    public function getPending(int $branchId)
    {
        $this->loggingService->logInfo('Fetching pending purchase orders', ['branch_id' => $branchId]);
        return $this->purchaseOrderRepository->getPending($branchId);
    }

    public function find(int $id)
    {
        $this->loggingService->logInfo('Finding purchase order', ['id' => $id]);
        return $this->purchaseOrderRepository->findWithItems($id);
    }

    public function create(array $data)
    {
        $this->loggingService->logInfo('Creating purchase order', ['data' => $data]);

        return DB::transaction(function () use ($data) {
            $items = $data['items'] ?? [];
            unset($data['items']);

            $data['po_number'] = PurchaseOrder::generatePoNumber();
            $data['status'] = $data['status'] ?? PurchaseOrder::STATUS_DRAFT;

            $po = $this->purchaseOrderRepository->create($data);

            foreach ($items as $item) {
                $po->items()->create([
                    'ingredient_id' => $item['ingredient_id'],
                    'quantity_ordered' => $item['quantity_ordered'],
                    'unit_cost' => $item['unit_cost'],
                    'total_cost' => $item['quantity_ordered'] * $item['unit_cost'],
                ]);
            }

            return $po->fresh(['items.ingredient', 'branch', 'user']);
        });
    }

    public function update(int $id, array $data)
    {
        $this->loggingService->logInfo('Updating purchase order', ['id' => $id, 'data' => $data]);

        return DB::transaction(function () use ($id, $data) {
            $items = $data['items'] ?? null;
            unset($data['items']);

            $po = $this->purchaseOrderRepository->update($id, $data);

            if ($items !== null) {
                // Delete existing items and recreate
                $po->items()->delete();
                foreach ($items as $item) {
                    $po->items()->create([
                        'ingredient_id' => $item['ingredient_id'],
                        'quantity_ordered' => $item['quantity_ordered'],
                        'unit_cost' => $item['unit_cost'],
                        'total_cost' => $item['quantity_ordered'] * $item['unit_cost'],
                    ]);
                }
            }

            return $po->fresh(['items.ingredient', 'branch', 'user']);
        });
    }

    public function delete(int $id)
    {
        $this->loggingService->logInfo('Deleting purchase order', ['id' => $id]);
        return $this->purchaseOrderRepository->delete($id);
    }

    public function updateStatus(int $id, string $status)
    {
        $this->loggingService->logInfo('Updating purchase order status', ['id' => $id, 'status' => $status]);

        $po = $this->purchaseOrderRepository->find($id);
        if (!$po) {
            return null;
        }

        return $this->purchaseOrderRepository->update($id, ['status' => $status]);
    }

    public function receive(int $id, array $receivedItems, int $userId)
    {
        $this->loggingService->logInfo('Receiving purchase order', ['id' => $id, 'items' => $receivedItems]);

        $po = $this->purchaseOrderRepository->findWithItems($id);
        if (!$po || !$po->canBeReceived()) {
            return null;
        }

        return DB::transaction(function () use ($po, $receivedItems, $userId) {
            foreach ($receivedItems as $receivedItem) {
                $poItem = $po->items->find($receivedItem['item_id']);
                if (!$poItem) {
                    continue;
                }

                $quantityReceived = $receivedItem['quantity_received'];

                // Update PO item
                $poItem->update([
                    'quantity_received' => $poItem->quantity_received + $quantityReceived,
                ]);

                // Add stock
                $this->inventoryService->addStock(
                    $po->branch_id,
                    $poItem->ingredient_id,
                    $quantityReceived,
                    $poItem->unit_cost,
                    $userId,
                    "Received from PO #{$po->po_number}",
                    'purchase_order',
                    $po->id
                );
            }

            // Check if all items are fully received
            $allReceived = $po->fresh()->items->every(fn ($item) => $item->isFullyReceived());

            $this->purchaseOrderRepository->update($po->id, [
                'status' => $allReceived ? PurchaseOrder::STATUS_RECEIVED : $po->status,
                'received_at' => $allReceived ? now() : $po->received_at,
            ]);

            return $po->fresh(['items.ingredient', 'branch', 'user']);
        });
    }

    public function cancel(int $id)
    {
        $this->loggingService->logInfo('Cancelling purchase order', ['id' => $id]);
        return $this->purchaseOrderRepository->update($id, ['status' => PurchaseOrder::STATUS_CANCELLED]);
    }
}
