<?php

namespace App\Modules\Procurement\Services;

use App\Modules\Inventory\Stock\Services\InventoryStockAdvisoryLock;
use Illuminate\Support\Facades\DB;

/**
 * Entry: GET_LOCK(proc post idempotency) then DB transaction + {@see GoodsReceiptPostingExecutor}.
 */
final class GoodsReceiptPostingService
{
    public function __construct(
        private readonly GoodsReceiptPostingExecutor $executor,
        private readonly InventoryStockAdvisoryLock $advisoryLock,
    ) {}

    /**
     * @return array<string, mixed>
     */
    public function postValidatedReceipt(
        int $tenantId,
        int $goodsReceiptId,
        string $idempotencyKey,
        string $idempotencySource,
        ?int $actorUserId,
        ?string $correlationId,
    ): array {
        if ($idempotencyKey === '') {
            throw new \InvalidArgumentException('receipt_post_idempotency_key_required');
        }
        $advisoryKey = 'proc-post:'.$tenantId.':'.$idempotencySource.':'.$idempotencyKey;

        return $this->advisoryLock->runWithLock($advisoryKey, function () use (
            $tenantId,
            $goodsReceiptId,
            $idempotencyKey,
            $idempotencySource,
            $actorUserId,
            $correlationId,
        ) {
            $attempts = (int) config('inventory.transaction_attempts', 5);

            return DB::transaction(function () use (
                $tenantId,
                $goodsReceiptId,
                $idempotencyKey,
                $idempotencySource,
                $actorUserId,
                $correlationId,
            ) {
                return $this->executor->executePost(
                    $tenantId,
                    $goodsReceiptId,
                    $idempotencyKey,
                    $idempotencySource,
                    $actorUserId,
                    $correlationId,
                );
            }, $attempts);
        });
    }
}
