<?php

namespace Modules\Procurement\Services;

use App\Models\ActivityLogModel;
use App\Models\GoodsReceiptLineModel;
use App\Models\GoodsReceiptModel;
use App\Models\PurchaseOrderLineModel;
use App\Models\PurchaseOrderModel;
use App\Models\SupplierModel;

class GoodsReceiptService
{
    protected GoodsReceiptModel $receipts;
    protected GoodsReceiptLineModel $lines;
    protected PurchaseOrderModel $orders;
    protected PurchaseOrderLineModel $orderLines;
    protected SupplierModel $suppliers;
    protected ActivityLogModel $activity;

    public function __construct()
    {
        $this->receipts   = new GoodsReceiptModel();
        $this->lines      = new GoodsReceiptLineModel();
        $this->orders     = new PurchaseOrderModel();
        $this->orderLines = new PurchaseOrderLineModel();
        $this->suppliers  = new SupplierModel();
        $this->activity   = new ActivityLogModel();
    }

    public function create(array $input, ?int $actingUserId): array
    {
        $orderId = (int) ($input['purchase_order_id'] ?? 0);
        $order = $this->orders->find($orderId);
        if (! $order) {
            return ['success' => false, 'errors' => ['purchase_order_id' => 'Purchase order not found.']];
        }

        $supplierId = (int) ($input['supplier_id'] ?? $order['supplier_id']);
        if (! $this->suppliers->find($supplierId)) {
            return ['success' => false, 'errors' => ['supplier_id' => 'Supplier not found.']];
        }

        $data = $this->mapInput($input, $order);
        $data['number']     = $this->receipts->nextNumber();
        $data['status']     = 'draft';
        $data['created_by'] = $actingUserId;
        $data['updated_by'] = $actingUserId;

        if (! $this->receipts->insert($data, true)) {
            return ['success' => false, 'errors' => $this->receipts->errors()];
        }

        $id = (int) $this->receipts->getInsertID();
        $this->lines->replaceForGoodsReceipt($id, $input['lines'] ?? []);
        $this->activity->log('goods_receipts', 'created', $actingUserId, "Created goods receipt #{$id} ({$data['number']})", (string) $id);

        return ['success' => true, 'id' => $id];
    }

    public function createFromOrder(int $orderId, ?int $actingUserId): array
    {
        $order = $this->orders->find($orderId);
        if (! $order) {
            return ['success' => false, 'error' => 'Purchase order not found.'];
        }
        if (! in_array($order['status'], ['approved', 'confirmed'], true)) {
            return ['success' => false, 'error' => 'Order must be approved before creating a goods receipt.'];
        }

        $oLines = $this->orderLines->getForPurchaseOrder($orderId);
        $lines = [];
        foreach ($oLines as $line) {
            $lines[] = [
                'item_code' => $line['item_code'],
                'item_name' => $line['item_name'],
                'quantity'  => $line['quantity'],
                'unit'      => $line['unit'],
            ];
        }

        return $this->create([
            'purchase_order_id' => $orderId,
            'supplier_id'       => $order['supplier_id'],
            'receipt_date'      => date('Y-m-d'),
            'notes'             => $order['notes'],
            'lines'             => $lines,
        ], $actingUserId);
    }

    public function update(int $id, array $input, ?int $actingUserId): array
    {
        $receipt = $this->receipts->find($id);
        if (! $receipt) {
            return ['success' => false, 'errors' => ['id' => 'Goods receipt not found.']];
        }
        if ($receipt['status'] !== 'draft') {
            return ['success' => false, 'errors' => ['status' => 'Only draft goods receipts can be edited.']];
        }

        $orderId = (int) ($input['purchase_order_id'] ?? $receipt['purchase_order_id']);
        $order = $this->orders->find($orderId);
        if (! $order) {
            return ['success' => false, 'errors' => ['purchase_order_id' => 'Purchase order not found.']];
        }

        $data = $this->mapInput($input, $order);
        $data['updated_by'] = $actingUserId;

        if (! $this->receipts->update($id, $data)) {
            return ['success' => false, 'errors' => $this->receipts->errors()];
        }

        $this->lines->replaceForGoodsReceipt($id, $input['lines'] ?? []);
        $this->activity->log('goods_receipts', 'updated', $actingUserId, "Updated goods receipt #{$id}", (string) $id);

        return ['success' => true];
    }

    public function post(int $id, ?int $actingUserId): array
    {
        $receipt = $this->receipts->find($id);
        if (! $receipt) {
            return ['success' => false, 'error' => 'Goods receipt not found.'];
        }
        if ($receipt['status'] !== 'draft') {
            return ['success' => false, 'error' => 'Only draft goods receipts can be posted.'];
        }

        $this->receipts->update($id, [
            'status'     => 'posted',
            'posted_by'  => $actingUserId,
            'posted_at'  => date('Y-m-d H:i:s'),
            'updated_by' => $actingUserId,
        ]);
        $this->activity->log('goods_receipts', 'posted', $actingUserId, "Posted goods receipt #{$id}", (string) $id);

        return ['success' => true];
    }

    public function cancel(int $id, ?int $actingUserId): array
    {
        $receipt = $this->receipts->find($id);
        if (! $receipt) {
            return ['success' => false, 'error' => 'Goods receipt not found.'];
        }
        if ($receipt['status'] === 'cancelled') {
            return ['success' => false, 'error' => 'Goods receipt is already cancelled.'];
        }
        if ($receipt['status'] === 'posted') {
            return ['success' => false, 'error' => 'Posted goods receipts cannot be cancelled.'];
        }

        $this->receipts->update($id, ['status' => 'cancelled', 'updated_by' => $actingUserId]);
        $this->activity->log('goods_receipts', 'cancelled', $actingUserId, "Cancelled goods receipt #{$id}", (string) $id);

        return ['success' => true];
    }

    public function delete(int $id, ?int $actingUserId): array
    {
        $receipt = $this->receipts->find($id);
        if (! $receipt) {
            return ['success' => false, 'error' => 'Goods receipt not found.'];
        }
        if (! in_array($receipt['status'], ['draft', 'cancelled'], true)) {
            return ['success' => false, 'error' => 'Only draft or cancelled goods receipts can be deleted.'];
        }

        $this->lines->where('goods_receipt_id', $id)->delete();
        $this->receipts->delete($id);
        $this->activity->log('goods_receipts', 'deleted', $actingUserId, "Deleted goods receipt #{$id}", (string) $id);

        return ['success' => true];
    }

    protected function mapInput(array $input, array $order): array
    {
        return [
            'purchase_order_id' => (int) ($input['purchase_order_id'] ?? $order['id']),
            'supplier_id'       => (int) ($input['supplier_id'] ?? $order['supplier_id']),
            'receipt_date'      => $input['receipt_date'] ?? date('Y-m-d'),
            'notes'             => ! empty($input['notes']) ? $input['notes'] : null,
        ];
    }
}
