<?php

namespace App\Services\Purchase;

use App\Services\BaseService;
use App\Repositories\GrnRepository;
use App\Models\Grn;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;

class GrnService extends BaseService
{
    protected GrnRepository $grnRepository;

    public function __construct(GrnRepository $repository)
    {
        parent::__construct($repository);
        $this->grnRepository = $repository;
    }

    /**
     * Get GRNs with details
     */
    public function getAllWithDetails(): Collection
    {
        return $this->grnRepository->getWithDetails();
    }

    /**
     * Get GRNs by vendor
     */
    public function getByVendor(int $vendorId): Collection
    {
        return $this->grnRepository->getByVendor($vendorId);
    }

    /**
     * Get pending GRNs
     */
    public function getPending(): Collection
    {
        return $this->grnRepository->getPending();
    }

    /**
     * Create GRN from Purchase Order
     */
    public function createFromPurchaseOrder(int $poId, array $data, array $items): Grn
    {
        return DB::transaction(function () use ($poId, $data, $items) {
            $data['purchase_order_id'] = $poId;
            $data['grn_no'] = $this->generateGrnNumber();

            $grn = $this->create($data);

            foreach ($items as $item) {
                $item['grn_id'] = $grn->id;
                $grn->items()->create($item);
            }

            $this->logAction('GRN created from PO', [
                'id' => $grn->id,
                'po_id' => $poId,
            ]);

            return $grn->fresh(['items']);
        });
    }

    /**
     * Create GRN with items
     */
    public function createWithItems(array $data, array $items): Grn
    {
        return DB::transaction(function () use ($data, $items) {
            $data['grn_no'] = $this->generateGrnNumber();
            $grn = $this->create($data);

            foreach ($items as $item) {
                $item['grn_id'] = $grn->id;
                $grn->items()->create($item);
            }

            // Update inventory
            $this->updateInventory($grn);

            $this->logAction('GRN created', ['id' => $grn->id]);
            return $grn->fresh(['items']);
        });
    }

    /**
     * Update inventory from GRN items
     */
    protected function updateInventory(Grn $grn): void
    {
        foreach ($grn->items as $item) {
            if ($item->stock_item_id) {
                $stockItem = \App\Models\StockItem::find($item->stock_item_id);
                if ($stockItem) {
                    $stockItem->increment('quantity', $item->received_qty);
                }
            }
        }
    }

    /**
     * Generate GRN number
     */
    public function generateGrnNumber(): string
    {
        $year = date('Y');
        return nextNumber("GRN/{$year}", 'grns', 'grn_no', 2);
    }

    /**
     * Approve GRN
     */
    public function approve(int $id): Grn
    {
        return DB::transaction(function () use ($id) {
            $grn = $this->findByIdOrFail($id);
            $grn->update(['status' => 'approved']);

            // Update inventory on approval
            $this->updateInventory($grn);

            $this->logAction('GRN approved', ['id' => $id]);
            return $grn->fresh();
        });
    }

    /**
     * Reject GRN
     */
    public function reject(int $id, ?string $remarks = null): Grn
    {
        return DB::transaction(function () use ($id, $remarks) {
            $grn = $this->findByIdOrFail($id);
            $grn->update([
                'status' => 'rejected',
                'remarks' => $remarks,
            ]);
            $this->logAction('GRN rejected', ['id' => $id]);
            return $grn->fresh();
        });
    }
}
