<?php

declare(strict_types=1);

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 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);
    }

    private static function sanitizeExecutionNo(string $executionNo): string
    {
        $normalized = preg_replace('/[^A-Za-z0-9._-]+/', '-', trim($executionNo)) ?? 'execution';

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