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

namespace DevTool.Tests;

public sealed class ScriptSmokeTests
{
    [Fact]
    public async Task DiagProbe_JsonContract_IsValid()
    {
        var python = ResolvePython();
        var result = await RunAsync(
            python,
            ["scripts/diag.py", "probe", "--tool", "python", "--json"]);

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

    [Fact]
    public async Task BuildAction_InvalidRequirements_PropagatesNonZeroAndJson()
    {
        var python = ResolvePython();
        var missingReq = Path.Combine(Path.GetTempPath(), Guid.NewGuid() + ".txt");

        var result = await RunAsync(
            python,
            [
                "scripts/build.py",
                "python-pip-install",
                "--project-root",
                RepoRoot(),
                "--requirements",
                missingReq,
                "--json"
            ]);

        Assert.NotEqual(0, result.ExitCode);
        var jsonText = ExtractLastJsonObject(result.StdOut);
        using var doc = JsonDocument.Parse(jsonText);
        Assert.True(doc.RootElement.TryGetProperty("exit_code", out var code));
        Assert.NotEqual(0, code.GetInt32());
        Assert.True(doc.RootElement.TryGetProperty("failure_reason", out _));
    }

    [Fact]
    public async Task BuildAction_DotnetRestore_CommandNotFoundStillReturnsJson()
    {
        var python = ResolvePython();

        var result = await RunAsync(
            python,
            [
                "scripts/build.py",
                "dotnet-restore",
                "--project-root",
                RepoRoot(),
                "--json"
            ]);

        var jsonText = ExtractLastJsonObject(result.StdOut);
        using var doc = JsonDocument.Parse(jsonText);
        Assert.True(doc.RootElement.TryGetProperty("exit_code", out _));
        Assert.True(doc.RootElement.TryGetProperty("status", out _));
    }

    [Fact]
    public async Task BuildAction_DotnetBuild_AutoSelectsSlnTarget_WhenSingleSlnFound()
    {
        var python = ResolvePython();
        var tempRoot = Path.Combine(Path.GetTempPath(), "sdt-dotnet-target-" + Guid.NewGuid().ToString("N"));
        Directory.CreateDirectory(tempRoot);
        var sln = Path.Combine(tempRoot, "sample.sln");
        await File.WriteAllTextAsync(sln, "Microsoft Visual Studio Solution File, Format Version 12.00");

        var result = await RunAsync(
            python,
            [
                "scripts/build.py",
                "dotnet-build",
                "--project-root",
                tempRoot,
                "--working-dir",
                ".",
                "--json"
            ]);

        var jsonText = ExtractLastJsonObject(result.StdOut);
        using var doc = JsonDocument.Parse(jsonText);
        Assert.True(doc.RootElement.TryGetProperty("args", out var args));
        Assert.Contains(args.EnumerateArray().Select(x => x.GetString()), x => string.Equals(x, sln, StringComparison.OrdinalIgnoreCase));
    }

    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 for script smoke tests.");
    }

    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 (devtool.json not found).");
    }

    private static string ExtractLastJsonObject(string text)
    {
        var lines = text.Split('\n', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
        for (var i = lines.Length - 1; i >= 0; i--)
        {
            var line = lines[i];
            if (line.StartsWith("{", StringComparison.Ordinal) && line.EndsWith("}", StringComparison.Ordinal))
                return line;
        }

        throw new InvalidOperationException("No JSON object line found in script output.");
    }
}
