using System.Collections.Generic;

namespace ZB.MOM.WW.LmxProxy.Host.Domain
{
    /// <summary>
    ///     Maps MxAccess MXSTATUS_PROXY fields (detail, category, source) to
    ///     human-readable messages and OPC UA quality codes.
    /// </summary>
    public static class MxStatusMapper
    {
        // ── MxStatusDetail (short) → name + client message ──────────

        private static readonly Dictionary<int, (string Name, string Message)> DetailCodes =
            new Dictionary<int, (string, string)>
            {
                { 0,    ("MX_S_Success",                    "Success") },
                { 1,    ("MX_E_RequestTimedOut",            "Request to AVEVA System Platform timed out") },
                { 2,    ("MX_E_PlatformCommunicationError", "Communication error with System Platform") },
                { 3,    ("MX_E_InvalidPlatformId",          "Invalid platform identifier") },
                { 4,    ("MX_E_InvalidEngineId",            "Invalid engine identifier") },
                { 5,    ("MX_E_EngineCommunicationError",   "Communication error with automation engine") },
                { 6,    ("MX_E_InvalidReference",           "Tag reference is invalid or could not be resolved") },
                { 7,    ("MX_E_NoGalaxyRepository",         "Galaxy repository is not available") },
                { 8,    ("MX_E_InvalidObjectId",            "Invalid object identifier") },
                { 9,    ("MX_E_ObjectSignatureMismatch",    "Object signature mismatch") },
                { 10,   ("MX_E_AttributeSignatureMismatch", "Attribute signature mismatch") },
                { 11,   ("MX_E_ResolvingAttribute",         "Attribute is still being resolved") },
                { 12,   ("MX_E_ResolvingObject",            "Object is still being resolved") },
                { 13,   ("MX_E_WrongDataType",              "Value type does not match attribute data type") },
                { 14,   ("MX_E_WrongNumberOfDimensions",    "Wrong number of array dimensions") },
                { 15,   ("MX_E_InvalidIndex",               "Invalid array index") },
                { 16,   ("MX_E_IndexOutOfOrder",            "Array index out of order") },
                { 17,   ("MX_E_DimensionDoesNotExist",      "Array dimension does not exist") },
                { 18,   ("MX_E_ConversionNotSupported",     "Data type conversion not supported") },
                { 19,   ("MX_E_UnableToConvertString",      "Unable to convert string to target type") },
                { 20,   ("MX_E_Overflow",                   "Numeric overflow during conversion") },
                { 21,   ("MX_E_NmxVersionMismatch",         "NMX version mismatch") },
                { 22,   ("MX_E_NmxInvalidCommand",          "NMX invalid command") },
                { 23,   ("MX_E_LmxVersionMismatch",         "LMX version mismatch") },
                { 24,   ("MX_E_LmxInvalidCommand",          "LMX invalid command") },
                { 25,   ("MX_E_GalaxyRepositoryBusy",       "Galaxy repository is busy") },
                { 26,   ("MX_E_EngineOverloaded",           "Automation engine is overloaded") },
                { 1000, ("MX_E_InvalidPrimitiveId",         "Invalid primitive identifier") },
                { 1001, ("MX_E_InvalidAttributeId",         "Invalid attribute identifier") },
                { 1002, ("MX_E_InvalidPropertyId",          "Invalid property identifier") },
                { 1003, ("MX_E_IndexOutOfRange",            "Array index out of range") },
                { 1004, ("MX_E_DataOutOfRange",             "Data value out of range") },
                { 1005, ("MX_E_IncorrectDataType",          "Incorrect data type for this attribute") },
                { 1006, ("MX_E_NotReadable",                "Attribute is not readable") },
                { 1007, ("MX_E_NotWriteable",               "Attribute is not writable") },
                { 1008, ("MX_E_WriteAccessDenied",          "Write access denied — insufficient security") },
                { 1009, ("MX_E_UnknownError",               "Unknown MxAccess error") },
                { 1010, ("MX_E_ObjectInitializing",         "Object is still initializing") },
                { 1011, ("MX_E_EngineInitializing",         "Automation engine is still initializing") },
                { 1012, ("MX_E_SecuredWrite",               "Attribute requires secured write authentication") },
                { 1013, ("MX_E_VerifiedWrite",              "Attribute requires verified write (two-user)") },
                { 1014, ("MX_E_NoAlarmAckPrivilege",        "No alarm acknowledgment privilege") },
                { 8000, ("MX_E_AutomationObjectSpecificError", "Automation object specific error") },
            };

        // ── MxStatusCategory (int) → name ──────────

        private static readonly Dictionary<int, string> CategoryNames = new Dictionary<int, string>
        {
            { -1, "Unknown" },
            { 0,  "Ok" },
            { 1,  "Pending" },
            { 2,  "Warning" },
            { 3,  "CommunicationError" },
            { 4,  "ConfigurationError" },
            { 5,  "OperationalError" },
            { 6,  "SecurityError" },
            { 7,  "SoftwareError" },
            { 8,  "OtherError" },
        };

        // ── MxStatusSource (int) → name ──────────

        private static readonly Dictionary<int, string> SourceNames = new Dictionary<int, string>
        {
            { -1, "Unknown" },
            { 0,  "RequestingLmx" },
            { 1,  "RespondingLmx" },
            { 2,  "RequestingNmx" },
            { 3,  "RespondingNmx" },
            { 4,  "RequestingAutomationObject" },
            { 5,  "RespondingAutomationObject" },
        };

        /// <summary>
        ///     Gets the symbolic name for an MxStatusDetail code (e.g., "MX_E_WrongDataType").
        /// </summary>
        public static string GetDetailName(int detailCode)
        {
            return DetailCodes.TryGetValue(detailCode, out var entry) ? entry.Name : string.Format("MX_E_Unknown({0})", detailCode);
        }

        /// <summary>
        ///     Gets a human-readable client message for an MxStatusDetail code.
        /// </summary>
        public static string GetDetailMessage(int detailCode)
        {
            return DetailCodes.TryGetValue(detailCode, out var entry) ? entry.Message : string.Format("MxAccess error code {0}", detailCode);
        }

        /// <summary>
        ///     Gets the symbolic name for an MxStatusCategory value.
        /// </summary>
        public static string GetCategoryName(int category)
        {
            return CategoryNames.TryGetValue(category, out var name) ? name : string.Format("Unknown({0})", category);
        }

        /// <summary>
        ///     Gets the symbolic name for an MxStatusSource value.
        /// </summary>
        public static string GetSourceName(int source)
        {
            return SourceNames.TryGetValue(source, out var name) ? name : string.Format("Unknown({0})", source);
        }

        /// <summary>
        ///     Builds a detailed error string from all MXSTATUS_PROXY fields.
        ///     Format: "MX_E_WrongDataType: Value type does not match attribute data type [Category=OperationalError, Source=RespondingAutomationObject]"
        /// </summary>
        public static string FormatStatus(int detail, int category, int source)
        {
            return string.Format("{0}: {1} [Category={2}, Source={3}]",
                GetDetailName(detail),
                GetDetailMessage(detail),
                GetCategoryName(category),
                GetSourceName(source));
        }

        /// <summary>
        ///     Maps an MxStatusCategory to the most appropriate OPC UA QualityCode.
        ///     Used when MXSTATUS_PROXY.success is false in an OnDataChange callback
        ///     to override the raw OPC DA quality byte.
        /// </summary>
        public static Quality CategoryToQuality(int category, int detail)
        {
            // Specific detail codes take priority
            switch (detail)
            {
                case 6:    // MX_E_InvalidReference
                case 1001: // MX_E_InvalidAttributeId
                    return Quality.Bad_ConfigError;
                case 2:    // MX_E_PlatformCommunicationError
                case 5:    // MX_E_EngineCommunicationError
                    return Quality.Bad_CommFailure;
                case 11:   // MX_E_ResolvingAttribute
                case 12:   // MX_E_ResolvingObject
                case 1010: // MX_E_ObjectInitializing
                case 1011: // MX_E_EngineInitializing
                    return Quality.Bad_WaitingForInitialData;
                case 1006: // MX_E_NotReadable
                    return Quality.Bad_OutOfService;
                case 1:    // MX_E_RequestTimedOut
                    return Quality.Bad_CommFailure;
            }

            // Fall back to category
            switch (category)
            {
                case 0:  // MxCategoryOk
                    return Quality.Good;
                case 1:  // MxCategoryPending
                    return Quality.Uncertain;
                case 2:  // MxCategoryWarning
                    return Quality.Uncertain;
                case 3:  // MxCategoryCommunicationError
                    return Quality.Bad_CommFailure;
                case 4:  // MxCategoryConfigurationError
                    return Quality.Bad_ConfigError;
                case 5:  // MxCategoryOperationalError
                    return Quality.Bad;
                case 6:  // MxCategorySecurityError
                    return Quality.Bad;
                case 7:  // MxCategorySoftwareError
                    return Quality.Bad;
                default:
                    return Quality.Bad;
            }
        }
    }
}
