using ZB.MOM.WW.MxGateway.Contracts;

namespace ZB.MOM.WW.MxGateway.Server.Workers;

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

    /// <summary>
    /// Byte margin the worker-frame (pipe) maximum must keep above the public gRPC message cap so a
    /// gRPC payload accepted at the public boundary always fits inside one worker frame once wrapped
    /// in a <c>WorkerEnvelope</c> (correlation id, timestamps, oneof framing). Without this headroom
    /// the pipe max equals the gRPC max and a maximally-sized accepted request faults the whole
    /// session on the outbound write. 64 KiB is far larger than the fixed envelope overhead.
    /// </summary>
    public const int EnvelopeOverheadReserveBytes = 64 * 1024;

    /// <summary>
    /// Initializes worker frame protocol options with a session ID.
    /// </summary>
    /// <param name="sessionId">Identifier of the session.</param>
    public WorkerFrameProtocolOptions(string sessionId)
        : this(
            sessionId,
            GatewayContractInfo.WorkerProtocolVersion,
            DefaultMaxMessageBytes)
    {
    }

    /// <summary>
    /// Initializes worker frame protocol options with all parameters.
    /// </summary>
    /// <param name="sessionId">Identifier of the session.</param>
    /// <param name="protocolVersion">Protocol version number.</param>
    /// <param name="maxMessageBytes">Maximum message size in bytes.</param>
    public WorkerFrameProtocolOptions(
        string sessionId,
        uint protocolVersion,
        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 (maxMessageBytes <= 0)
        {
            throw new WorkerFrameProtocolException(
                WorkerFrameProtocolErrorCode.InvalidConfiguration,
                "Worker frame protocol max message size must be greater than zero.");
        }

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

    /// <summary>
    /// Gets the session identifier.
    /// </summary>
    public string SessionId { get; }

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

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