<?php

declare(strict_types=1);

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

namespace App\Services\SupportCenter;

/**
 * 系统更新工作目录（packages / staging / backups / logs，均在 storage 下，非 public）。
 */
final class HostSystemUpdateWorkspaceStorage
{
    public static function baseDirectory(): string
    {
        return storage_path('app/dberp/updates');
    }

    public static function packagesDirectory(): string
    {
        return self::baseDirectory().'/packages';
    }

    public static function stagingDirectory(string $executionNo): string
    {
        return self::baseDirectory().'/staging/'.self::sanitizeExecutionNo($executionNo);
    }

    public static function backupsDirectory(string $executionNo): string
    {
        return self::baseDirectory().'/backups/'.self::sanitizeExecutionNo($executionNo);
    }

    public static function logsDirectory(): string
    {
        return self::baseDirectory().'/logs';
    }

    public static function sessionsDirectory(): string
    {
        return self::baseDirectory().'/sessions';
    }

    public static function executionWorkspaceDirectory(string $executionNo): string
    {
        return self::baseDirectory().'/executions/'.self::sanitizeExecutionNo($executionNo);
    }

    public static function relativeFromStorage(string $absolutePath): string
    {
        $normalized = str_replace('\\', '/', $absolutePath);
        $storageRoot = str_replace('\\', '/', storage_path());

        if (str_starts_with($normalized, $storageRoot.'/')) {
            return 'storage/'.substr($normalized, strlen($storageRoot) + 1);
        }

        return basename($normalized);
    }

    public static function absoluteFromRelativeStorage(string $relativePath): string
    {
        $normalized = str_replace('\\', '/', trim($relativePath));

        if (str_starts_with($normalized, 'storage/')) {
            return storage_path(substr($normalized, strlen('storage/')));
        }

        if (str_starts_with($normalized, '/')) {
            return $normalized;
        }

        return base_path($normalized);
    }

    public static function isWithinUpdatesWorkspace(string $path): bool
    {
        $normalized = rtrim(strtolower(str_replace('\\', '/', trim($path))), '/');
        $workspace = rtrim(strtolower(str_replace('\\', '/', self::baseDirectory())), '/');

        return $normalized !== ''
            && ($normalized === $workspace || str_starts_with($normalized, $workspace.'/'));
    }

    public static function ensureDirectoryExists(string $directory): void
    {
        if (! is_dir($directory)) {
            mkdir($directory, 0755, true);
        }
    }

    public static function ensureBaseStructureExists(): void
    {
        self::ensureDirectoryExists(self::baseDirectory());
        self::ensureDirectoryExists(self::packagesDirectory());
        self::ensureDirectoryExists(self::logsDirectory());
        self::ensureDirectoryExists(self::sessionsDirectory());
    }

    public static function ensureSessionsDirectoryExists(): void
    {
        self::ensureDirectoryExists(self::sessionsDirectory());
    }

    public static function recreateCleanDirectory(string $directory): void
    {
        if (is_dir($directory)) {
            self::deleteDirectory($directory);
        }

        self::ensureDirectoryExists($directory);
    }

    public static function deleteDirectory(string $directory): void
    {
        if (! is_dir($directory)) {
            return;
        }

        $items = scandir($directory);

        if ($items === false) {
            return;
        }

        foreach ($items as $item) {
            if ($item === '.' || $item === '..') {
                continue;
            }

            $path = $directory.DIRECTORY_SEPARATOR.$item;

            if (is_dir($path)) {
                self::deleteDirectory($path);
            } elseif (is_file($path)) {
                @unlink($path);
            }
        }

        @rmdir($directory);
    }

    /**
     * 与 staging/backups/executions 子目录名一致，清理保留列表比对时必须使用同一规则。
     */
    public static function sanitizeExecutionNo(string $executionNo): string
    {
        $normalized = preg_replace('/[^A-Za-z0-9._-]+/', '-', trim($executionNo)) ?? 'execution';

        return trim($normalized, '-') !== '' ? trim($normalized, '-') : 'execution';
    }
}
