<?php

declare(strict_types=1);

/**
 * 本文件属于 DBErp 进销存系统。
 *
 * 版权所有 © 2026 北京珑大钜商科技有限公司。保留所有权利。
 *
 * 未经官方授权，不得删除、篡改或隐藏本文件中的版权声明、产品标识与来源信息。
 * 商业授权、官方更新与技术支持服务，请以珑大官方支持中心记录为准。
 *
 * @link https://support.loongdom.cn
 * @see  https://www.dberp.com.cn
 */

namespace App\Services\SupportCenter;

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

/**
 * 浏览器分步更新失败/中断时的收尾：清理会话；存在待回滚或回滚失败时保留维护模式。
 */
final class HostSystemUpdateBrowserFailureFinalizer
{
    public function __construct(
        private readonly HostSystemUpdateStepProgressStore $progressStore,
        private readonly HostSystemUpdateExecutionStateMachine $stateMachine,
        private readonly HostSystemUpdateMaintenanceModeService $maintenanceModeService,
    ) {}

    public function finalize(?string $sessionId, ?HostSystemUpdateExecution $execution = null): void
    {
        $execution = $execution?->fresh(['package', 'backups', 'logs'])
            ?? $this->resolveExecutionFromSession($sessionId)
            ?? $this->resolveLatestActiveExecution();

        if ($execution instanceof HostSystemUpdateExecution) {
            if ($this->shouldRemainInMaintenanceForRecovery($execution)) {
                $this->closeOpenStepSession($sessionId);

                return;
            }

            $this->markInterruptedIfStillActive($execution);
            $execution = $execution->fresh(['package', 'backups', 'logs']) ?? $execution;
            $this->maintenanceModeService->attemptLeaveMaintenanceOnFailure($execution);
        } else {
            $this->maintenanceModeService->attemptLeaveMaintenanceOnFailure(null);
        }

        $this->closeOpenStepSession($sessionId);
    }

    private function shouldRemainInMaintenanceForRecovery(HostSystemUpdateExecution $execution): bool
    {
        if (method_exists($this->maintenanceModeService, 'shouldRemainInMaintenanceForRecovery')) {
            return $this->maintenanceModeService->shouldRemainInMaintenanceForRecovery($execution);
        }

        return in_array((string) ($execution->status ?? ''), [
            HostSystemUpdateExecutionStatus::RollbackRequired->value,
            HostSystemUpdateExecutionStatus::RollingBack->value,
            HostSystemUpdateExecutionStatus::RollbackFailed->value,
            HostSystemUpdateExecutionStatus::ManualRecoveryRequired->value,
        ], true);
    }

    private function markInterruptedIfStillActive(HostSystemUpdateExecution $execution): void
    {
        $status = (string) ($execution->status ?? '');

        if (! in_array($status, HostSystemUpdateExecutionStatus::activeValues(), true)) {
            return;
        }

        $this->stateMachine->fail(
            $execution,
            'host_system_update_browser_interrupted',
            (string) __('dberp.system_update_center.errors.browser_update_interrupted'),
            ['source' => 'browser_failure_finalizer'],
        );
    }

    private function closeOpenStepSession(?string $sessionId): void
    {
        if ($sessionId === null || $sessionId === '') {
            return;
        }

        $progress = $this->progressStore->read($sessionId);

        if ($progress === null) {
            return;
        }

        if (! $progress->terminal) {
            $this->progressStore->markTerminal(
                $progress,
                failed: true,
                errorMessage: (string) __('dberp.system_update_center.errors.browser_update_interrupted'),
            );
        }

        $this->progressStore->delete($sessionId);
    }

    private function resolveExecutionFromSession(?string $sessionId): ?HostSystemUpdateExecution
    {
        if ($sessionId === null || $sessionId === '') {
            return null;
        }

        $progress = $this->progressStore->read($sessionId);
        $executionNo = $progress?->executionNo;

        if (! is_string($executionNo) || $executionNo === '') {
            return null;
        }

        return HostSystemUpdateExecution::query()
            ->where('execution_no', $executionNo)
            ->first();
    }

    private function resolveLatestActiveExecution(): ?HostSystemUpdateExecution
    {
        return HostSystemUpdateExecution::query()
            ->whereIn('status', HostSystemUpdateExecutionStatus::activeValues())
            ->latest('id')
            ->first();
    }
}
