<?php

declare(strict_types=1);

namespace App\Services\SupportCenter;

use App\Enums\SupportCenter\HostSystemUpdateExecutionStatus;
use App\Exceptions\SupportCenter\HostSystemUpdateExecutionException;
use App\Models\HostSystemUpdateExecution;

/**
 * 防止并发创建或并行运行多个系统更新执行任务。
 */
final class HostSystemUpdateExecutionLock
{
    public function findActiveExecution(): ?HostSystemUpdateExecution
    {
        return HostSystemUpdateExecution::query()
            ->whereIn('status', HostSystemUpdateExecutionStatus::activeValues())
            ->orderByDesc('id')
            ->lockForUpdate()
            ->first();
    }

    public function assertNoActiveExecution(): void
    {
        $active = HostSystemUpdateExecution::query()
            ->whereIn('status', HostSystemUpdateExecutionStatus::activeValues())
            ->orderByDesc('id')
            ->first();

        if ($active instanceof HostSystemUpdateExecution) {
            throw HostSystemUpdateExecutionException::activeExecutionExists((string) $active->execution_no);
        }
    }

    public function acquire(HostSystemUpdateExecution $execution, string $lockOwner): HostSystemUpdateExecution
    {
        $execution->fill([
            'locked_at' => now()->utc(),
            'lock_owner' => $lockOwner,
        ]);
        $execution->save();

        return $execution->fresh() ?? $execution;
    }

    public function release(HostSystemUpdateExecution $execution): HostSystemUpdateExecution
    {
        $execution->fill([
            'locked_at' => null,
            'lock_owner' => null,
        ]);
        $execution->save();

        return $execution->fresh() ?? $execution;
    }
}
