<?php

declare(strict_types=1);

namespace App\Services\SupportCenter;

use App\Enums\SupportCenter\HostSystemUpdateExecutionStatus;
use App\Enums\SupportCenter\HostSystemUpdateExecutionStep;
use App\Enums\SupportCenter\HostSystemUpdateStepPhase;
use App\Models\HostSystemUpdateExecution;

/**
 * 将既有执行任务状态映射为 {@see HostSystemUpdateStepRunner} 可续跑的分步阶段。
 */
final class HostSystemUpdateExecutionResumePhaseResolver
{
    public function __construct(
        private readonly HostSystemUpdateMigrationBatchRunner $migrationBatchRunner,
        private readonly HostSystemUpdateBatchPhaseRunner $batchPhaseRunner,
    ) {}

    public function resolve(HostSystemUpdateExecution $execution): HostSystemUpdateExecutionResumeState
    {
        $step = HostSystemUpdateExecutionStep::tryFrom((string) ($execution->current_step ?? ''));
        $status = HostSystemUpdateExecutionStatus::tryFrom((string) ($execution->status ?? ''));

        $phase = $this->resolvePhase($status, $step);

        if ($phase === HostSystemUpdateStepPhase::MigrateBatch) {
            $execution = $execution->fresh(['package']) ?? $execution;

            return new HostSystemUpdateExecutionResumeState(
                phase: HostSystemUpdateStepPhase::MigrateBatch,
                migrationProgress: $this->migrationBatchRunner->snapshotProgress($execution),
                migratePhaseComplete: false,
            );
        }

        if ($this->isBatchablePhase($phase)) {
            $batchProgress = $this->batchPhaseRunner->snapshotProgress($execution, $phase);

            if ($batchProgress !== null && ! $batchProgress->isCompleted()) {
                return new HostSystemUpdateExecutionResumeState(
                    phase: $phase,
                    batchProgress: $batchProgress,
                );
            }
        }

        return new HostSystemUpdateExecutionResumeState(phase: $phase);
    }

    private function isBatchablePhase(HostSystemUpdateStepPhase $phase): bool
    {
        return match ($phase) {
            HostSystemUpdateStepPhase::ExtractStaging,
            HostSystemUpdateStepPhase::Backup,
            HostSystemUpdateStepPhase::ReplaceFiles,
            HostSystemUpdateStepPhase::ReplaceVendor => true,
            default => false,
        };
    }

    private function resolvePhase(
        ?HostSystemUpdateExecutionStatus $status,
        ?HostSystemUpdateExecutionStep $step,
    ): HostSystemUpdateStepPhase {
        if ($step !== null) {
            $fromStep = $this->phaseFromExecutionStep($step);

            if ($fromStep !== null) {
                return $fromStep;
            }
        }

        return match ($status) {
            HostSystemUpdateExecutionStatus::Prechecking => HostSystemUpdateStepPhase::Precheck,
            HostSystemUpdateExecutionStatus::Ready => HostSystemUpdateStepPhase::ExtractStaging,
            default => HostSystemUpdateStepPhase::MaintenanceDown,
        };
    }

    private function phaseFromExecutionStep(HostSystemUpdateExecutionStep $step): ?HostSystemUpdateStepPhase
    {
        return match ($step) {
            HostSystemUpdateExecutionStep::Created => HostSystemUpdateStepPhase::MaintenanceDown,
            HostSystemUpdateExecutionStep::MaintenanceDown => HostSystemUpdateStepPhase::Precheck,
            HostSystemUpdateExecutionStep::Precheck => HostSystemUpdateStepPhase::Precheck,
            HostSystemUpdateExecutionStep::ExtractStaging,
            HostSystemUpdateExecutionStep::VerifyStaging => HostSystemUpdateStepPhase::ExtractStaging,
            HostSystemUpdateExecutionStep::Backup => HostSystemUpdateStepPhase::Backup,
            HostSystemUpdateExecutionStep::ReplaceFiles => HostSystemUpdateStepPhase::ReplaceFiles,
            HostSystemUpdateExecutionStep::ReplaceVendor => HostSystemUpdateStepPhase::ReplaceVendor,
            HostSystemUpdateExecutionStep::RunMigrations => HostSystemUpdateStepPhase::MigrateBatch,
            HostSystemUpdateExecutionStep::ClearCache => HostSystemUpdateStepPhase::ClearCache,
            HostSystemUpdateExecutionStep::WriteVersion => HostSystemUpdateStepPhase::WriteVersion,
            HostSystemUpdateExecutionStep::MaintenanceUp => HostSystemUpdateStepPhase::Complete,
            default => null,
        };
    }
}
