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

namespace StandardScene.ExtendDevice.Door
{
    /// <summary>
    /// Modbus 门控制器实现
    /// </summary>
    [DoorType("ModbusDoorController")]
    public class ModbusDoorController : BasicDoorController
    {
        /// <summary>
        /// Modbus TCP 客户端
        /// </summary>
        private ModbusRtu _modbusClient;

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

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

        /// <summary>
        /// 最近一次已下发的门控制状态，键为门索引
        /// </summary>
        private readonly Dictionary<int, bool> _lastSentControl = new Dictionary<int, bool>();

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

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

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

        /// <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>
        /// <param name="doorIndex">门索引</param>
        /// <param name="open">true=打开，false=关闭</param>
        public override void SetDoorControlTarget(int doorIndex, bool open)
        {
            lock (_syncLock)
            {
                base.SetDoorControlTarget(doorIndex, open);
            }
        }

        /// <summary>
        /// 连接门控制器
        /// </summary>
        public override void Connect()
        {
            lock (_syncLock)
            {
                if (_isStarted)
                {
                    return;
                }

                try
                {
                    UpdateState(DoorControllerState.Connecting);

                    // 根据配置的门初始化门状态
                    var doorIndices = DoorConfigs.Keys.OrderBy(k => k).ToList();
                    InitializeDoors(doorIndices);

                    // 初始化最近一次已下发的控制状态
                    _lastSentControl.Clear();
                    foreach (var index in doorIndices)
                    {
                        _lastSentControl[index] = false;
                        if (!DoorControlTargets.ContainsKey(index))
                        {
                            DoorControlTargets[index] = false;
                        }
                    }

                    // 尝试连接 Modbus TCP 客户端
                    try
                    {
                        _modbusClient = new ModbusRtu();
                        _modbusClient.StartTcpRtu(Ip, Port);
                        UpdateState(DoorControllerState.Online);
                    }
                    catch (Exception connectEx)
                    {
                        UpdateState(DoorControllerState.Connecting);
                        Diagnosis.Log($"ModbusDoorController[{Index}] 初次连接失败，将在后台持续重连: {ExceptionFormatter.FormatEx(connectEx)}", "ModbusDoorController", true);
                    }

                    // 启动定时读取任务
                    _cancellationTokenSource = new CancellationTokenSource();
                    _readTask = Task.Run(() => ReadDoorStatesLoop(_cancellationTokenSource.Token));

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

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

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

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

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

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

                    // 检查连接状态
                    bool isConnected = _modbusClient?.modbusRtu?.Connected ?? false;
                    if (_modbusClient == null || !isConnected)
                    {
                        UpdateState(DoorControllerState.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;
                        }
                    }

                    // 读取所有门的状态
                    ReadAllDoorStates();

                    // 根据目标控制状态下发控制指令
                    ApplyDoorControlTargets();

                    // 更新在线状态
                    UpdateState(DoorControllerState.Online);
                }
                catch (Exception ex)
                {
                    Diagnosis.Log($"ModbusDoorController[{Index}] 读取状态失败: {ExceptionFormatter.FormatEx(ex)}", "ModbusDoorController", true);
                    UpdateState(DoorControllerState.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($"ModbusDoorController[{Index}] 重连成功", "ModbusDoorController", false);
            }
            catch (Exception ex)
            {
                // 重连失败，确保资源释放
                if (_modbusClient != null)
                {
                    try
                    {
                        _modbusClient.Close();
                    }
                    catch
                    {
                        // 忽略关闭异常
                    }
                    _modbusClient = null;
                }

                Diagnosis.Log($"ModbusDoorController[{Index}] 重连失败: {ExceptionFormatter.FormatEx(ex)}", "ModbusDoorController", false);
            }
        }

        /// <summary>
        /// 读取所有门的状态
        /// </summary>
        private void ReadAllDoorStates()
        {
            lock (_syncLock)
            {
                foreach (var doorConfig in DoorConfigs.Values)
                {
                    try
                    {
                        var state = ReadDoorState(doorConfig.Index);
                        UpdateDoorState(doorConfig.Index, state ? DoorState.Open : DoorState.Closed);
                    }
                    catch (Exception ex)
                    {
                        Diagnosis.Log($"ModbusDoorController[{Index}] 读取门{doorConfig.Index}状态失败: {ExceptionFormatter.FormatEx(ex)}", "ModbusDoorController", true);
                    }
                }
            }
        }

        /// <summary>
        /// 根据 DoorControlTargets 中的目标状态，下发门控制指令
        /// </summary>
        private void ApplyDoorControlTargets()
        {
            lock (_syncLock)
            {
                foreach (var doorConfig in DoorConfigs.Values)
                {
                    var doorIndex = doorConfig.Index;

                    // 获取目标控制状态，默认false
                    bool target = false;
                    DoorControlTargets.TryGetValue(doorIndex, out target);

                    // 如果门配置为不允许发送任何控制指令，则跳过（既不打开也不关闭）
                    if (doorConfig.NoControl)
                    {
                        continue;
                    }

                    // 获取上一次已下发的状态
                    bool last;
                    var hasLast = _lastSentControl.TryGetValue(doorIndex, out last);

                    // 如果没有记录或状态发生变化，则下发控制
                    if (!hasLast || last != target)
                    {
                        try
                        {
                            WriteDoorControl(doorIndex, target);
                            _lastSentControl[doorIndex] = target;
                        }
                        catch (Exception ex)
                        {
                            Diagnosis.Log($"ModbusDoorController[{Index}] 下发门{doorIndex}控制指令失败: {ExceptionFormatter.FormatEx(ex)}", "ModbusDoorController", true);
                        }
                    }
                }
            }
        }

        /// <summary>
        /// 读取门状态（开到位信号）
        /// </summary>
        /// <param name="doorIndex">门索引</param>
        /// <returns>true=打开，false=关闭</returns>
        public override bool ReadDoorState(int doorIndex)
        {
            lock (_syncLock)
            {
                if (!DoorConfigs.TryGetValue(doorIndex, out var doorConfig))
                {
                    throw new ArgumentException($"门{doorIndex}不存在");
                }

                if (_modbusClient == null || !_modbusClient.modbusRtu.Connected)
                {
                    throw new InvalidOperationException("Modbus连接未建立");
                }

                // 读取开到位信号
                var data = _modbusClient.ReadDiscreteInputs_02(SlaveAddress, doorConfig.OpenStatusAddress, 1);
                return data != null && data.Length > 0 && data[0];
            }
        }

        /// <summary>
        /// 写入门控制信号（开关控制）
        /// </summary>
        /// <param name="doorIndex">门索引</param>
        /// <param name="open">true=打开，false=关闭</param>
        public override void WriteDoorControl(int doorIndex, bool open)
        {
            lock (_syncLock)
            {
                if (!DoorConfigs.TryGetValue(doorIndex, out var doorConfig))
                {
                    throw new ArgumentException($"门{doorIndex}不存在");
                }

                if (_modbusClient == null || !_modbusClient.modbusRtu.Connected)
                {
                    // 尝试重连
                    TryReconnect();
                    if (_modbusClient == null || !_modbusClient.modbusRtu.Connected)
                    {
                        throw new InvalidOperationException("Modbus连接未建立");
                    }
                }

                // 写入开关控制信号（线圈）
                _modbusClient.WriteMultipleCoils_15(SlaveAddress, doorConfig.ControlAddress, [open]);
            }
        }

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