<?php

declare(strict_types=1);

namespace App\Services\SupportCenter;

use App\Enums\SupportCenter\HostSystemUpdateExecutionStep;
use App\Exceptions\SupportCenter\HostSystemUpdatePostApplyException;
use App\Models\HostSystemUpdateExecution;

/**
 * 执行安全缓存清理命令（optimize/config/route/view clear）。
 */
final class HostSystemUpdateCacheCleaner
{
    /**
     * @var list<callable(): HostSystemUpdateArtisanCommandResult>
     */
    private array $commandInvokers;

    public function __construct(
        private readonly HostSystemUpdateExecutionContextResolver $contextResolver,
        private readonly HostSystemUpdateArtisanCommandRunner $commandRunner,
        private readonly HostSystemUpdateExecutionLogger $executionLogger,
        private readonly SupportCenterAuditLogger $auditLogger,
    ) {
        $this->commandInvokers = [
            fn (): HostSystemUpdateArtisanCommandResult => $this->commandRunner->runOptimizeClear(),
            fn (): HostSystemUpdateArtisanCommandResult => $this->commandRunner->runConfigClear(),
            fn (): HostSystemUpdateArtisanCommandResult => $this->commandRunner->runRouteClear(),
            fn (): HostSystemUpdateArtisanCommandResult => $this->commandRunner->runViewClear(),
        ];
    }

    /**
     * @return list<HostSystemUpdateArtisanCommandResult>
     */
    public function clearCaches(HostSystemUpdateExecution $execution): array
    {
        $startedAt = now()->utc();
        $package = $this->contextResolver->resolveReadyPackage($execution);

        $this->auditLogger->logSystemUpdateCacheClearStarted($execution, $package);
        $this->executionLogger->logStepStarted(
            $execution,
            HostSystemUpdateExecutionStep::ClearCache->value,
            (string) __('dberp.system_update.post_apply.log.cache_clear_started'),
        );

        /** @var list<HostSystemUpdateArtisanCommandResult> $results */
        $results = [];

        try {
            foreach ($this->commandInvokers as $invoker) {
                $result = $invoker();

                if (! $result->succeeded()) {
                    throw HostSystemUpdatePostApplyException::cacheClearFailed($result->command);
                }

                $results[] = $result;

                $this->executionLogger->logTransition(
                    $execution,
                    HostSystemUpdateExecutionStep::ClearCache->value,
                    (string) __('dberp.system_update.post_apply.log.cache_command_completed', [
                        'command' => $result->command,
                    ]),
                    $result->toLogContext(),
                );
            }

            $this->executionLogger->logStepCompleted(
                $execution,
                HostSystemUpdateExecutionStep::ClearCache->value,
                (string) __('dberp.system_update.post_apply.log.cache_clear_completed'),
                [
                    'commands' => array_map(
                        static fn (HostSystemUpdateArtisanCommandResult $result): string => $result->command,
                        $results,
                    ),
                ],
                $startedAt,
            );

            $this->auditLogger->logSystemUpdateCacheClearCompleted($execution, $package, $results);

            return $results;
        } catch (HostSystemUpdatePostApplyException $exception) {
            $this->executionLogger->logStepFailed(
                $execution,
                HostSystemUpdateExecutionStep::ClearCache->value,
                $exception->userFacingMessage(),
                $exception->errorCode(),
                $exception->userFacingMessage(),
                [
                    'completed_commands' => array_map(
                        static fn (HostSystemUpdateArtisanCommandResult $result): string => $result->command,
                        $results,
                    ),
                ],
                $startedAt,
            );
            $this->auditLogger->logSystemUpdateCacheClearFailed($execution, $package, $exception);

            throw $exception;
        }
    }
}
