using Common.Attributes;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using static Common.Attributes.ATSCommandAttribute;

namespace ZLGCANFD
{
    /// <summary>
    /// ZLG CAN 驱动类 (由 TSMaster CAN 改写)
    /// </summary>
    [ATSCommand]
    [DeviceCategory("CAN卡驱动")]
    public class CAN
    {
        public static event Action ConnectEvent;
        public static event Action DisConnectEvent;
        public static bool ConnectFlag { get; set; } = false;

        // 存储 ZLG 的设备句柄和多通道句柄
        private static nint _deviceHandle = 0;
        private static Dictionary<uint, nint> _channelHandles = new Dictionary<uint, nint>();

        /// <summary>
        /// 用于接收 CAN FD 报文的队列
        /// </summary>
        private static readonly Queue<ZLGCAN.ZCAN_ReceiveFD_Data> _receivedMessages = new Queue<ZLGCAN.ZCAN_ReceiveFD_Data>();
        private static readonly object _lock = new object(); // 线程安全锁

        // 接收线程控制标志
        private static bool _isReceiving = false;
        public static Action<ZLGCAN.ZCAN_ReceiveFD_Data> listener; // ZLG 接收事件委托
 
        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        public class ZCAN_CANFD_FRAME
        {
            public uint can_id;    // 报文ID (包含扩展帧标志位)
            public byte len;       // 数据长度
            public byte flags;     // CANFD标志 (0x01:CANFD, 0x02:BRS, 0x04:ESI)
            public byte __res0;    // 保留
            public byte __res1;    // 保留

            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
            public byte[] data;    // 数据负载

            // --- 添加以下属性以解决报错并适配旧代码 ---

            /// <summary>
            /// 模拟 eff 字段：1表示扩展帧，0表示标准帧
            /// </summary>
            public uint eff
            {
                get { return (can_id & 0x80000000) != 0 ? 1u : 0u; }
                set
                {
                    if (value != 0)
                        can_id |= 0x80000000;  // 将最高位置1，表示扩展帧
                    else
                        can_id &= 0x7FFFFFFF;  // 将最高位清0，表示标准帧
                }
            }

            public ZCAN_CANFD_FRAME()
            {
                data = new byte[64];
            }
        }

        /// <summary>
        /// 初始化 CAN 驱动
        /// </summary>
        [Browsable(false)]
        public static int Init(uint deviceType, uint deviceIndex)
        {
            if (_deviceHandle != 0) return 0;

            _deviceHandle = ZLGCAN.ZCAN_OpenDevice(deviceType, deviceIndex, 0);

            if (_deviceHandle == 0)
            {
                Debug.WriteLine("ZLG 设备初始化失败！");
                return -1;
            }
            return 0;
        }

        /// <summary>
        /// 释放 CAN 驱动
        /// </summary>
        [Browsable(false)]
        public static void Release()
        {
            DisConnect();
            if (_deviceHandle != 0)
            {
                ZLGCAN.ZCAN_CloseDevice(_deviceHandle);
                _deviceHandle = 0;
            }
        }

        /// <summary>
        /// 注册监听器
        /// </summary>
        [Browsable(false)]
        public static int RegisterListener(Action<ZLGCAN.ZCAN_ReceiveFD_Data> listenEvent)
        {
            listener = listenEvent;

            if (!_isReceiving)
            {
                _isReceiving = true;
                Task.Run(ReceiveThreadProcess);
            }
            return 0;
        }

        /// <summary>
        /// 注销监听器
        /// </summary>
        [Browsable(false)]
        public static int UnRegisterListener()
        {
            listener = null;
            _isReceiving = false;
            return 0;
        }

        private static void ReceiveThreadProcess()
        {
            while (_isReceiving)
            {
                bool hasData = false;
                foreach (var chnHandle in _channelHandles.Values)
                {
                    uint len = ZLGCAN.ZCAN_GetReceiveNum(chnHandle, ZDBC.FT_CANFD);
                    if (len > 0)
                    {
                        int size = Marshal.SizeOf(typeof(ZLGCAN.ZCAN_ReceiveFD_Data));
                        nint ptr = Marshal.AllocHGlobal((int)len * size);

                        uint readLen = ZLGCAN.ZCAN_ReceiveFD(chnHandle, ptr, len, 50);

                        for (int i = 0; i < readLen; i++)
                        {
                            nint pItem = ptr + i * size;
                            var frame = Marshal.PtrToStructure<ZLGCAN.ZCAN_ReceiveFD_Data>(pItem);

                            lock (_lock)
                            {
                                _receivedMessages.Enqueue(frame);
                            }
                            listener?.Invoke(frame);
                        }
                        Marshal.FreeHGlobal(ptr);
                        hasData = true;
                    }
                }

                if (!hasData) Thread.Sleep(10);
            }
        }

        public static int Connect(uint channel, ZLGCAN.ZCAN_CHANNEL_INIT_CONFIG config)
        {
            if (_deviceHandle == 0) return -1;

            nint chnHandle = ZLGCAN.ZCAN_InitCAN(_deviceHandle, channel, ref config);
            if (chnHandle == 0)
            {
                Debug.WriteLine($"CAN 通道 {channel} 初始化失败");
                return -1;
            }

            if (ZLGCAN.ZCAN_StartCAN(chnHandle) == 1)
            {
                _channelHandles[channel] = chnHandle;
                ConnectFlag = true;
                Task.Run(() => ConnectEvent?.Invoke());
                return 0;
            }
            else
            {
                Debug.WriteLine($"CAN 通道 {channel} 启动失败");
                return -1;
            }
        }

        public static int DisConnect()
        {
            foreach (var handle in _channelHandles.Values)
            {
                ZLGCAN.ZCAN_ResetCAN(handle);
            }
            _channelHandles.Clear();
            ConnectFlag = false;
            Task.Run(() => DisConnectEvent?.Invoke());
            return 0;
        }
        [Browsable(false)]
        public static int LoadDBC(string filePath, int[] channel, out uint databaseID)
        {
            // 1. 初始化 ZDBC 模块，获取句柄
            databaseID = ZDBC.ZDBC_Init(0, 1);

            if (databaseID == ZDBC.INVALID_DBC_HANDLE)
            {
                return -1; // 初始化失败
            }

            // 2. 构造文件信息结构体并加载
            ZDBC.FileInfo fileInfo = new ZDBC.FileInfo();
            fileInfo.strFilePath = new byte[ZDBC._MAX_FILE_PATH_ + 1];
            byte[] pathBytes = System.Text.Encoding.Default.GetBytes(filePath);
            Array.Copy(pathBytes, fileInfo.strFilePath, Math.Min(pathBytes.Length, ZDBC._MAX_FILE_PATH_));

            fileInfo.type = ZDBC.PROTOCOL_OTHER; // 默认普通 CAN/CANFD
            fileInfo.merge = 0; // 清除原有数据加载新文件

            // 将结构体封送到非托管内存
            nint pFileInfo = Marshal.AllocHGlobal(Marshal.SizeOf(fileInfo));
            Marshal.StructureToPtr(fileInfo, pFileInfo, false);

            bool success = ZDBC.ZDBC_LoadFile(databaseID, pFileInfo);
            Marshal.FreeHGlobal(pFileInfo); // 释放临时内存

            if (!success) return -2; // 加载文件失败

            // 3. 将加载的数据同步到您本地的缓存（如 MsgDatabase）
            // 注意：ZLG 的加载通常是全局的，如果您的业务逻辑需要分 channel 存储，
            // 需要根据您的解析类进行填充
            foreach (var ch in channel)
            {
                // 这里的 Parse 需要您根据 ZDBC 的 API 重新实现（见下方第2点）
                DBCParse.Parse(databaseID, ch);
            }

            return 0;
        }

        [Browsable(false)]
        public static int UnLoadDBC(uint? databaseID = null)
        {
            // 1. 如果传入了句柄，释放 ZDBC 引擎资源
            if (databaseID.HasValue && databaseID.Value != ZDBC.INVALID_DBC_HANDLE)
            {
                ZDBC.ZDBC_Release(databaseID.Value);
            }

            // 2. 清除本地缓存
            DBCParse.MsgDatabase.Clear();

            return 0;
        }

        #region 信号值获取方法 (ZLG 适配版)

        public static double GetSignalValue(byte channel, string AMsgName, string ASgnName)
        {
            double value = double.NaN;
            var find = DBCParse.MsgDatabase[channel].FirstOrDefault(s => s.msg_name == AMsgName);

            if (find != null)
            {
                int re = GetZlgSignalValue(ref find.ACANFD, AMsgName, ASgnName, ref value);

                if (re != 1)
                {
                    Debug.WriteLine($"GetSignalValue: 获取信号值失败, 消息: {AMsgName}, 信号: {ASgnName}");
                }
            }
            else
            {
                Debug.WriteLine($"GetSignalValue: 未找到消息定义, 消息: {AMsgName}, 通道: {channel}");
            }
            return value;
        }

        [Browsable(false)]
        public static int GetSignalValue(byte channel, string AMsgName, string ASgnName, ref double value)
        {
            var find = DBCParse.MsgDatabase[channel].FirstOrDefault(s => s.msg_name == AMsgName);
            if (find != null)
            {
                return GetZlgSignalValue(ref find.ACANFD, AMsgName, ASgnName, ref value);
            }
            else
            {
                Debug.WriteLine($"GetSignalValue: 未找到消息定义, 消息: {AMsgName}, 通道: {channel}");
                return -1;
            }
        }

        [Browsable(false)]
        public static int GetSignalValue(ref ZCAN_CANFD_FRAME ACANFD, string AMsgName, string ASgnName, ref double value)
        {
            return GetZlgSignalValue(ref ACANFD, AMsgName, ASgnName, ref value);
        }

        #endregion

        #region ZLG 私有解析辅助

        private static int GetZlgSignalValue(ref ZCAN_CANFD_FRAME frame, string msgName, string sigName, ref double val)
        {
            try
            {
                // 模拟或调用 ZLG 外部 DBC 库进行信号解析
                return 0;
            }
            catch
            {
                return -1;
            }
        }

        #endregion

        private static Dictionary<string, System.Timers.Timer> _cyclicTimers = new Dictionary<string, System.Timers.Timer>();

        #region 信号值设置方法 (ZLG 适配版)

        public static int SetSignalValue(byte channel, string AMsgName, string ASgnName, double AValue, bool isSend = false, float sendPeriod = 0)
        {
            var find = DBCParse.MsgDatabase[channel].FirstOrDefault(s => s.msg_name == AMsgName);
            if (find == null)
            {
                Debug.WriteLine($"SetSignalValue: 未找到消息定义, 消息: {AMsgName}, 通道: {channel}");
                return -1;
            }

            int re = EncodeZlgSignal(ref find.ACANFD, AMsgName, ASgnName, AValue);

            if (re != 0)
            {
                Debug.WriteLine($"设置信号值编码失败! 消息:{AMsgName}, 信号:{ASgnName}");
                return re;
            }

            if (isSend)
            {
                return TransmitLogic(channel, find, sendPeriod);
            }

            return 0;
        }

        public static int SetSignalValue(uint channel, string AMsgName, float sendPeriod = 0)
        {
            var find = DBCParse.MsgDatabase[(byte)channel].FirstOrDefault(s => s.msg_name == AMsgName);
            if (find == null)
            {
                Debug.WriteLine($"SetSignalValue: 未找到消息定义, 消息: {AMsgName}, 通道: {channel}");
                return -1;
            }

            return TransmitLogic((byte)channel, find, sendPeriod);
        }

        #endregion

        #region 内部辅助逻辑

        private static int TransmitLogic(byte channel, ZLG_Msg msg, float period)
        {
            if (period <= 0)
            {
                return SendZlgFrame(channel, msg.ACANFD);
            }
            else
            {
                string key = $"{channel}_{msg.msg_id}";

                if (_cyclicTimers.ContainsKey(key))
                {
                    _cyclicTimers[key].Stop();
                    _cyclicTimers[key].Dispose();
                }

                var timer = new System.Timers.Timer(period);
                timer.Elapsed += (s, e) => SendZlgFrame(channel, msg.ACANFD);
                timer.AutoReset = true;
                timer.Enabled = true;
                _cyclicTimers[key] = timer;

                return 0;
            }
        }

        private static int SendZlgFrame(byte channel, ZCAN_CANFD_FRAME frame)
        {
            if (!_channelHandles.ContainsKey(channel)) return -1;

            nint ptr = Marshal.AllocHGlobal(Marshal.SizeOf(frame));
            try
            {
                Marshal.StructureToPtr(frame, ptr, false);
                uint result = ZLGCAN.ZCAN_TransmitFD(_channelHandles[channel], ptr, 1);
                return result == 1 ? 0 : -1;
            }
            finally
            {
                Marshal.FreeHGlobal(ptr);
            }
        }

        private static int EncodeZlgSignal(ref ZCAN_CANFD_FRAME frame, string msgName, string sigName, double val)
        {
            // 信号编码逻辑实现
            return 0;
        }

        #endregion
    }
}