using Sdt.Core;
using Sdt.Config;
using Xunit;

namespace DevTool.Tests;

public sealed class CommandResolverTests
{
    [Fact]
    public void Resolve_Npm_OnWindows_UsesCmdShim()
    {
        var resolved = CommandResolver.Resolve("npm");
        if (OperatingSystem.IsWindows())
            Assert.True(
                resolved.EndsWith("npm.cmd", StringComparison.OrdinalIgnoreCase) ||
                resolved.EndsWith("\\npm", StringComparison.OrdinalIgnoreCase) ||
                string.Equals(resolved, "npm.cmd", StringComparison.OrdinalIgnoreCase),
                $"Resolved npm path was '{resolved}'");
        else
            Assert.Equal("npm", resolved);
    }

    [Fact]
    public void Resolve_PathOrExtension_Unchanged()
    {
        Assert.Equal("C:\\tools\\npm.cmd", CommandResolver.Resolve("C:\\tools\\npm.cmd"));
        var resolved = CommandResolver.Resolve("dotnet.exe");
        if (OperatingSystem.IsWindows() && Path.IsPathRooted(resolved))
            Assert.EndsWith("dotnet.exe", resolved, StringComparison.OrdinalIgnoreCase);
        else
            Assert.Equal("dotnet.exe", resolved);
    }

    [Fact]
    public void Resolve_Npm_PrefersCmdShim_WhenBothBareAndCmdExist()
    {
        if (!OperatingSystem.IsWindows())
            return;

        var temp = Path.Combine(Path.GetTempPath(), "sdt-cmdresolve-" + Guid.NewGuid().ToString("N"));
        Directory.CreateDirectory(temp);
        File.WriteAllText(Path.Combine(temp, "npm"), "");
        File.WriteAllText(Path.Combine(temp, "npm.cmd"), "@echo off");

        var originalPath = Environment.GetEnvironmentVariable("PATH");
        try
        {
            Environment.SetEnvironmentVariable("PATH", temp);
            var resolved = CommandResolver.Resolve("npm");
            Assert.EndsWith("npm.cmd", resolved, StringComparison.OrdinalIgnoreCase);
        }
        finally
        {
            Environment.SetEnvironmentVariable("PATH", originalPath);
            try { Directory.Delete(temp, recursive: true); } catch { }
        }
    }

    [Fact]
    public void ResolveWithTrace_ConfiguredOverride_IsUsed()
    {
        if (!OperatingSystem.IsWindows())
            return;

        var temp = Path.Combine(Path.GetTempPath(), "sdt-cmdresolve-" + Guid.NewGuid().ToString("N"));
        Directory.CreateDirectory(temp);
        var overridePath = Path.Combine(temp, "npm.cmd");
        File.WriteAllText(overridePath, "@echo off");

        var cfg = new DevToolConfig
        {
            Tooling = new ToolingConfig
            {
                Tools =
                [
                    new ToolInstallDefinition
                    {
                        Tool = "npm",
                        Executables = [overridePath]
                    }
                ]
            }
        };

        var resolved = CommandResolver.ResolveWithTrace("npm", cfg, "npm");
        Assert.Equal(CommandResolutionSource.ConfiguredOverride, resolved.Source);
        Assert.EndsWith("npm.cmd", resolved.Resolved, StringComparison.OrdinalIgnoreCase);
    }

    [Fact]
    public void ResolveWithTrace_ExpandsWindowsPathTokens()
    {
        if (!OperatingSystem.IsWindows())
            return;

        var nvmHome = Path.Combine(Path.GetTempPath(), "sdt-nvmhome-" + Guid.NewGuid().ToString("N"));
        var nvmLink = Path.Combine(Path.GetTempPath(), "sdt-nvmlink-" + Guid.NewGuid().ToString("N"));
        Directory.CreateDirectory(nvmHome);
        Directory.CreateDirectory(nvmLink);
        File.WriteAllText(Path.Combine(nvmLink, "npm.cmd"), "@echo off");

        var originalPath = Environment.GetEnvironmentVariable("PATH");
        var originalHome = Environment.GetEnvironmentVariable("NVM_HOME");
        var originalLink = Environment.GetEnvironmentVariable("NVM_SYMLINK");
        try
        {
            Environment.SetEnvironmentVariable("NVM_HOME", nvmHome);
            Environment.SetEnvironmentVariable("NVM_SYMLINK", nvmLink);
            Environment.SetEnvironmentVariable("PATH", "%NVM_HOME%;%NVM_SYMLINK%");

            var result = CommandResolver.ResolveWithTrace("npm");
            Assert.True(result.Source is CommandResolutionSource.Shim or CommandResolutionSource.Path);
            Assert.EndsWith("npm.cmd", result.Resolved, StringComparison.OrdinalIgnoreCase);
        }
        finally
        {
            Environment.SetEnvironmentVariable("PATH", originalPath);
            Environment.SetEnvironmentVariable("NVM_HOME", originalHome);
            Environment.SetEnvironmentVariable("NVM_SYMLINK", originalLink);
            try { Directory.Delete(nvmHome, recursive: true); } catch { }
            try { Directory.Delete(nvmLink, recursive: true); } catch { }
        }
    }
}
