<?php

namespace App\Modules\Procurement\Services;

use App\Modules\Procurement\Models\GoodsReceipt;
use App\Modules\Procurement\Models\GoodsReceiptItem;
use App\Modules\Procurement\Models\PurchaseOrderItem;
use App\Modules\Procurement\Support\GoodsReceiptViolationCode;
final class GoodsReceiptQuarantineService
{
    public function __construct(
        private readonly GoodsReceiptObservability $obs,
    ) {}

    /**
     * @return array{quarantined:int, scanned:int}
     */
    public function quarantineInvalidLinesOnReceipt(int $tenantId, int $goodsReceiptId): array
    {
        $receipt = GoodsReceipt::withoutGlobalScopes()
            ->where('tenant_id', $tenantId)
            ->whereKey($goodsReceiptId)
            ->first();
        if ($receipt === null) {
            return ['quarantined' => 0, 'scanned' => 0];
        }

        $quarantined = 0;
        $lines = GoodsReceiptItem::withoutGlobalScopes()
            ->where('tenant_id', $tenantId)
            ->where('goods_receipt_id', $goodsReceiptId)
            ->whereNull('quarantined_at')
            ->orderBy('id')
            ->get();

        foreach ($lines as $line) {
            $code = $this->classify($receipt, (int) $line->purchase_order_item_id, $tenantId);
            if ($code === null) {
                continue;
            }
            $line->forceFill([
                'quarantined_at' => now(),
                'integrity_violation_code' => $code,
            ])->save();
            $quarantined++;
            $this->obs->hydrationQuarantine([
                'goods_receipt_item_id' => $line->id,
                'goods_receipt_id' => $line->goods_receipt_id,
                'code' => $code,
            ]);
        }

        return ['quarantined' => $quarantined, 'scanned' => $lines->count()];
    }

    private function classify(GoodsReceipt $receipt, int $purchaseOrderItemId, int $tenantId): ?string
    {
        $poi = PurchaseOrderItem::withoutGlobalScopes()->withTrashed()->find($purchaseOrderItemId);
        if ($poi === null) {
            $this->obs->orphanDetected([
                'goods_receipt_id' => $receipt->id,
                'purchase_order_item_id' => $purchaseOrderItemId,
            ]);

            return GoodsReceiptViolationCode::MISSING_PO_ITEM;
        }
        if ((int) $poi->tenant_id !== $tenantId) {
            $this->obs->invalidReceiptLine('tenant_mismatch', ['goods_receipt_id' => $receipt->id]);

            return GoodsReceiptViolationCode::MISSING_PO_ITEM;
        }
        if ($poi->trashed()) {
            $this->obs->invalidReceiptLine('deleted_po_item', [
                'goods_receipt_id' => $receipt->id,
                'purchase_order_item_id' => $poi->id,
            ]);

            return GoodsReceiptViolationCode::DELETED_PO_ITEM;
        }
        if ((int) $poi->purchase_order_id !== (int) $receipt->purchase_order_id) {
            $this->obs->crossPoReceiptContamination([
                'goods_receipt_id' => $receipt->id,
                'receipt_purchase_order_id' => $receipt->purchase_order_id,
                'line_purchase_order_id' => $poi->purchase_order_id,
            ]);

            return GoodsReceiptViolationCode::CROSS_PO;
        }

        return null;
    }
}
