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

namespace ZB.MOM.WW.MxGateway.Worker.Ipc;

/// <summary>Configuration options for the worker frame protocol.</summary>
public sealed class WorkerFrameProtocolOptions
{
    /// <summary>Default maximum message size in bytes (16 MB).</summary>
    public const int DefaultMaxMessageBytes = 16 * 1024 * 1024;

    /// <summary>Initializes a new instance of the WorkerFrameProtocolOptions class from WorkerOptions.</summary>
    /// <param name="options">Worker initialization options.</param>
    public WorkerFrameProtocolOptions(WorkerOptions options)
        : this(
            options?.SessionId ?? throw new ArgumentNullException(nameof(options)),
            options.ProtocolVersion,
            options.Nonce,
            DefaultMaxMessageBytes)
    {
    }

    /// <summary>Initializes a new instance of the WorkerFrameProtocolOptions class with default max message bytes.</summary>
    /// <param name="sessionId">Identifier of the session.</param>
    /// <param name="protocolVersion">Protocol version.</param>
    /// <param name="nonce">Nonce for startup validation.</param>
    public WorkerFrameProtocolOptions(
        string sessionId,
        uint protocolVersion,
        string nonce)
        : this(
            sessionId,
            protocolVersion,
            nonce,
            DefaultMaxMessageBytes)
    {
    }

    /// <summary>Initializes a new instance of the WorkerFrameProtocolOptions class with all parameters.</summary>
    /// <param name="sessionId">Identifier of the session.</param>
    /// <param name="protocolVersion">Protocol version.</param>
    /// <param name="nonce">Nonce for startup validation.</param>
    /// <param name="maxMessageBytes">Maximum message size in bytes.</param>
    public WorkerFrameProtocolOptions(
        string sessionId,
        uint protocolVersion,
        string nonce,
        int maxMessageBytes)
    {
        if (string.IsNullOrWhiteSpace(sessionId))
        {
            throw new WorkerFrameProtocolException(
                WorkerFrameProtocolErrorCode.InvalidConfiguration,
                "Worker frame protocol requires a session id.");
        }

        if (protocolVersion == 0)
        {
            throw new WorkerFrameProtocolException(
                WorkerFrameProtocolErrorCode.InvalidConfiguration,
                "Worker frame protocol requires a non-zero protocol version.");
        }

        if (protocolVersion != GatewayContractInfo.WorkerProtocolVersion)
        {
            throw new WorkerFrameProtocolException(
                WorkerFrameProtocolErrorCode.ProtocolVersionMismatch,
                $"Worker frame protocol version {protocolVersion} is not supported.");
        }

        if (string.IsNullOrWhiteSpace(nonce))
        {
            throw new WorkerFrameProtocolException(
                WorkerFrameProtocolErrorCode.InvalidConfiguration,
                "Worker frame protocol requires a nonce.");
        }

        if (maxMessageBytes <= 0)
        {
            throw new WorkerFrameProtocolException(
                WorkerFrameProtocolErrorCode.InvalidConfiguration,
                "Worker frame protocol max message size must be greater than zero.");
        }

        SessionId = sessionId;
        ProtocolVersion = protocolVersion;
        Nonce = nonce;
        MaxMessageBytes = maxMessageBytes;
    }

    /// <summary>Gets the session ID for the worker protocol.</summary>
    public string SessionId { get; }

    /// <summary>Gets the protocol version.</summary>
    public uint ProtocolVersion { get; }

    /// <summary>Gets the nonce for startup validation.</summary>
    public string Nonce { get; }

    /// <summary>Gets the maximum message size in bytes.</summary>
    public int MaxMessageBytes { get; }
}
