namespace ZB.MOM.WW.OtOpcUa.Driver.TwinCAT;

/// <summary>
///     Maps AMS / ADS error codes to OPC UA StatusCodes. ADS error codes are taken from the
///     <c>AdsErrorCode</c> enum in <c>Beckhoff.TwinCAT.Ads</c> 7.x — numeric values are the
///     authoritative source (not the hex shorthand in older Beckhoff InfoSys pages, which has
///     known transcription errors). Key device-layer codes start at 0x0700 (1792 decimal).
/// </summary>
public static class TwinCATStatusMapper
{
    public const uint Good = 0u;

    // ---- OPC UA StatusCode constants ----
    public const uint BadInternalError      = 0x80020000u;
    public const uint BadNodeIdUnknown      = 0x80340000u;
    public const uint BadNotWritable        = 0x803B0000u;
    public const uint BadOutOfRange         = 0x803C0000u;
    public const uint BadNotSupported       = 0x803D0000u;
    public const uint BadDeviceFailure      = 0x808B0000u;
    public const uint BadCommunicationError = 0x80050000u;
    public const uint BadTimeout            = 0x800A0000u;
    public const uint BadTypeMismatch       = 0x80740000u;
    public const uint BadOutOfService       = 0x808D0000u;
    public const uint BadInvalidState       = 0x80AF0000u;

    // ---- AdsErrorCode numeric values (confirmed from Beckhoff.TwinCAT.Ads 7.0.172) ----

    /// <summary>
    ///     ADS <c>DeviceSymbolVersionInvalid</c> — error code 1809 (0x0711 decimal).
    ///     Raised by the runtime after a PLC program re-download: every symbol handle and
    ///     notification handle the driver holds is now stale. The driver treats this as an
    ///     <see cref="Core.Abstractions.IRediscoverable"/> trigger, not a connection error
    ///     (docs/v2/driver-specs.md §6).
    ///     <para>
    ///     Note: legacy Beckhoff InfoSys documentation sometimes cites this as "0x0702"; that
    ///     is a transcription error — 0x0702 is <c>DeviceInvalidGroup</c> (1794). The SDK enum
    ///     value 1809 (0x0711) is authoritative.
    ///     </para>
    /// </summary>
    public const uint AdsSymbolVersionChanged = 1809u; // DeviceSymbolVersionInvalid = 0x0711

    /// <summary>True when <paramref name="adsError"/> is the symbol-version-changed code.</summary>
    /// <param name="adsError">The ADS error code to check.</param>
    /// <returns>True if the error code indicates symbol version changed.</returns>
    public static bool IsSymbolVersionChanged(uint adsError) => adsError == AdsSymbolVersionChanged;

    /// <summary>
    ///     Map an AMS / ADS error code (uint cast from <c>AdsErrorCode</c> enum) to an OPC UA
    ///     StatusCode. 0 = success. Device-layer codes (0x0700–0x073F) cover the operations a
    ///     driver actually encounters during normal runtime.
    /// </summary>
    /// <param name="adsError">The ADS error code to map.</param>
    /// <returns>The corresponding OPC UA status code.</returns>
    public static uint MapAdsError(uint adsError) => adsError switch
    {
        0                      => Good,

        // AMS router / transport errors
        6 or 7                 => BadCommunicationError, // TargetPortNotFound / TargetMachineNotFound
        1285 or 1290           => BadCommunicationError, // RouterNotInitialized / RouterNotActive

        // Device-layer codes (Beckhoff.TwinCAT.Ads AdsErrorCode enum, confirmed 7.0.172)
        1792                   => BadDeviceFailure,    // DeviceError (generic device error)
        1793                   => BadNotSupported,     // DeviceServiceNotSupported
        1794                   => BadOutOfRange,       // DeviceInvalidGroup (ADS index-group error)
        1795                   => BadOutOfRange,       // DeviceInvalidOffset (ADS index-offset error)
        1796                   => BadNotWritable,      // DeviceInvalidAccess (write-access denied)
        1797                   => BadOutOfRange,       // DeviceInvalidSize (size mismatch)
        1798                   => BadTypeMismatch,     // DeviceInvalidData (data format mismatch)
        1799                   => BadOutOfService,     // DeviceNotReady (PLC not running / in config)
        1804                   => BadNodeIdUnknown,    // DeviceNotFound
        1807                   => BadDeviceFailure,    // DeviceIncompatible (0x070E)
        1808                   => BadNodeIdUnknown,    // DeviceSymbolNotFound (0x0710)
        1809                   => BadInvalidState,     // DeviceSymbolVersionInvalid — rediscovery trigger
        1810                   => BadInvalidState,     // DeviceInvalidState (PLC in Config mode, 0x0712)
        1811                   => BadNotSupported,     // DeviceTransModeNotSupported (0x0713)
        1812                   => BadNodeIdUnknown,    // DeviceNotifyHandleInvalid (stale handle, 0x0714)
        1827                   => BadNotWritable,      // DeviceAccessDenied (0x0723)
        1844                   => BadOutOfRange,       // DeviceOutOfRange (0x0734)

        // Client-layer timeout
        1861                   => BadTimeout,          // ClientSyncTimeOut (0x0745)

        _                      => BadCommunicationError,
    };
}
