<?php

declare(strict_types=1);

namespace App\Console\Commands;

use App\Exceptions\SupportCenter\HostSystemUpdateExecutionException;
use App\Exceptions\SupportCenter\HostSystemUpdateFileExecutionException;
use App\Exceptions\SupportCenter\HostSystemUpdatePostApplyException;
use App\Exceptions\SupportCenter\HostSystemUpdateRecoveryException;
use App\Exceptions\SupportCenter\HostSystemUpdateStagingException;
use App\Exceptions\SupportCenter\SupportCenterException;
use App\Services\SupportCenter\HostSystemUpdateBatchProgress;
use App\Services\SupportCenter\HostSystemUpdateCliRunException;
use App\Services\SupportCenter\HostSystemUpdateCliRunnerService;
use App\Services\SupportCenter\HostSystemUpdateMigrationProgress;
use App\Services\SupportCenter\HostSystemUpdateStepResult;
use DomainException;
use Illuminate\Console\Command;
use Throwable;

/**
 * 在服务器终端执行系统更新：可从头完整执行，或续跑指定任务编号（与 Web 分步链一致）。
 */
final class DberpSystemUpdateRunCommand extends Command
{
    protected $signature = 'dberp:system-update:run
                            {execution_no? : 省略则从检查官方版本开始完整更新；提供编号则续跑该任务}';

    protected $description = '在命令行中执行 DBErp 系统更新（完整流程或续跑指定任务）';

    public function handle(HostSystemUpdateCliRunnerService $runner): int
    {
        $executionNo = trim((string) ($this->argument('execution_no') ?? ''));

        if ($executionNo === '') {
            $this->info((string) __('dberp.system_update_center.cli.output.full_started'));
        } else {
            $this->info((string) __('dberp.system_update_center.cli.output.started', [
                'execution_no' => $executionNo,
            ]));
        }

        try {
            $result = $executionNo === ''
                ? $runner->runFull(function (HostSystemUpdateStepResult $stepResult) use ($runner): void {
                    $this->reportStepProgress($runner, $stepResult);
                })
                : $runner->run(
                    $executionNo,
                    function (HostSystemUpdateStepResult $stepResult) use ($runner): void {
                        $this->reportStepProgress($runner, $stepResult);
                    },
                );

            if ($result->succeeded) {
                $this->info($result->message);

                return self::SUCCESS;
            }

            $this->error($result->message);

            if ($result->recoverySuggestion !== null && $result->recoverySuggestion !== '') {
                $this->warn($result->recoverySuggestion);
            }

            return self::FAILURE;
        } catch (HostSystemUpdateCliRunException $exception) {
            $this->error($exception->userFacingMessage());

            if ($exception->recoverySuggestion() !== null && $exception->recoverySuggestion() !== '') {
                $this->warn($exception->recoverySuggestion());
            }

            return self::FAILURE;
        } catch (Throwable $exception) {
            report($exception);
            $this->error($this->resolveThrowableMessage($exception));

            return self::FAILURE;
        }
    }

    private function reportStepProgress(HostSystemUpdateCliRunnerService $runner, HostSystemUpdateStepResult $result): void
    {
        $label = $runner->phaseLabel($result->phase);
        $this->line('→ '.$label);

        if ($result->migrationProgress instanceof HostSystemUpdateMigrationProgress) {
            $progress = $result->migrationProgress;
            $this->line(sprintf(
                '  %s',
                (string) __('dberp.system_update_center.cli.output.migration_progress', [
                    'completed' => (string) $progress->completed,
                    'total' => (string) $progress->total,
                    'pending' => (string) $progress->pending,
                ]),
            ));
        }

        if ($result->batchProgress instanceof HostSystemUpdateBatchProgress) {
            $progress = $result->batchProgress;
            $this->line(sprintf(
                '  %s',
                (string) __('dberp.system_update_center.cli.output.batch_progress', [
                    'processed' => (string) $progress->processed,
                    'total' => (string) $progress->total,
                    'percent' => (string) HostSystemUpdateBatchProgress::percentComplete($progress),
                ]),
            ));
        }
    }

    private function resolveThrowableMessage(Throwable $throwable): string
    {
        if ($throwable instanceof SupportCenterException
            || $throwable instanceof HostSystemUpdateExecutionException
            || $throwable instanceof HostSystemUpdateRecoveryException
            || $throwable instanceof HostSystemUpdateFileExecutionException
            || $throwable instanceof HostSystemUpdatePostApplyException
            || $throwable instanceof HostSystemUpdateStagingException) {
            return $throwable->userFacingMessage();
        }

        if ($throwable instanceof DomainException) {
            return $throwable->getMessage();
        }

        return (string) __('dberp.system_update_center.cli.errors.unexpected_failure');
    }
}
