using ZB.MOM.WW.OtOpcUa.Core.Abstractions;

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

/// <summary>Map a Logix atomic type to the driver-surface <see cref="DriverDataType"/>.</summary>
public static class AbCipDataTypeExtensions
{
    /// <summary>
    ///     Map to the driver-agnostic type the server's address-space builder consumes.
    ///     <c>DriverDataType</c> carries Int64, UInt32, and UInt64 so each Logix type maps
    ///     to the widest correct signed/unsigned equivalent without silent truncation:
    ///     <list type="bullet">
    ///         <item>LInt (signed 64-bit) → Int64; ULInt (unsigned 64-bit) → UInt64.</item>
    ///         <item>UDInt (unsigned 32-bit) → UInt32 so values above Int32.MaxValue are not
    ///             wrapped to negative.</item>
    ///         <item>USInt / UInt widen into Int32; they can never overflow it.</item>
    ///     </list>
    /// </summary>
    /// <param name="t">The Logix data type to convert.</param>
    /// <returns>The corresponding driver data type.</returns>
    public static DriverDataType ToDriverDataType(this AbCipDataType t) => t switch
    {
        AbCipDataType.Bool => DriverDataType.Boolean,
        AbCipDataType.SInt or AbCipDataType.Int or AbCipDataType.DInt => DriverDataType.Int32,
        AbCipDataType.USInt or AbCipDataType.UInt => DriverDataType.Int32,
        AbCipDataType.UDInt => DriverDataType.UInt32,
        AbCipDataType.LInt => DriverDataType.Int64,
        AbCipDataType.ULInt => DriverDataType.UInt64,
        AbCipDataType.Real => DriverDataType.Float32,
        AbCipDataType.LReal => DriverDataType.Float64,
        AbCipDataType.String => DriverDataType.String,
        AbCipDataType.Dt => DriverDataType.Int32, // epoch-seconds DINT
        AbCipDataType.Structure => DriverDataType.String, // placeholder until UDT introduces a structured kind
        _ => DriverDataType.Int32,
    };
}
