using System.Diagnostics;
using Microsoft.Win32;

namespace NexusInstaller.Services;

internal static class RuntimeChecker
{
    public static async Task<bool> HasDotNet8DesktopAsync() =>
        await HasDesktopRuntimeAsync("8.").ConfigureAwait(false);

    public static async Task<bool> HasDotNet10DesktopAsync() =>
        await HasDesktopRuntimeAsync("10.").ConfigureAwait(false);

    public static async Task<bool> HasDotNet8CoreAsync() =>
        await HasCoreRuntimeAsync("8.").ConfigureAwait(false);

    private static async Task<bool> HasDesktopRuntimeAsync(string majorPrefix)
    {
        var output = await RunDotnetListRuntimesAsync().ConfigureAwait(false);
        if (output.Contains($"Microsoft.WindowsDesktop.App {majorPrefix}", StringComparison.Ordinal))
        {
            return true;
        }

        return CheckRegistryDesktop(majorPrefix);
    }

    private static async Task<bool> HasCoreRuntimeAsync(string majorPrefix)
    {
        var output = await RunDotnetListRuntimesAsync().ConfigureAwait(false);
        if (output.Contains($"Microsoft.NETCore.App {majorPrefix}", StringComparison.Ordinal))
        {
            return true;
        }

        return CheckRegistryCore(majorPrefix);
    }

    private static bool CheckRegistryDesktop(string majorPrefix)
    {
        foreach (var root in RegistryRoots())
        {
            using var key = root.OpenSubKey(@"SOFTWARE\dotnet\Setup\InstalledVersions\x64\sharedfx\Microsoft.WindowsDesktop.App");
            if (key is null)
            {
                continue;
            }

            foreach (var version in key.GetValueNames())
            {
                if (version.StartsWith(majorPrefix.TrimEnd('.'), StringComparison.Ordinal))
                {
                    return true;
                }
            }
        }

        return false;
    }

    private static bool CheckRegistryCore(string majorPrefix)
    {
        foreach (var root in RegistryRoots())
        {
            using var key = root.OpenSubKey(@"SOFTWARE\dotnet\Setup\InstalledVersions\x64\sharedfx\Microsoft.NETCore.App");
            if (key is null)
            {
                continue;
            }

            foreach (var version in key.GetValueNames())
            {
                if (version.StartsWith(majorPrefix.TrimEnd('.'), StringComparison.Ordinal))
                {
                    return true;
                }
            }
        }

        return false;
    }

    private static IEnumerable<RegistryKey> RegistryRoots()
    {
        yield return Registry.LocalMachine;
        yield return Registry.CurrentUser;
    }

    private static async Task<string> RunDotnetListRuntimesAsync()
    {
        try
        {
            var psi = new ProcessStartInfo
            {
                FileName = "dotnet",
                Arguments = "--list-runtimes",
                RedirectStandardOutput = true,
                RedirectStandardError = true,
                UseShellExecute = false,
                CreateNoWindow = true,
            };

            using var process = Process.Start(psi);
            if (process is null)
            {
                return string.Empty;
            }

            var stdout = await process.StandardOutput.ReadToEndAsync().ConfigureAwait(false);
            await process.WaitForExitAsync().ConfigureAwait(false);
            return stdout;
        }
        catch
        {
            return string.Empty;
        }
    }
}
