using ClaudeDo.Worker.Lifecycle;

namespace ClaudeDo.Worker.Tests.Services;

public class VerifyCommandRunnerTests
{
    private readonly VerifyCommandRunner _runner = new();

    [Fact]
    public async Task RunAsync_ExitsZero_ReportsSuccessNotTimedOut()
    {
        var result = await _runner.RunAsync(
            Path.GetTempPath(), "exit 0", TimeSpan.FromSeconds(30), CancellationToken.None);

        Assert.Equal(0, result.ExitCode);
        Assert.False(result.TimedOut);
    }

    [Fact]
    public async Task RunAsync_NonZeroExit_ReportsExitCode()
    {
        var result = await _runner.RunAsync(
            Path.GetTempPath(), "exit 7", TimeSpan.FromSeconds(30), CancellationToken.None);

        Assert.Equal(7, result.ExitCode);
        Assert.False(result.TimedOut);
    }

    [Fact]
    public async Task RunAsync_CapturesStdoutAndStderr()
    {
        var result = await _runner.RunAsync(
            Path.GetTempPath(), "echo hello-out & echo hello-err 1>&2", TimeSpan.FromSeconds(30), CancellationToken.None);

        Assert.Contains("hello-out", result.Output);
        Assert.Contains("hello-err", result.Output);
    }

    [Fact]
    public async Task RunAsync_RunsInSpecifiedWorkingDirectory()
    {
        var dir = Path.Combine(Path.GetTempPath(), $"verify_wd_{Guid.NewGuid():N}");
        Directory.CreateDirectory(dir);
        try
        {
            var result = await _runner.RunAsync(dir, "cd", TimeSpan.FromSeconds(30), CancellationToken.None);
            Assert.Contains(new DirectoryInfo(dir).Name, result.Output);
        }
        finally { Directory.Delete(dir, recursive: true); }
    }

    [Fact]
    public async Task RunAsync_ExceedsTimeout_KillsProcessAndReportsTimedOut()
    {
        var result = await _runner.RunAsync(
            Path.GetTempPath(), "ping -n 60 127.0.0.1", TimeSpan.FromMilliseconds(300), CancellationToken.None);

        Assert.True(result.TimedOut);
    }
}
