using System.Text.Json.Nodes;
using Microsoft.Extensions.Logging.Abstractions;
using Nexus.Api.Models;
using Nexus.Api.Services;
using Xunit;

namespace Nexus.Api.Tests;

public sealed class OpenClawWizardServiceTests
{
    private static readonly OpenClawInvocationContext Invocation =
        OpenClawInvocationContext.Create(
            actor: "owner-1",
            idempotencyKey: "wizard-test",
            correlationId: "wizard-correlation",
            traceParent: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01");

    [Fact]
    public async Task Start_RequiresExplicitConfirmationAndLocalManagement()
    {
        var gateway = ReadyGateway();
        var state = new OpenClawManagementState();
        var service = CreateService(gateway, state);

        var unconfirmed = await service.StartAsync(
            new StartOpenClawWizardRequest(Confirmed: false),
            Invocation);
        var disabled = await service.StartAsync(
            new StartOpenClawWizardRequest(Confirmed: true),
            Invocation);

        Assert.Equal("confirmation_required", unconfirmed.State);
        Assert.Equal("management_disabled", disabled.State);
        Assert.Empty(gateway.Invocations);
    }

    [Fact]
    public async Task Start_UsesOfficialSafeParametersAndProjectsInteractiveStep()
    {
        var gateway = ReadyGateway();
        gateway.Handler = (method, _) => method == "wizard.start"
            ? JsonNode.Parse(
                """
                {
                  "sessionId": "wizard-1",
                  "done": false,
                  "status": "running",
                  "step": {
                    "id": "mode",
                    "type": "select",
                    "title": "Choose mode",
                    "options": [
                      { "value": "safe", "label": "Safe", "hint": "Recommended" }
                    ]
                  }
                }
                """)
            : null;
        var state = new OpenClawManagementState();
        state.SetEnabled(true);
        var service = CreateService(gateway, state);

        var result = await service.StartAsync(
            new StartOpenClawWizardRequest("remote", Confirmed: true),
            Invocation);

        Assert.True(result.Ok);
        Assert.Equal("wizard-1", result.SessionId);
        Assert.Equal("select", result.Step?.Type);
        var invocation = Assert.Single(gateway.Invocations);
        Assert.Equal("wizard.start", invocation.Method);
        Assert.Equal("remote", invocation.Parameters?["mode"]?.GetValue<string>());
        Assert.False(invocation.Parameters?["installDaemon"]?.GetValue<bool>());
        Assert.Equal("setup", invocation.Parameters?["flow"]?.GetValue<string>());
    }

    [Fact]
    public async Task SensitiveStep_IsRedactedAndCannotBeAnsweredFromBrowser()
    {
        var gateway = ReadyGateway();
        gateway.Handler = (method, _) => method == "wizard.start"
            ? JsonNode.Parse(
                """
                {
                  "sessionId": "wizard-secret",
                  "done": false,
                  "step": {
                    "id": "provider-token",
                    "type": "text",
                    "title": "Provider token",
                    "sensitive": true,
                    "initialValue": "must-not-leak",
                    "placeholder": "must-not-leak"
                  }
                }
                """)
            : null;
        var state = new OpenClawManagementState();
        state.SetEnabled(true);
        var service = CreateService(gateway, state);

        var started = await service.StartAsync(
            new StartOpenClawWizardRequest(Confirmed: true),
            Invocation);
        var advanced = await service.NextAsync(
            new AdvanceOpenClawWizardRequest(
                "wizard-secret",
                "provider-token",
                JsonValue.Create("browser-secret"),
                HasAnswer: true),
            Invocation);

        Assert.True(started.Step?.Sensitive);
        Assert.Null(started.Step?.InitialValue);
        Assert.Null(started.Step?.Placeholder);
        Assert.False(started.Step?.CanAnswer);
        Assert.Equal("server_secret_required", advanced.State);
        Assert.Single(gateway.Invocations);
        Assert.DoesNotContain("must-not-leak", started.ToString(), StringComparison.Ordinal);
        Assert.DoesNotContain("browser-secret", advanced.ToString(), StringComparison.Ordinal);
    }

    private static OpenClawWizardService CreateService(
        SetupGatewayConnector gateway,
        IOpenClawManagementState managementState)
        => new(
            gateway,
            NullLogger<OpenClawWizardService>.Instance,
            managementState);

    private static SetupGatewayConnector ReadyGateway()
    {
        var gateway = new SetupGatewayConnector
        {
            ConnectionState = GatewayConnectionState.Connected,
            GrantedScopes = new HashSet<string>(
                ["operator.read", "operator.admin"],
                StringComparer.Ordinal),
            AdvertisedMethods = new HashSet<string>(
                ["wizard.start", "wizard.next", "wizard.status", "wizard.cancel"],
                StringComparer.Ordinal)
        };
        return gateway;
    }
}
