namespace ZB.MOM.WW.OtOpcUa.Driver.FOCAS.Wire;

/// <summary>
///     Thrown by the wire client when a FOCAS request fails — either at the protocol layer
///     (invalid PDU magic, desynchronised response framing, connection dropped mid-request)
///     or when the CNC returns a non-zero <c>EW_*</c> return code.
/// </summary>
/// <remarks>
///     <para>Callers distinguish the two classes via <see cref="IsTransient"/>: <c>true</c>
///     when the transport is gone (socket closed, timeout, cancellation mid-write) and the
///     wire client has already torn the sockets down, so a reconnect is required before any
///     further call. <c>false</c> for protocol-level errors where the connection is still
///     usable.</para>
///     <para><see cref="Rc"/> carries the wire-level FOCAS return code when the exception
///     came from a parsed response block. Null when the failure happened before a response
///     was received (e.g. connect-time handshake errors).</para>
/// </remarks>
public class FocasWireException : Exception
{
    /// <summary>FOCAS <c>EW_*</c> return code from the response block, when available.</summary>
    public short? Rc { get; }

    /// <summary>
    ///     True when the transport was closed as a side effect of this failure — the caller
    ///     must reconnect before issuing the next request.
    /// </summary>
    public bool IsTransient { get; }

    /// <summary>Initializes a new FOCAS wire exception with a message.</summary>
    /// <param name="message">The exception message.</param>
    public FocasWireException(string message)
        : base(message)
    {
    }

    /// <summary>Initializes a new FOCAS wire exception with message, return code, and transient flag.</summary>
    /// <param name="message">The exception message.</param>
    /// <param name="rc">The FOCAS return code, if available.</param>
    /// <param name="isTransient">Whether the transport was closed.</param>
    public FocasWireException(string message, short? rc, bool isTransient = false)
        : base(message)
    {
        Rc = rc;
        IsTransient = isTransient;
    }

    /// <summary>Initializes a new FOCAS wire exception with a message and inner exception.</summary>
    /// <param name="message">The exception message.</param>
    /// <param name="innerException">The inner exception.</param>
    public FocasWireException(string message, Exception innerException)
        : base(message, innerException)
    {
    }

    /// <summary>Initializes a new FOCAS wire exception with message, inner exception, and transient flag.</summary>
    /// <param name="message">The exception message.</param>
    /// <param name="innerException">The inner exception.</param>
    /// <param name="isTransient">Whether the transport was closed.</param>
    public FocasWireException(string message, Exception innerException, bool isTransient)
        : base(message, innerException)
    {
        IsTransient = isTransient;
    }
}
