using ClaudeDo.Installer.Core;

namespace ClaudeDo.Installer.Steps;

public sealed class RegisterMcpStep : IInstallStep
{
    private const string ServerName = "claudedo";
    private readonly Func<InstallerWorkerConfig> _loadWorkerConfig;

    public RegisterMcpStep(Func<InstallerWorkerConfig>? loadWorkerConfig = null)
    {
        _loadWorkerConfig = loadWorkerConfig ?? InstallerWorkerConfig.Load;
    }

    public string Name => "Register MCP with Claude";

    // Resolves the URL from the persisted worker.config.json rather than ctx.ExternalMcpPort:
    // an Update run never repopulates ctx from the existing installation, so ctx would still
    // hold the wizard default (47822) even when the installed config has a different port.
    // Returns null when the port is 0 — WorkerConfig treats that as "external listener off",
    // so registering a URL against it would just point Claude at nothing.
    public static string? ResolveUrl(InstallerWorkerConfig cfg) =>
        cfg.ExternalMcpPort == 0 ? null : $"http://127.0.0.1:{cfg.ExternalMcpPort}/mcp";

    public async Task<StepResult> ExecuteAsync(InstallContext ctx, IProgress<string> progress, CancellationToken ct)
    {
        if (!ctx.RegisterMcpWithClaude)
        {
            progress.Report("Skipped (not selected)");
            return StepResult.Ok();
        }

        var url = ResolveUrl(_loadWorkerConfig());
        if (url is null)
        {
            progress.Report("Skipped (external_mcp_port is 0 — the external MCP listener is disabled).");
            return StepResult.Ok();
        }

        // Drop any prior registration first so a re-run (e.g. update, changed port)
        // overwrites cleanly instead of erroring on a duplicate name.
        progress.Report($"Removing existing '{ServerName}' MCP registration (if any)...");
        await ProcessRunner.RunAsync(ctx.ClaudeBin, $"mcp remove --scope user {ServerName}", null, progress, ct);

        progress.Report($"Registering '{ServerName}' MCP server at {url}...");
        var (exit, output) = await ProcessRunner.RunAsync(
            ctx.ClaudeBin,
            $"mcp add --transport http --scope user {ServerName} {url}",
            null, progress, ct);

        // Non-fatal: a missing/old Claude CLI must never block the install. Surface the
        // manual command so the user can register it themselves later.
        if (exit != 0)
        {
            progress.Report(
                $"Could not register MCP automatically (claude exited {exit}). " +
                $"Run manually: claude mcp add --transport http --scope user {ServerName} {url}");
        }
        else
        {
            progress.Report("MCP server registered with Claude.");
        }

        return StepResult.Ok();
    }
}
