namespace YMhut.Box.Core.App;

public sealed class AppPaths
{
    public static IReadOnlyList<string> RuntimePayloadDirectoryNames { get; } =
    [
        "Runtime",
        "runtime",
        "Runtimes",
        "runtimes"
    ];

    public static IReadOnlyList<string> UserPayloadDirectoryNames { get; } =
    [
        "Runtime",
        "runtime",
        "Runtimes",
        "runtimes",
        "Tools",
        "Metadata"
    ];

    public AppPaths(string root, string? assetsRoot = null)
    {
        Root = root;
        Logs = Path.Combine(root, "Logs");
        Cache = Path.Combine(root, "Cache");
        Data = Path.Combine(root, "Data");
        Assets = assetsRoot ?? Path.Combine(AppContext.BaseDirectory, "Assets");
    }

    public string Root { get; }

    public string Logs { get; }

    public string Cache { get; }

    public string Data { get; }

    public string Assets { get; }

    public void EnsureCreated()
    {
        Directory.CreateDirectory(Root);
        Directory.CreateDirectory(Logs);
        Directory.CreateDirectory(Cache);
        Directory.CreateDirectory(Data);
        CleanupUserPayloadDirectories(Root);
    }

    public IReadOnlyList<string> CleanupRuntimePayloadDirectories()
        => CleanupRuntimePayloadDirectories(Root);

    public static IReadOnlyList<string> CleanupRuntimePayloadDirectories(string root)
        => CleanupPayloadDirectories(root, RuntimePayloadDirectoryNames);

    public IReadOnlyList<string> CleanupUserPayloadDirectories()
        => CleanupUserPayloadDirectories(Root);

    public static IReadOnlyList<string> CleanupUserPayloadDirectories(string root)
        => CleanupPayloadDirectories(root, UserPayloadDirectoryNames);

    private static IReadOnlyList<string> CleanupPayloadDirectories(string root, IEnumerable<string> names)
    {
        if (string.IsNullOrWhiteSpace(root))
        {
            return [];
        }

        var removed = new List<string>();
        string rootFullPath;
        try
        {
            rootFullPath = Path.GetFullPath(root).TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
        }
        catch
        {
            return removed;
        }

        foreach (var name in names)
        {
            var candidate = Path.Combine(rootFullPath, name);
            if (!IsChildPath(rootFullPath, candidate))
            {
                continue;
            }

            if (TryDeleteDirectory(candidate))
            {
                removed.Add(candidate);
            }
        }

        return removed;
    }

    public static AppPaths ForCurrentUser(string? root = null, string? assetsRoot = null)
    {
        var appRoot = root ?? Path.Combine(
            Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
            "YMhut Box",
            "WinUI");
        var paths = new AppPaths(appRoot, assetsRoot);
        paths.EnsureCreated();
        return paths;
    }

    private static bool TryDeleteDirectory(string directory)
    {
        try
        {
            if (!Directory.Exists(directory))
            {
                return false;
            }

            NormalizeAttributes(directory);
            Directory.Delete(directory, recursive: true);
            return true;
        }
        catch
        {
            return false;
        }
    }

    private static void NormalizeAttributes(string directory)
    {
        foreach (var path in Directory.EnumerateFileSystemEntries(directory, "*", SearchOption.AllDirectories))
        {
            File.SetAttributes(path, FileAttributes.Normal);
        }

        File.SetAttributes(directory, FileAttributes.Normal);
    }

    private static bool IsChildPath(string rootFullPath, string candidate)
    {
        try
        {
            var childFullPath = Path.GetFullPath(candidate).TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
            return childFullPath.StartsWith(rootFullPath + Path.DirectorySeparatorChar, StringComparison.OrdinalIgnoreCase) ||
                childFullPath.StartsWith(rootFullPath + Path.AltDirectorySeparatorChar, StringComparison.OrdinalIgnoreCase);
        }
        catch
        {
            return false;
        }
    }
}
