<?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\HostSystemUpdateStepPhase;
use App\Exceptions\SupportCenter\HostSystemUpdateFileExecutionException;
use App\Models\HostSystemUpdateExecution;

/**
 * 编排 staging 文件替换、删除与 vendor 策略（不执行 migrate/cache/版本写入）。
 */
final class HostSystemUpdateApplyService
{
    public function __construct(
        private readonly HostSystemUpdateExecutionStateMachine $stateMachine,
        private readonly HostSystemUpdateBatchPhaseRunner $batchPhaseRunner,
    ) {}

    public function applyStagedChanges(HostSystemUpdateExecution $execution): HostSystemUpdateExecution
    {
        return $this->applyVendorPhase($this->applyFilesPhase($execution));
    }

    public function applyFilesPhase(HostSystemUpdateExecution $execution): HostSystemUpdateExecution
    {
        $partialChangesApplied = false;

        try {
            $execution = $this->runBatchesUntilComplete(
                $execution->fresh(['package', 'backups']) ?? $execution,
                HostSystemUpdateStepPhase::ReplaceFiles,
            );

            return $execution->fresh(['package', 'backups']) ?? $execution;
        } catch (HostSystemUpdateFileExecutionException $exception) {
            $this->handleFileExecutionFailure($execution, $exception, $exception->partialChangesApplied());

            throw $exception;
        }
    }

    public function applyVendorPhase(HostSystemUpdateExecution $execution): HostSystemUpdateExecution
    {
        try {
            $execution = $this->runBatchesUntilComplete(
                $execution->fresh(['package', 'backups']) ?? $execution,
                HostSystemUpdateStepPhase::ReplaceVendor,
            );

            return $execution->fresh(['package', 'backups']) ?? $execution;
        } catch (HostSystemUpdateFileExecutionException $exception) {
            $this->handleFileExecutionFailure($execution, $exception, false);

            throw $exception;
        }
    }

    private function handleFileExecutionFailure(
        HostSystemUpdateExecution $execution,
        HostSystemUpdateFileExecutionException $exception,
        bool $partialChangesApplied,
    ): void {
        $fresh = $execution->fresh() ?? $execution;
        $shouldRollback = $partialChangesApplied || $exception->partialChangesApplied();

        if ($shouldRollback) {
            $this->stateMachine->requireRollback(
                $fresh,
                $exception->errorCode(),
                $exception->userFacingMessage(),
                ['partial_changes_applied' => true],
            );
        } else {
            $this->stateMachine->fail(
                $fresh,
                $exception->errorCode(),
                $exception->userFacingMessage(),
            );
        }

    }

    private function runBatchesUntilComplete(
        HostSystemUpdateExecution $execution,
        HostSystemUpdateStepPhase $phase,
    ): HostSystemUpdateExecution {
        while (! $this->batchPhaseRunner->isPhaseComplete($execution, $phase)) {
            $result = $this->batchPhaseRunner->runNextBatch($execution, $phase);
            $execution = $result->execution ?? $execution;
        }

        $this->batchPhaseRunner->clearPhaseProgress($execution, $phase);

        return $execution;
    }
}
