<?php

declare(strict_types=1);

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

namespace App\Services\SupportCenter;

use App\Exceptions\SupportCenter\HostSystemUpdateFileExecutionException;
use App\Exceptions\SupportCenter\HostSystemUpdateStagingException;
use App\Models\HostSystemUpdateBackup;
use App\Models\HostSystemUpdateExecution;
use App\Models\HostSystemUpdatePackage;

/**
 * 解析执行任务上下文（包、manifest、staging、备份），供文件执行层复用。
 */
final class HostSystemUpdateExecutionContextResolver
{
    public function resolveReadyPackage(HostSystemUpdateExecution $execution): HostSystemUpdatePackage
    {
        $package = $execution->package;

        if (! $package instanceof HostSystemUpdatePackage) {
            throw HostSystemUpdateFileExecutionException::prerequisitesNotMet('package_missing');
        }

        if (! $package->verified
            || $package->download_status !== HostSystemUpdatePackage::STATUS_VERIFIED
            || $package->manifest_status !== HostSystemUpdatePackage::MANIFEST_STATUS_VALID) {
            throw HostSystemUpdateFileExecutionException::prerequisitesNotMet('package_not_ready');
        }

        return $package;
    }

    /**
     * @return array<string, mixed>
     */
    public function manifest(HostSystemUpdateExecution $execution): array
    {
        $package = $this->resolveReadyPackage($execution);
        $manifest = $package->manifest;

        if (! is_array($manifest) || $manifest === []) {
            throw HostSystemUpdateFileExecutionException::prerequisitesNotMet('manifest_missing');
        }

        return $manifest;
    }

    public function stagingDirectory(HostSystemUpdateExecution $execution): string
    {
        $directory = HostSystemUpdateWorkspaceStorage::stagingDirectory($execution->execution_no);

        if (! is_dir($directory)) {
            throw HostSystemUpdateFileExecutionException::stagingMissing();
        }

        return $directory;
    }

    public function resolveCompletedFileSnapshotBackup(HostSystemUpdateExecution $execution): HostSystemUpdateBackup
    {
        $backup = $execution->backups()
            ->where('backup_type', HostSystemUpdateBackup::TYPE_FILE_SNAPSHOT)
            ->where('status', HostSystemUpdateBackup::STATUS_COMPLETED)
            ->latest('id')
            ->first();

        if (! $backup instanceof HostSystemUpdateBackup) {
            throw HostSystemUpdateFileExecutionException::backupNotCompleted();
        }

        return $backup;
    }

    /**
     * @return list<string>
     */
    public function backedUpPaths(HostSystemUpdateExecution $execution): array
    {
        $backup = $this->resolveCompletedFileSnapshotBackup($execution);
        $paths = $backup->included_paths;

        if (! is_array($paths)) {
            return [];
        }

        return array_values(array_filter($paths, static fn (mixed $path): bool => is_string($path) && $path !== ''));
    }

    public function stagedFilePath(string $stagingDirectory, string $relativePath): string
    {
        $normalized = $this->protectedPathGuard()->normalizeRelativePath($relativePath);

        if ($normalized === null) {
            throw HostSystemUpdateStagingException::protectedUpdateTarget($relativePath, 'files');
        }

        return $stagingDirectory.DIRECTORY_SEPARATOR.str_replace('/', DIRECTORY_SEPARATOR, $normalized);
    }

    private function protectedPathGuard(): HostSystemUpdateProtectedPathGuard
    {
        return app(HostSystemUpdateProtectedPathGuard::class);
    }
}
