using ZB.MOM.WW.MxGateway.Contracts;
using ZB.MOM.WW.MxGateway.Worker.Bootstrap;

namespace ZB.MOM.WW.MxGateway.Worker.Tests.Bootstrap;

public sealed class WorkerOptionsParserTests
{
    /// <summary>Verifies that parsing with all required inputs returns worker options.</summary>
    [Fact]
    public void Parse_WithAllRequiredInputs_ReturnsWorkerOptions()
    {
        WorkerOptionsParser parser = new(CreateEnvironment("nonce-secret"));

        WorkerBootstrapResult result = parser.Parse(ValidArgs());

        Assert.True(result.Succeeded);
        Assert.Equal(WorkerExitCode.Success, result.ExitCode);
        Assert.NotNull(result.Options);
        Assert.Equal("session-1", result.Options.SessionId);
        Assert.Equal("mxaccess-gateway-123-session-1", result.Options.PipeName);
        Assert.Equal(GatewayContractInfo.WorkerProtocolVersion, result.Options.ProtocolVersion);
        Assert.Equal("nonce-secret", result.Options.Nonce);
    }

    /// <summary>Verifies that parsing with missing session ID returns invalid arguments.</summary>
    [Fact]
    public void Parse_WithMissingSessionId_ReturnsInvalidArguments()
    {
        WorkerOptionsParser parser = new(CreateEnvironment("nonce-secret"));

        WorkerBootstrapResult result = parser.Parse(
        [
            "--pipe-name",
            "mxaccess-gateway-123-session-1",
            "--protocol-version",
            GatewayContractInfo.WorkerProtocolVersion.ToString(),
        ]);

        Assert.False(result.Succeeded);
        Assert.Equal(WorkerExitCode.InvalidArguments, result.ExitCode);
        Assert.Contains(result.Errors, error => error.Contains("--session-id"));
    }

    /// <summary>Verifies that parsing with unknown option returns invalid arguments.</summary>
    [Fact]
    public void Parse_WithUnknownOption_ReturnsInvalidArguments()
    {
        WorkerOptionsParser parser = new(CreateEnvironment("nonce-secret"));

        WorkerBootstrapResult result = parser.Parse(
        [
            "--session-id",
            "session-1",
            "--pipe-name",
            "mxaccess-gateway-123-session-1",
            "--protocol-version",
            GatewayContractInfo.WorkerProtocolVersion.ToString(),
            "--unexpected",
            "value",
        ]);

        Assert.Equal(WorkerExitCode.InvalidArguments, result.ExitCode);
        Assert.Contains(result.Errors, error => error.Contains("Unknown option"));
    }

    /// <summary>Verifies that parsing with non-numeric protocol version returns invalid protocol version.</summary>
    [Fact]
    public void Parse_WithNonNumericProtocolVersion_ReturnsInvalidProtocolVersion()
    {
        WorkerOptionsParser parser = new(CreateEnvironment("nonce-secret"));

        WorkerBootstrapResult result = parser.Parse(ValidArgs(protocolVersion: "abc"));

        Assert.False(result.Succeeded);
        Assert.Equal(WorkerExitCode.InvalidProtocolVersion, result.ExitCode);
    }

    /// <summary>Verifies that parsing with unsupported protocol version returns invalid protocol version.</summary>
    [Fact]
    public void Parse_WithUnsupportedProtocolVersion_ReturnsInvalidProtocolVersion()
    {
        WorkerOptionsParser parser = new(CreateEnvironment("nonce-secret"));

        WorkerBootstrapResult result = parser.Parse(ValidArgs(protocolVersion: "999"));

        Assert.False(result.Succeeded);
        Assert.Equal(WorkerExitCode.InvalidProtocolVersion, result.ExitCode);
    }

    /// <summary>Verifies that parsing with missing nonce returns missing nonce error.</summary>
    [Fact]
    public void Parse_WithMissingNonce_ReturnsMissingNonce()
    {
        WorkerOptionsParser parser = new(new MemoryWorkerEnvironment());

        WorkerBootstrapResult result = parser.Parse(ValidArgs());

        Assert.False(result.Succeeded);
        Assert.Equal(WorkerExitCode.MissingNonce, result.ExitCode);
    }

    private static string[] ValidArgs(string? protocolVersion = null)
    {
        return
        [
            "--session-id",
            "session-1",
            "--pipe-name",
            "mxaccess-gateway-123-session-1",
            "--protocol-version",
            protocolVersion ?? GatewayContractInfo.WorkerProtocolVersion.ToString(),
        ];
    }

    private static MemoryWorkerEnvironment CreateEnvironment(string nonce)
    {
        MemoryWorkerEnvironment environment = new();
        environment.Set(WorkerOptions.NonceEnvironmentVariableName, nonce);
        return environment;
    }
}
