using ClaudeDo.Installer.Checks;
using ClaudeDo.Installer.Core;

namespace ClaudeDo.Installer.Tests.Checks;

public sealed class ClaudeCliCheckTests : IDisposable
{
    private readonly string _dir;

    public ClaudeCliCheckTests()
    {
        _dir = Path.Combine(Path.GetTempPath(), $"cdclaudecli_{Guid.NewGuid():N}");
        Directory.CreateDirectory(_dir);
    }

    public void Dispose()
    {
        try { Directory.Delete(_dir, recursive: true); } catch { }
    }

    [Fact]
    public async Task Found_as_exe_reports_ok_with_path_and_version_and_no_shim_detail()
    {
        File.WriteAllText(Path.Combine(_dir, "claude.exe"), "");
        var runner = new FakeProcessRunner((0, "2.1.230 (Claude Code)"));
        var check = new ClaudeCliCheck(new ClaudeCliLookup(runner, pathOverride: _dir, pathExtOverride: ".exe"));

        var result = await check.RunAsync(new InstallContext(), CancellationToken.None);

        Assert.Equal(CheckStatus.Ok, result.Status);
        Assert.Contains(_dir, result.Message);
        Assert.Contains("2.1.230", result.Message);
        Assert.Null(result.Detail);
    }

    [Fact]
    public async Task Found_as_shim_flags_it_in_detail()
    {
        File.WriteAllText(Path.Combine(_dir, "claude.cmd"), "");
        var runner = new FakeProcessRunner((0, "2.1.230 (Claude Code)"));
        var check = new ClaudeCliCheck(new ClaudeCliLookup(runner, pathOverride: _dir, pathExtOverride: ".cmd"));

        var result = await check.RunAsync(new InstallContext(), CancellationToken.None);

        Assert.Equal(CheckStatus.Ok, result.Status);
        Assert.NotNull(result.Detail);
    }

    [Fact]
    public async Task Not_found_reports_failed_naming_searched_locations()
    {
        var runner = new FakeProcessRunner();
        var check = new ClaudeCliCheck(new ClaudeCliLookup(runner, pathOverride: _dir, pathExtOverride: ".exe"));
        // A distinctive, definitely-missing name — a plain "claude" would still resolve via
        // ExecutableResolver's fixed fallback dirs (e.g. %USERPROFILE%\.local\bin) on a machine
        // that has the real CLI installed, regardless of pathOverride.
        var ctx = new InstallContext { ClaudeBin = "claudedo_totally_missing_cmd_9f3a1" };

        var result = await check.RunAsync(ctx, CancellationToken.None);

        Assert.Equal(CheckStatus.Failed, result.Status);
        Assert.Equal(CheckSeverity.Error, result.Severity);
        Assert.Contains(_dir, result.Message);
        Assert.NotNull(result.HintKey);
        Assert.Empty(runner.Calls);
    }

    [Fact]
    public async Task Nonzero_exit_reports_failed()
    {
        File.WriteAllText(Path.Combine(_dir, "claude.exe"), "");
        var runner = new FakeProcessRunner((1, "some error"));
        var check = new ClaudeCliCheck(new ClaudeCliLookup(runner, pathOverride: _dir, pathExtOverride: ".exe"));

        var result = await check.RunAsync(new InstallContext(), CancellationToken.None);

        Assert.Equal(CheckStatus.Failed, result.Status);
    }
}
