<?php

declare(strict_types=1);

namespace App\Support\SystemConsole;

use App\Models\OperationRun;
use App\Support\OperationRunStatus;
use Carbon\CarbonImmutable;
use Illuminate\Database\Eloquent\Builder;

final class StuckRunClassifier
{
    public function __construct(
        private readonly int $queuedThresholdMinutes = 0,
        private readonly int $runningThresholdMinutes = 0,
    ) {}

    public function queuedThresholdMinutes(): int
    {
        if ($this->queuedThresholdMinutes > 0) {
            return $this->queuedThresholdMinutes;
        }

        return max(1, (int) config('tenantpilot.system_console.stuck_thresholds.queued_minutes', 15));
    }

    public function runningThresholdMinutes(): int
    {
        if ($this->runningThresholdMinutes > 0) {
            return $this->runningThresholdMinutes;
        }

        return max(1, (int) config('tenantpilot.system_console.stuck_thresholds.running_minutes', 30));
    }

    public function apply(Builder $query, ?CarbonImmutable $now = null): Builder
    {
        $now ??= CarbonImmutable::now();

        $queuedCutoff = $now->subMinutes($this->queuedThresholdMinutes());
        $runningCutoff = $now->subMinutes($this->runningThresholdMinutes());

        return $query->where(function (Builder $stuckQuery) use ($queuedCutoff, $runningCutoff): void {
            $stuckQuery
                ->where(function (Builder $queuedQuery) use ($queuedCutoff): void {
                    $queuedQuery
                        ->where('status', OperationRunStatus::Queued->value)
                        ->whereNull('started_at')
                        ->where('created_at', '<=', $queuedCutoff);
                })
                ->orWhere(function (Builder $runningQuery) use ($runningCutoff): void {
                    $runningQuery
                        ->where('status', OperationRunStatus::Running->value)
                        ->where('started_at', '<=', $runningCutoff);
                });
        });
    }

    public function classify(OperationRun $run, ?CarbonImmutable $now = null): ?string
    {
        $now ??= CarbonImmutable::now();

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

            if ($run->created_at === null) {
                return null;
            }

            return $run->created_at->lte($now->subMinutes($this->queuedThresholdMinutes()))
                ? OperationRunStatus::Queued->value
                : null;
        }

        if ($run->status === OperationRunStatus::Running->value && $run->started_at !== null) {
            return $run->started_at->lte($now->subMinutes($this->runningThresholdMinutes()))
                ? OperationRunStatus::Running->value
                : null;
        }

        return null;
    }
}
