using System.Diagnostics;
using System.Text.Json;
using Xunit;

namespace DevTool.Tests;

public sealed class DevShellScriptTests
{
    [Theory]
    [InlineData("pwsh")]
    [InlineData("bash")]
    [InlineData("zsh")]
    [InlineData("cmd")]
    public async Task DevShellExport_ReturnsSuccess_ForSupportedShells(string shell)
    {
        var python = ResolvePython();
        var result = await RunAsync(
            python,
            ["scripts/dev_shell.py", "export", "--shell", shell, "--json"]);

        Assert.Equal(0, result.ExitCode);
        using var doc = JsonDocument.Parse(result.StdOut);
        Assert.True(doc.RootElement.TryGetProperty("projectRoot", out _));
        Assert.True(doc.RootElement.TryGetProperty("env", out _));
    }

    [Fact]
    public async Task DevShellExport_InvalidShell_ReturnsExitCode3()
    {
        var python = ResolvePython();
        var result = await RunAsync(
            python,
            ["scripts/dev_shell.py", "export", "--shell", "fish"]);

        Assert.Equal(3, result.ExitCode);
    }

    [Fact]
    public async Task DevShellDoctor_ReturnsJson()
    {
        var python = ResolvePython();
        var result = await RunAsync(
            python,
            ["scripts/dev_shell.py", "doctor"]);

        Assert.Equal(0, result.ExitCode);
        using var doc = JsonDocument.Parse(result.StdOut);
        Assert.True(doc.RootElement.TryGetProperty("repo_root", out _));
    }

    private static string ResolvePython()
    {
        var candidates = OperatingSystem.IsWindows()
            ? new[] { "python", "py" }
            : new[] { "python3", "python" };

        foreach (var candidate in candidates)
        {
            try
            {
                using var process = new Process
                {
                    StartInfo = new ProcessStartInfo
                    {
                        FileName = candidate,
                        RedirectStandardOutput = true,
                        RedirectStandardError = true,
                        UseShellExecute = false,
                        CreateNoWindow = true,
                    }
                };
                process.StartInfo.ArgumentList.Add("--version");
                process.Start();
                process.WaitForExit(2000);
                if (process.ExitCode == 0)
                    return candidate;
            }
            catch
            {
            }
        }

        throw new InvalidOperationException("Python executable not found.");
    }

    private static async Task<(int ExitCode, string StdOut, string StdErr)> RunAsync(string command, IReadOnlyList<string> args)
    {
        var psi = new ProcessStartInfo
        {
            FileName = command,
            RedirectStandardOutput = true,
            RedirectStandardError = true,
            UseShellExecute = false,
            CreateNoWindow = true,
            WorkingDirectory = RepoRoot(),
        };
        foreach (var arg in args)
            psi.ArgumentList.Add(arg);

        using var process = new Process { StartInfo = psi };
        process.Start();
        var stdout = await process.StandardOutput.ReadToEndAsync();
        var stderr = await process.StandardError.ReadToEndAsync();
        await process.WaitForExitAsync();
        return (process.ExitCode, stdout, stderr);
    }

    private static string RepoRoot()
    {
        var dir = new DirectoryInfo(AppContext.BaseDirectory);
        while (dir is not null)
        {
            if (File.Exists(Path.Combine(dir.FullName, "devtool.json")))
                return dir.FullName;
            dir = dir.Parent;
        }

        throw new InvalidOperationException("Could not locate repo root.");
    }
}
