using ClaudeDo.Installer.Core;
using ClaudeDo.Installer.Steps;

namespace ClaudeDo.Installer.Tests;

public sealed class RegisterMcpStepTests
{
    // Progress<T> posts to the SynchronizationContext (or the ThreadPool) asynchronously,
    // so asserting on captured messages right after an await needs a synchronous reporter.
    private sealed class SyncProgress<T>(Action<T> report) : IProgress<T>
    {
        public void Report(T value) => report(value);
    }


    [Fact]
    public void ResolveUrl_uses_the_configured_port()
    {
        var url = RegisterMcpStep.ResolveUrl(new InstallerWorkerConfig { ExternalMcpPort = 49999 });

        Assert.Equal("http://127.0.0.1:49999/mcp", url);
    }

    [Fact]
    public void ResolveUrl_defaults_to_47822_without_a_configured_port()
    {
        var url = RegisterMcpStep.ResolveUrl(new InstallerWorkerConfig());

        Assert.Equal("http://127.0.0.1:47822/mcp", url);
    }

    [Fact]
    public void ResolveUrl_is_null_when_the_external_listener_is_disabled()
    {
        var url = RegisterMcpStep.ResolveUrl(new InstallerWorkerConfig { ExternalMcpPort = 0 });

        Assert.Null(url);
    }

    [Fact]
    public async Task Not_selected_skips_without_loading_the_worker_config()
    {
        var loaded = false;
        var step = new RegisterMcpStep(() => { loaded = true; return new InstallerWorkerConfig(); });
        var ctx = new InstallContext { RegisterMcpWithClaude = false };

        var result = await step.ExecuteAsync(ctx, new Progress<string>(_ => { }), CancellationToken.None);

        Assert.True(result.Success);
        Assert.False(loaded);
    }

    [Fact]
    public async Task Disabled_external_port_skips_without_running_the_claude_cli()
    {
        var step = new RegisterMcpStep(() => new InstallerWorkerConfig { ExternalMcpPort = 0 });
        var ctx = new InstallContext { RegisterMcpWithClaude = true };
        var messages = new List<string>();

        var result = await step.ExecuteAsync(ctx, new SyncProgress<string>(messages.Add), CancellationToken.None);

        Assert.True(result.Success);
        Assert.Contains(messages, m => m.Contains("external_mcp_port is 0", StringComparison.Ordinal));
    }
}
