<?php

declare(strict_types=1);

namespace App\Support\Operations;

use App\Models\OperationRun;
use App\Support\OperationRunStatus;

enum OperationRunFreshnessState: string
{
    case FreshActive = 'fresh_active';
    case LikelyStale = 'likely_stale';
    case ReconciledFailed = 'reconciled_failed';
    case TerminalNormal = 'terminal_normal';
    case Unknown = 'unknown';

    public static function forRun(OperationRun $run, ?OperationLifecyclePolicy $policy = null): self
    {
        $policy ??= app(OperationLifecyclePolicy::class);

        if ((string) $run->status === OperationRunStatus::Completed->value) {
            return $run->isLifecycleReconciled() ? self::ReconciledFailed : self::TerminalNormal;
        }

        if (! $policy->supports((string) $run->type)) {
            return self::Unknown;
        }

        if ((string) $run->status === OperationRunStatus::Queued->value) {
            if ($run->started_at !== null || $run->created_at === null) {
                return self::Unknown;
            }

            return $run->created_at->lte(now()->subSeconds($policy->queuedStaleAfterSeconds((string) $run->type)))
                ? self::LikelyStale
                : self::FreshActive;
        }

        if ((string) $run->status === OperationRunStatus::Running->value) {
            $startedAt = $run->started_at ?? $run->created_at;

            if ($startedAt === null) {
                return self::Unknown;
            }

            return $startedAt->lte(now()->subSeconds($policy->runningStaleAfterSeconds((string) $run->type)))
                ? self::LikelyStale
                : self::FreshActive;
        }

        return self::Unknown;
    }

    public function isFreshActive(): bool
    {
        return $this === self::FreshActive;
    }

    public function isLikelyStale(): bool
    {
        return $this === self::LikelyStale;
    }

    public function isReconciledFailed(): bool
    {
        return $this === self::ReconciledFailed;
    }
}
