<?php

declare(strict_types=1);

namespace App\Services\Install;

/**
 * 安装进度 API 响应（不含敏感载荷与堆栈信息）。
 */
final class WebInstallProgressApiResponse
{
    /**
     * @return array<string, mixed>
     */
    public static function fromState(
        WebInstallProgressState $state,
        bool $locked = false,
        bool $applicationAlreadyInstalled = false,
    ): array {
        $currentLabel = self::resolveCurrentLabel($state, $applicationAlreadyInstalled);
        $userMessage = self::resolveUserMessage($state, $applicationAlreadyInstalled);
        $phase = WebInstallPhase::tryFrom($state->currentStage);

        $response = [
            'install_id' => $state->installId,
            'status' => $state->status->value,
            'status_label' => WebInstallProgressDisplay::statusLabelZh($state->status),
            'current_stage' => $state->currentStage,
            'current_label' => $currentLabel,
            'percent' => $state->percent,
            'completed_stages' => $state->completedStages,
            'warnings' => $state->warnings,
            'errors' => array_map(
                static fn (string $error): string => WebInstallUserMessages::sanitizeFailureDetail($error, $phase),
                $state->errors,
            ),
            'user_message' => $userMessage,
            'stages' => WebInstallProgressDisplay::businessStages(),
            'locked' => $locked,
            'already_installed' => $applicationAlreadyInstalled,
            'is_terminal' => self::isProgressTerminal($state->status),
            'started_at' => $state->startedAt,
            'updated_at' => $state->updatedAt,
        ];

        if ($state->migrationProgress !== null) {
            $response['migration_progress'] = self::publicMigrationProgress($state->migrationProgress);
        }

        if (in_array($state->status, [WebInstallProgressStatus::Completed, WebInstallProgressStatus::Warning], true)) {
            $response['finished_url'] = route('install.finished');
        }

        return $response;
    }

    public static function userMessageForState(
        WebInstallProgressState $state,
        bool $applicationAlreadyInstalled = false,
    ): string {
        return self::resolveUserMessage($state, $applicationAlreadyInstalled);
    }

    private static function isProgressTerminal(WebInstallProgressStatus $status): bool
    {
        return in_array($status, [
            WebInstallProgressStatus::Completed,
            WebInstallProgressStatus::Warning,
            WebInstallProgressStatus::Failed,
        ], true);
    }

    private static function resolveCurrentLabel(
        WebInstallProgressState $state,
        bool $applicationAlreadyInstalled,
    ): string {
        if (self::shouldShowAlreadyInstalledCopy($state, $applicationAlreadyInstalled)) {
            return WebInstallUserMessages::APPLICATION_ALREADY_INSTALLED;
        }

        if ($state->status === WebInstallProgressStatus::Failed) {
            return '安装失败';
        }

        if ($state->status === WebInstallProgressStatus::Completed) {
            return '安装完成';
        }

        if ($state->status === WebInstallProgressStatus::Warning && $state->currentStage === WebInstallPhase::Completed->value) {
            return '安装完成';
        }

        return self::resolveInProgressCopy($state);
    }

    private static function resolveUserMessage(
        WebInstallProgressState $state,
        bool $applicationAlreadyInstalled,
    ): string {
        if (self::shouldShowAlreadyInstalledCopy($state, $applicationAlreadyInstalled)) {
            return WebInstallUserMessages::APPLICATION_ALREADY_INSTALLED;
        }

        if ($state->status === WebInstallProgressStatus::Failed) {
            return WebInstallProgressDisplay::FAILED_USER_MESSAGE;
        }

        if ($state->status === WebInstallProgressStatus::Warning) {
            return WebInstallProgressDisplay::WARNING_USER_MESSAGE;
        }

        if ($state->status === WebInstallProgressStatus::Completed) {
            return WebInstallProgressDisplay::COMPLETED_USER_MESSAGE;
        }

        return self::resolveInProgressCopy($state);
    }

    private static function shouldShowAlreadyInstalledCopy(
        WebInstallProgressState $state,
        bool $applicationAlreadyInstalled,
    ): bool {
        if (! $applicationAlreadyInstalled || ! self::isProgressTerminal($state->status)) {
            return false;
        }

        return $state->currentLabel === WebInstallUserMessages::APPLICATION_ALREADY_INSTALLED;
    }

    private static function resolveInProgressCopy(WebInstallProgressState $state): string
    {
        if ($state->status === WebInstallProgressStatus::Pending && $state->currentStage === '') {
            return WebInstallProgressDisplay::WAITING_FOR_EXECUTION_LABEL;
        }

        if ($state->currentStage === WebInstallPhase::Migrating->value && $state->migrationProgress !== null) {
            return WebInstallMigrationProgress::businessLabel($state->migrationProgress);
        }

        $businessLabel = WebInstallProgressDisplay::businessLabelForStage($state->currentStage);

        if ($businessLabel !== '') {
            return $businessLabel;
        }

        $phase = WebInstallPhase::tryFrom($state->currentStage);

        if ($phase !== null && $state->currentLabel !== '') {
            return $state->currentLabel;
        }

        if ($phase !== null) {
            return $phase->labelZh();
        }

        return $state->currentLabel !== ''
            ? $state->currentLabel
            : WebInstallProgressDisplay::WAITING_FOR_EXECUTION_LABEL;
    }

    /**
     * @return array{
     *     total: int,
     *     completed: int,
     *     pending: int,
     *     percent: int,
     *     batch_size: int
     * }
     */
    private static function publicMigrationProgress(WebInstallMigrationProgress $progress): array
    {
        return [
            'total' => $progress->total,
            'completed' => $progress->completed,
            'pending' => $progress->pending,
            'percent' => WebInstallMigrationProgress::percentComplete($progress),
            'batch_size' => $progress->batchSize,
        ];
    }
}
