using Simple3.RCS;
using Simple3.RCS.CarTypes;
using SimpleCore;
using SimpleCore.Library;
using SimpleCore.PropType;
using StandardScene.Charge;
using StandardScene.TCP;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace StandardScene.ChargeStationType
{
    public class FLChargeStation : AbstractChargeStation
    {
        private AsyncTcpClient Client;
        private IPEndPoint _endPoint;

        // 重连相关
        private Timer _reconnectTimer;
        private bool _isManualDisconnect = false; // 标识是否为手动断开
        private int _reconnectAttempts = 0; // 重连尝试次数
        private const int MAX_RECONNECT_ATTEMPTS = 5; // 最大重连次数
        private const int RECONNECT_INTERVAL_MS = 3000; // 重连间隔（毫秒）
        private readonly object _connectionLock = new object(); // 连接锁
        private bool _isConnecting = false; // 是否正在连接中

        // 连接状态
        public bool IsConnected { get; private set; } = false;
        public DateTime? LastConnectedTime { get; private set; }
        public DateTime? LastDisconnectedTime { get; private set; }

        /// <summary>
        /// 关闭当前TCP连接
        /// </summary>
        public override void CloseCommunication()
        {
            lock (_connectionLock)
            {
                _isManualDisconnect = true; // 标记为手动断开，不触发自动重连

                // 停止重连定时器
                if (_reconnectTimer != null)
                {
                    _reconnectTimer.Dispose();
                    _reconnectTimer = null;
                }
                _isConnecting = false;
                if (Client != null)
                {
                    try
                    {
                        // 取消订阅事件，避免内存泄漏
                        Client.PlaintextReceived -= OnPlaintextReceived;
                        Client.ServerConnected -= OnServerConnected;
                        Client.ServerDisconnected -= OnServerDisconnected;

                        // 关闭连接
                        Client.Close();
                        Client = null;

                        IsConnected = false;
                        LastDisconnectedTime = DateTime.Now;

                        Diagnosis.Log($"FLChargeStation[{SiteId}] TCP connection closed manually");
                    }
                    catch (Exception ex)
                    {
                        Diagnosis.Log($"ERR:FLChargeStation[{SiteId}] failed to close connection: {ex.Message}");
                    }
                }
            }
        }

        /// <summary>
        /// 创建TCP连接
        /// </summary>
        public override void CreateCommunication(IPAddress ip, int port)
        {
            lock (_connectionLock)
            {
                // 先关闭旧连接
                if (Client != null)
                {
                    CloseCommunication();
                }

                _endPoint = new IPEndPoint(ip, port);
                _isManualDisconnect = false; // 重置手动断开标记
                _reconnectAttempts = 0; // 重置重连次数

                ConnectInternal();
            }
        }

        /// <summary>
        /// 内部连接方法
        /// </summary>
        private void ConnectInternal()
        {
            if (_isConnecting)
            {
                Diagnosis.Log($"FLChargeStation[{SiteId}] is already connecting, skip");
                return;
            }

            try
            {
                _isConnecting = true;

                // 创建新的TCP客户端
                Client = new AsyncTcpClient(_endPoint.Address, _endPoint.Port);
                Client.PlaintextReceived += OnPlaintextReceived;
                Client.ServerConnected += OnServerConnected;
                Client.ServerDisconnected += OnServerDisconnected;

                // 连接
                Client.Connect();

                if (Client.Connected)
                {
                    Diagnosis.Log($"FLChargeStation[{SiteId}] connecting to {_endPoint.Address}:{_endPoint.Port}...");
                }
                else
                {
                    _isConnecting = false;
                    Diagnosis.Log($"FLChargeStation[{SiteId}] connecting to {_endPoint.Address}:{_endPoint.Port}...  未建立连接");
                }

            }
            catch (Exception ex)
            {
                Diagnosis.Log($"ERR:FLChargeStation[{SiteId}] failed to create connection: {ex.Message}");
                _isConnecting = false;

                // 触发重连
                if (!_isManualDisconnect)
                {
                    ScheduleReconnect();
                }
            }
        }

        /// <summary>
        /// 手动触发重连
        /// </summary>
        public void Reconnect()
        {
            lock (_connectionLock)
            {
                Diagnosis.Log($"FLChargeStation[{SiteId}] manual reconnect triggered");

                _isManualDisconnect = false;
                _reconnectAttempts = 0;

                // 关闭现有连接
                if (Client != null)
                {
                    try
                    {
                        Client.PlaintextReceived -= OnPlaintextReceived;
                        Client.ServerConnected -= OnServerConnected;
                        Client.ServerDisconnected -= OnServerDisconnected;
                        Client.Close();
                        Client = null;
                    }
                    catch { }
                }

                // 重新连接
                ConnectInternal();
            }
        }

        /// <summary>
        /// 安排自动重连
        /// </summary>
        private void ScheduleReconnect()
        {
            if (_isManualDisconnect)
            {
                Diagnosis.Log($"FLChargeStation[{SiteId}] manual disconnect, skip auto reconnect");
                return;
            }

            if (_reconnectAttempts >= MAX_RECONNECT_ATTEMPTS)
            {
                Diagnosis.Log($"ERR:FLChargeStation[{SiteId}] max reconnect attempts ({MAX_RECONNECT_ATTEMPTS}) reached, stop reconnecting");
                return;
            }

            _reconnectAttempts++;

            // 停止现有定时器
            if (_reconnectTimer != null)
            {
                _reconnectTimer.Dispose();
            }

            Diagnosis.Log($"FLChargeStation[{SiteId}] scheduling reconnect attempt {_reconnectAttempts}/{MAX_RECONNECT_ATTEMPTS} in {RECONNECT_INTERVAL_MS}ms");

            // 创建新的定时器
            _reconnectTimer = new Timer(
                callback: _ => AttemptReconnect(),
                state: null,
                dueTime: RECONNECT_INTERVAL_MS,
                period: Timeout.Infinite
            );
        }

        /// <summary>
        /// 尝试重连
        /// </summary>
        private void AttemptReconnect()
        {
            lock (_connectionLock)
            {
                if (_isManualDisconnect || IsConnected)
                {
                    return;
                }

                Diagnosis.Log($"FLChargeStation[{SiteId}] attempting to reconnect (attempt {_reconnectAttempts}/{MAX_RECONNECT_ATTEMPTS})...");

                try
                {
                    // 清理旧客户端
                    if (Client != null)
                    {
                        try
                        {
                            Client.PlaintextReceived -= OnPlaintextReceived;
                            Client.ServerConnected -= OnServerConnected;
                            Client.ServerDisconnected -= OnServerDisconnected;
                            Client.Close();
                        }
                        catch { }
                        Client = null;
                    }

                    // 重新连接
                    ConnectInternal();
                }
                catch (Exception ex)
                {
                    Diagnosis.Log($"ERR:FLChargeStation[{SiteId}] reconnect failed: {ex.Message}");

                    // 继续安排下一次重连
                    if (!_isManualDisconnect && _reconnectAttempts < MAX_RECONNECT_ATTEMPTS)
                    {
                        ScheduleReconnect();
                    }
                }
            }
        }

        private void OnPlaintextReceived(object sender, TcpDatagramReceivedEventArgs<byte[]> e)
        {
            var messageService = CommunicationMessageService.Instance;
            var recBytes = e.Datagram.Take(35).ToArray();
            string IP = ((AsyncTcpClient)sender).RemoteIPEndPoint.Address.ToString();
            Diagnosis.Post($"{string.Join(" ", recBytes.Select(p => $"{p:X2}"))}", $"{IP}", true);
            IsSafe = recBytes[28] == 2;
            messageService.AddReceiveMessage(_endPoint.Address.ToString(), _endPoint.Port, BitConverter.ToString(recBytes).Replace("-", " "), "FRLDTall");
        }

        /// <summary>
        /// 服务器连接成功事件
        /// </summary>
        private void OnServerConnected(object sender, TcpServerConnectedEventArgs e)
        {
            lock (_connectionLock)
            {
                _isConnecting = false;
                IsConnected = true;
                LastConnectedTime = DateTime.Now;
                _reconnectAttempts = 0; // 重置重连次数

                Diagnosis.Log($"FLChargeStation[{SiteId}] TCP connected successfully to {_endPoint.Address}:{_endPoint.Port}");

                // 停止重连定时器
                if (_reconnectTimer != null)
                {
                    _reconnectTimer.Dispose();
                    _reconnectTimer = null;
                }
            }
        }

        /// <summary>
        /// 服务器断开连接事件
        /// </summary>
        private void OnServerDisconnected(object sender, TcpServerDisconnectedEventArgs e)
        {
            lock (_connectionLock)
            {
                _isConnecting = false;
                IsConnected = false;
                LastDisconnectedTime = DateTime.Now;

                Diagnosis.Log($"WARN:FLChargeStation[{SiteId}] TCP disconnected from {_endPoint.Address}:{_endPoint.Port}");
            }
        }

        /// <summary>
        /// 发送充电指令到充电站
        /// </summary>
        public override void SendToChargeStation(int isCharge, Car car,Site site)
        {
            // 检查连接状态
            if (!IsConnected || Client == null)
            {
                Diagnosis.Log($"WARN:FLChargeStation[{SiteId}] not connected, cannot send charge command");
                return;
            }

            try
            {
                var messageService = CommunicationMessageService.Instance;
                float soc = 0f, voltage = 0, electricCurrent = 0;
                int carId = 0;
                float setVoltage = 55.0f;
                float setElectricCurrent = 50.0f;
                //Site site = null;
                if (car != null)
                {
                    soc = float.Parse(Commons.GetCarStatus(car, "Soc"));
                    voltage = float.Parse(Commons.GetCarStatus(car, "Voltage"));
                    electricCurrent = float.Parse(Commons.GetCarStatus(car, "ElectricCurrent"));
                    carId = car.id;
                    //site = SimpleLib.GetSite(car.status.holdingLocks.FirstOrDefault());

                    

                }
                if (site != null && site.fields.ContainsKey("setVoltage") && site.fields.ContainsKey("setElectricCurrent"))
                {
                    setVoltage = float.Parse(site.fields["setVoltage"]);
                    setElectricCurrent = float.Parse(site.fields["setElectricCurrent"]);
                }

                var msg = GetSendBytes((byte)(isCharge),
                   setVoltage, setElectricCurrent, 1000,
                    Convert.ToSingle(carId), Convert.ToSingle(soc), Convert.ToSingle(electricCurrent), Convert.ToSingle(voltage));

                messageService.AddSendMessage(_endPoint.Address.ToString(), _endPoint.Port, BitConverter.ToString(msg).Replace("-", " "), "FRLDTall", site?.name);

                // 发送数据，带异常处理
                try
                {
                    Client.Send(msg);
                    Diagnosis.Post($"{string.Join(" ", msg.Select(d => $"{d:X2}"))}",
                        $"sendChargeSite: {SiteId}", true);
                }
                catch (ObjectDisposedException)
                {
                    Diagnosis.Log($"ERR:FLChargeStation[{SiteId}] client disposed during send, triggering reconnect");
                    IsConnected = false;
                }
                catch (SocketException ex)
                {
                    Diagnosis.Log($"ERR:FLChargeStation[{SiteId}] socket error during send: {ex.SocketErrorCode}, triggering reconnect");
                    IsConnected = false;
                }
            }
            catch (Exception e)
            {
                Diagnosis.Post($"ERR:FLChargeStation[{SiteId}] SwitchCharge Fail: {ExceptionFormatter.FormatEx(e)}");
            }
        }

        private byte[] GetSendBytes(byte startCharge, float chargeVoltage, float chargeElectricCurrent,
            float chargeTimeSpan, float carId,
            float carSoc, float carElectricCurrent, float carVoltage)
        {
            var sendByte = new byte[32];
            try
            {
                //BB 01 42 48 00 00 42 5C 00 00 00 00 00 02 00 5D 41 B4 00 00 41 28 00 00 00 00 00 00 00 00 00 EE
                sendByte = new byte[2] { 0xBB, startCharge }
                    .Concat(BitConverter.GetBytes(chargeElectricCurrent).AsEnumerable().Reverse())
                    .Concat(BitConverter.GetBytes(chargeVoltage).AsEnumerable().Reverse())
                    .Concat(BitConverter.GetBytes((ushort)chargeTimeSpan).AsEnumerable().Reverse())
                    .Concat(BitConverter.GetBytes((ushort)carId).AsEnumerable().Reverse())
                    .Concat(BitConverter.GetBytes((ushort)carSoc).AsEnumerable().Reverse())
                    .Concat(BitConverter.GetBytes(carElectricCurrent).AsEnumerable().Reverse())
                    .Concat(BitConverter.GetBytes(carVoltage).AsEnumerable().Reverse())
                    .Concat(new byte[] { 00, 00, 00, 00, 00, 00, 00, 0xEE }).ToArray();

            }
            catch (Exception ex)
            {
                Diagnosis.Post($"下发充电控制{(startCharge == 1 ? "启动" : "停止")}异常+ex:{ExceptionFormatter.FormatEx(ex)}", "error");
            }

            return sendByte;
        }
    }
}
