<?php

namespace App\Modules\Inventory\Reservation\Console;

use App\Modules\Admin\Tenancy\Services\TenantContext;
use App\Modules\Inventory\Reservation\DTOs\ReleaseInventoryInput;
use App\Modules\Inventory\Reservation\Repositories\InventoryReservationMovementRepository;
use App\Modules\Inventory\Reservation\Services\InventoryReservationObservability;
use App\Modules\Inventory\Reservation\Services\ReleaseInventoryService;
use App\Modules\Inventory\Stock\Support\DecimalQuantity;
use Illuminate\Console\Command;

class InventoryReservationExpirationSweepCommand extends Command
{
    protected $signature = 'inventory:reservation:sweep-expired {tenant? : Limit to tenant id}';

    protected $description = 'Release open quantities for expired reservations (replay-safe per reservation idempotency key)';

    public function handle(
        TenantContext $ctx,
        InventoryReservationMovementRepository $movements,
        ReleaseInventoryService $release,
        InventoryReservationObservability $obs,
    ): int {
        $tenantArg = $this->argument('tenant');
        $tenantFilter = $tenantArg !== null ? (int) $tenantArg : null;
        if ($tenantFilter !== null) {
            $ctx->setTenantId($tenantFilter);
        }

        $processed = 0;
        foreach ($movements->distinctExpiredReserveHeads($tenantFilter) as $head) {
            $tid = $head['tenant_id'];
            $ctx->setTenantId($tid);

            $rid = $head['reservation_public_id'];
            $open = $movements->sumOpenQuantity($tid, $rid);
            if (! DecimalQuantity::gtZero($open)) {
                $obs->staleReservation(['tenant_id' => $tid, 'reservation_public_id' => $rid]);

                continue;
            }

            try {
                $release->release(new ReleaseInventoryInput(
                    tenantId: $tid,
                    warehouseId: $head['warehouse_id'],
                    itemId: $head['item_id'],
                    reservationPublicId: $rid,
                    quantity: $open,
                    actorUserId: null,
                    correlationId: null,
                    idempotencyKey: 'expire:'.$rid,
                    idempotencySource: 'expiration_sweep_v1',
                    sourceType: 'expiration_sweep',
                    sourceId: null,
                    metadata: ['reason' => 'expired_sweep'],
                ));
            } catch (\Throwable $e) {
                $obs->allocationFailure('expiration_sweep_failed', [
                    'tenant_id' => $tid,
                    'reservation_public_id' => $rid,
                    'error' => $e->getMessage(),
                ]);
                throw $e;
            }
            $processed++;
        }

        $this->info('Sweep pass processed: '.$processed);

        return self::SUCCESS;
    }
}
