
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using StandardScene.Utils;
using SimpleCore;
using SimpleCore.Library;

namespace StandardScene.ExtendDevice.ButtonBox
{
    /// <summary>
    /// Azowie 呼叫器按钮盒实现
    /// 基于 Modbus TCP 协议
    /// </summary>
    public class AzowieButtonBox : BasicButtonBox
    {
        /// <summary>
        /// Modbus TCP 客户端
        /// </summary>
        private ModbusRtu _modbusClient;

        /// <summary>
        /// 同步锁
        /// </summary>
        private readonly object _syncLock = new object();

        /// <summary>
        /// 是否已启动
        /// </summary>
        private bool _isStarted = false;

        /// <summary>
        /// 定时读取任务取消令牌
        /// </summary>
        private CancellationTokenSource _cancellationTokenSource;

        /// <summary>
        /// 定时读取任务
        /// </summary>
        private Task _readTask;

        /// <summary>
        /// 读取间隔（毫秒），默认500ms
        /// </summary>
        public int ReadInterval { get; set; } = 500;

        /// <summary>
        /// 重连间隔（毫秒），默认3000ms，避免过于频繁的重连
        /// </summary>
        public int ReconnectInterval { get; set; } = 3000;

        /// <summary>
        /// 上次重连尝试时间
        /// </summary>
        private DateTime _lastReconnectAttempt = DateTime.MinValue;

        /// <summary>
        /// Modbus 从站地址，默认1
        /// </summary>
        public byte SlaveAddress { get; set; } = 1;

        /// <summary>
        /// 呼叫器编号（只读）
        /// </summary>
        public int DeviceId { get; private set; } = 0;

        /// <summary>
        /// 电池电量（0-100）
        /// </summary>
        public int BatteryLevel { get; private set; } = 0;

        /// <summary>
        /// 按钮灯状态字典
        /// </summary>
        public Dictionary<int, ButtonLightState> ButtonLightStates { get; private set; } = new Dictionary<int, ButtonLightState>();

        /// <summary>
        /// 按钮灯状态枚举
        /// </summary>
        public enum ButtonLightState
        {
            /// <summary>
            /// 常灭
            /// </summary>
            Off = 0,
            /// <summary>
            /// 常亮
            /// </summary>
            On = 1,
            /// <summary>
            /// 快闪，间隔0.5秒
            /// </summary>
            FastBlink = 2,
            /// <summary>
            /// 慢闪，间隔2秒
            /// </summary>
            SlowBlink = 3
        }

        /// <summary>
        /// 连接按钮盒
        /// </summary>
        public override void Connect()
        {
            lock (_syncLock)
            {
                if (_isStarted)
                {
                    return;
                }

                try
                {
                    UpdateState(ButtonBoxState.Connecting);

                    // 根据配置的按钮初始化按钮状态
                    var buttonIndices = ButtonConfigs.Keys.OrderBy(k => k).ToList();
                    if (buttonIndices.Count == 0)
                    {
                        // 如果没有配置，默认初始化按钮1-8
                        buttonIndices = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8 };
                    }
                    InitializeButtons(buttonIndices);

                    // 初始化按钮灯状态
                    foreach (var index in buttonIndices)
                    {
                        ButtonLightStates[index] = ButtonLightState.Off;
                    }

                    // 尝试连接 Modbus TCP 客户端
                    try
                    {
                        _modbusClient = new ModbusRtu();
                        _modbusClient.StartTcpRtu(Ip, Port);
                        UpdateState(ButtonBoxState.Online);
                    }
                    catch (Exception connectEx)
                    {
                        // 初次连接失败，但不阻止启动读取循环，循环中会持续重连
                        UpdateState(ButtonBoxState.Connecting);
                        Diagnosis.Log($"AzowieButtonBox[{Index}] 初次连接失败，将在后台持续重连: {ExceptionFormatter.FormatEx(connectEx)}", "AzowieButtonBox", true);
                    }

                    // 启动定时读取任务（即使连接失败也会启动，循环中会持续重连）
                    _cancellationTokenSource = new CancellationTokenSource();
                    _readTask = Task.Run(() => ReadButtonStatesLoop(_cancellationTokenSource.Token));

                    _isStarted = true;
                }
                catch (Exception ex)
                {
                    UpdateState(ButtonBoxState.Error, $"初始化失败: {ex.Message}");
                    _isStarted = false;
                    Diagnosis.Log($"AzowieButtonBox[{Index}] 初始化失败: {ExceptionFormatter.FormatEx(ex)}", "AzowieButtonBox", true);
                }
            }
        }

        /// <summary>
        /// 断开连接
        /// </summary>
        public override void Disconnect()
        {
            lock (_syncLock)
            {
                if (!_isStarted || _modbusClient == null)
                {
                    return;
                }

                try
                {
                    // 停止读取任务
                    _cancellationTokenSource?.Cancel();
                    _readTask?.Wait(1000);

                    // 关闭 Modbus 连接
                    _modbusClient?.Close();
                    _modbusClient = null;

                    _isStarted = false;
                    UpdateState(ButtonBoxState.Offline);
                }
                catch (Exception ex)
                {
                    UpdateState(ButtonBoxState.Error, $"断开连接失败: {ex.Message}");
                    Diagnosis.Log($"AzowieButtonBox[{Index}] 断开连接失败: {ExceptionFormatter.FormatEx(ex)}", "AzowieButtonBox", true);
                }
            }
        }

        /// <summary>
        /// 定时读取按钮状态循环
        /// </summary>
        private void ReadButtonStatesLoop(CancellationToken cancellationToken)
        {
            while (!cancellationToken.IsCancellationRequested)
            {
                try
                {
                    if (!_isStarted)
                    {
                        break;
                    }

                    // 检查连接状态，如果未连接或连接断开，尝试重连
                    bool isConnected = _modbusClient?.modbusRtu?.Connected ?? false;
                    if (_modbusClient == null || !isConnected)
                    {
                        UpdateState(ButtonBoxState.Connecting);
                        
                        // 控制重连频率，避免过于频繁的重连导致资源浪费
                        var timeSinceLastReconnect = (DateTime.Now - _lastReconnectAttempt).TotalMilliseconds;
                        if (timeSinceLastReconnect >= ReconnectInterval)
                        {
                            _lastReconnectAttempt = DateTime.Now;
                            TryReconnect();
                        }
                        
                        // 如果重连后仍然未连接，等待后继续下一次循环
                        isConnected = _modbusClient?.modbusRtu?.Connected ?? false;
                        if (_modbusClient == null || !isConnected)
                        {
                            Thread.Sleep(ReadInterval);
                            continue;
                        }
                    }

                    // 读取按钮状态（寄存器 01-04 对应按钮1-4，21-24 对应按钮5-8）
                    ReadButtonStates();

                    // 读取设备信息（每5秒读取一次）
                    //if (DateTime.Now.Second % 5 == 0)
                    //{
                    //    ReadDeviceInfo();
                    //}

                    // 更新在线状态
                    UpdateState(ButtonBoxState.Online);
                }
                catch (Exception ex)
                {
                    Diagnosis.Log($"AzowieButtonBox[{Index}] 读取状态失败: {ExceptionFormatter.FormatEx(ex)}", "AzowieButtonBox", true);
                    UpdateState(ButtonBoxState.Error, $"读取状态失败: {ex.Message}");
                    
                    // 如果连接失败，尝试重连
                    TryReconnect();
                }

                // 等待指定间隔
                Thread.Sleep(ReadInterval);
            }
        }

        /// <summary>
        /// 尝试重连 Modbus TCP 连接
        /// </summary>
        private void TryReconnect()
        {
            ModbusRtu oldClient = null;
            try
            {
                // 安全关闭旧连接
                if (_modbusClient != null)
                {
                    oldClient = _modbusClient;
                    _modbusClient = null; // 先置空，避免并发访问
                    
                    try
                    {
                        oldClient.Close();
                    }
                    catch
                    {
                        // 忽略关闭时的异常，继续创建新连接
                    }
                    finally
                    {
                        oldClient = null; // 确保引用释放
                    }
                }

                // 创建新连接
                _modbusClient = new ModbusRtu();
                _modbusClient.StartTcpRtu(Ip, Port);
                
                Diagnosis.Log($"AzowieButtonBox[{Index}] 重连成功", "AzowieButtonBox", false);
            }
            catch (Exception ex)
            {
                // 重连失败，确保资源释放
                if (_modbusClient != null)
                {
                    try
                    {
                        _modbusClient.Close();
                    }
                    catch
                    {
                        // 忽略关闭异常
                    }
                    _modbusClient = null;
                }
                
                // 记录日志但不抛出异常，等待下次循环继续尝试
                Diagnosis.Log($"AzowieButtonBox[{Index}] 重连失败: {ExceptionFormatter.FormatEx(ex)}", "AzowieButtonBox", false);
            }
        }

        /// <summary>
        /// 读取按钮状态
        /// 根据配置的按钮数量和编号读取对应的寄存器
        /// </summary>
        private void ReadButtonStates()
        {
            try
            {
                // 获取配置的按钮索引列表
                var configuredButtons = ButtonConfigs.Keys.OrderBy(k => k).ToList();
                if (configuredButtons.Count == 0)
                {
                    // 如果没有配置，默认读取按钮1-8
                    configuredButtons = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8 };
                }

                // 将按钮分为两组：按钮1-4（寄存器01-04）和按钮5-8（寄存器21-24）
                var buttons1_4 = configuredButtons.Where(b => b >= 1 && b <= 4).OrderBy(b => b).ToList();
                var buttons5_8 = configuredButtons.Where(b => b >= 5 && b <= 8).OrderBy(b => b).ToList();

                // 读取按钮1-4的状态（寄存器地址 01-04）
                // 按钮索引直接对应寄存器地址：按钮1->寄存器01，按钮2->寄存器02，按钮3->寄存器03，按钮4->寄存器04
                if (buttons1_4.Count > 0)
                {
                    // 计算需要读取的寄存器范围（从最小按钮索引到最大按钮索引）
                    var minButton = buttons1_4.Min();
                    var maxButton = buttons1_4.Max();
                    var startReg = (ushort)minButton; // 按钮索引直接对应寄存器地址
                    var count = maxButton - minButton + 1;
                    
                    var buttonStates1_4 = _modbusClient.ReadRegisterBuffer_03(SlaveAddress, startReg, (ushort)count);
                    
                    // 将读取结果映射到对应的按钮索引
                    foreach (var buttonIndex in buttons1_4)
                    {
                        // 计算该按钮在读取结果数组中的位置
                        var arrayIndex = buttonIndex - minButton;
                        if (arrayIndex >= 0 && arrayIndex < buttonStates1_4.Length)
                        {
                            var state = buttonStates1_4[arrayIndex];
                            UpdateButtonState(buttonIndex, state == 1 ? ButtonState.Pressed : ButtonState.Released);
                        }
                    }
                }

                // 读取按钮5-8的状态（寄存器地址 21-24）
                // 按钮索引对应寄存器地址：按钮5->寄存器21，按钮6->寄存器22，按钮7->寄存器23，按钮8->寄存器24
                // 寄存器地址 = 20 + 按钮索引
                if (buttons5_8.Count > 0)
                {
                    var minButton = buttons5_8.Min();
                    var maxButton = buttons5_8.Max();
                    var startReg = (ushort)(20 + minButton); // 按钮5对应寄存器21
                    var count = maxButton - minButton + 1;
                    
                    var buttonStates5_8 = _modbusClient.ReadRegisterBuffer_03(SlaveAddress, startReg, (ushort)count);
                    
                    // 将读取结果映射到对应的按钮索引
                    foreach (var buttonIndex in buttons5_8)
                    {
                        // 计算该按钮在读取结果数组中的位置
                        var arrayIndex = buttonIndex - minButton;
                        if (arrayIndex >= 0 && arrayIndex < buttonStates5_8.Length)
                        {
                            var state = buttonStates5_8[arrayIndex];
                            UpdateButtonState(buttonIndex, state == 1 ? ButtonState.Pressed : ButtonState.Released);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                throw new Exception($"读取按钮状态失败: {ex.Message}", ex);
            }
        }

        /// <summary>
        /// 更新按钮配置信息
        /// 当配置变化时，同步更新按钮状态和按钮灯状态字典
        /// </summary>
        /// <param name="buttonConfigs">按钮配置列表</param>
        public override void UpdateButtonConfigs(List<ButtonModel> buttonConfigs)
        {
            lock (_syncLock)
            {
                // 保存旧的按钮索引列表
                var oldButtonIndices = new HashSet<int>(ButtonConfigs.Keys);
                
                // 调用基类方法更新配置
                base.UpdateButtonConfigs(buttonConfigs);
                
                // 获取新的按钮索引列表
                var newButtonIndices = new HashSet<int>(ButtonConfigs.Keys);
                
                // 如果配置发生变化，更新按钮状态和按钮灯状态字典
                if (!oldButtonIndices.SetEquals(newButtonIndices))
                {
                    // 移除已删除的按钮状态
                    var toRemove = oldButtonIndices.Where(k => !newButtonIndices.Contains(k)).ToList();
                    foreach (var index in toRemove)
                    {
                        ButtonStates.Remove(index);
                        ButtonLightStates.Remove(index);
                    }
                    
                    // 添加新按钮的状态（初始化为未按下和常灭）
                    var toAdd = newButtonIndices.Where(k => !oldButtonIndices.Contains(k)).ToList();
                    foreach (var index in toAdd)
                    {
                        if (!ButtonStates.ContainsKey(index))
                        {
                            ButtonStates[index] = ButtonState.Released;
                        }
                        if (!ButtonLightStates.ContainsKey(index))
                        {
                            ButtonLightStates[index] = ButtonLightState.Off;
                        }
                    }
                    
                    // 如果没有配置，默认初始化按钮1-8
                    if (newButtonIndices.Count == 0)
                    {
                        var defaultButtons = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8 };
                        InitializeButtons(defaultButtons);
                        foreach (var index in defaultButtons)
                        {
                            if (!ButtonLightStates.ContainsKey(index))
                            {
                                ButtonLightStates[index] = ButtonLightState.Off;
                            }
                        }
                    }
                    
                    Diagnosis.Log($"AzowieButtonBox[{Index}] 按钮配置已更新: 旧配置{oldButtonIndices.Count}个按钮, 新配置{newButtonIndices.Count}个按钮", "AzowieButtonBox", false);
                }
            }
        }

        /// <summary>
        /// 清零指定按钮的寄存器状态
        /// </summary>
        /// <param name="buttonIndex">按钮索引（1-8）</param>
        public override void ClearButtonRegister(int buttonIndex)
        {
            lock (_syncLock)
            {
                if (!_isStarted)
                {
                    return;
                }

                if (buttonIndex < 1 || buttonIndex > 8)
                {
                    Diagnosis.Log($"AzowieButtonBox[{Index}] 按钮索引超出范围: {buttonIndex}", "AzowieButtonBox", true);
                    return;
                }

                try
                {
                    // 检查连接状态，如果未连接则尝试重连
                    bool isConnected = _modbusClient?.modbusRtu?.Connected ?? false;
                    if (!isConnected)
                    {
                        // 尝试重连
                        TryReconnect();
                        isConnected = _modbusClient?.modbusRtu?.Connected ?? false;
                        
                        // 如果重连失败，记录日志并返回
                        if (!isConnected)
                        {
                            Diagnosis.Log($"AzowieButtonBox[{Index}] 清零按钮{buttonIndex}寄存器失败: 连接未建立", "AzowieButtonBox", true);
                            return;
                        }
                    }

                    // 根据按钮索引确定寄存器地址
                    // 按钮1-4对应寄存器01-04，按钮5-8对应寄存器21-24
                    ushort buttonRegisterAddress;
                    if (buttonIndex >= 1 && buttonIndex <= 4)
                    {
                        buttonRegisterAddress = (ushort)buttonIndex; // 按钮索引直接对应寄存器地址
                    }
                    else
                    {
                        buttonRegisterAddress = (ushort)(20 + buttonIndex); // 按钮5-8对应寄存器21-24
                    }

                    // 清零按钮状态寄存器
                    _modbusClient.WriteSingleRegister_06(SlaveAddress, buttonRegisterAddress, 0);

                    // 清零对应的按钮灯状态寄存器
                    // 按钮灯1-4对应寄存器05-08（按钮索引 + 4），按钮灯5-8对应寄存器25-28（按钮索引 + 20）
                    ushort lightRegisterAddress;
                    if (buttonIndex is >= 1 and <= 4)
                    {
                        lightRegisterAddress = (ushort)(4 + buttonIndex); // 按钮灯寄存器 = 按钮索引 + 4
                    }
                    else
                    {
                        lightRegisterAddress = (ushort)(20 + buttonIndex); // 按钮灯寄存器 = 按钮索引 + 20
                    }

                    _modbusClient.WriteSingleRegister_06(SlaveAddress, lightRegisterAddress, 0);

                    // 更新本地按钮灯状态
                    if (ButtonLightStates.ContainsKey(buttonIndex))
                    {
                        ButtonLightStates[buttonIndex] = ButtonLightState.Off;
                    }

                    Diagnosis.Log($"AzowieButtonBox[{Index}] 清零按钮{buttonIndex}状态和灯光寄存器成功", "AzowieButtonBox", false);
                }
                catch (Exception ex)
                {
                    Diagnosis.Log($"AzowieButtonBox[{Index}] 清零按钮{buttonIndex}寄存器失败: {ExceptionFormatter.FormatEx(ex)}", "AzowieButtonBox", true);
                    
                    // 如果是因为连接问题导致的异常，尝试重连
                    bool isConnected = _modbusClient?.modbusRtu?.Connected ?? false;
                    if (!isConnected)
                    {
                        TryReconnect();
                    }
                }
            }
        }

        /// <summary>
        /// 析构函数，确保资源释放
        /// </summary>
        ~AzowieButtonBox()
        {
            Disconnect();
        }
    }
}
