using AntDesign;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using OneOf.Types;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Text;
using static System.Runtime.InteropServices.JavaScript.JSType;

namespace EasyTemplate.Service
{
    public class UdpListenerService : IHostedService
    {
        private readonly ILogger<UdpListenerService> _logger;
        private UdpClient? _udpClient;
        public static List<string> ReceivedMessages { get; } = new();

        public Dictionary<int, NozzleState> g_mNozzleState = new Dictionary<int, NozzleState>();

        public UdpListenerService(ILogger<UdpListenerService> logger)
        {
            _logger = logger;
        }


        public string GetUdpData()
        {
            return "";
        }


        public Dictionary<int, NozzleState> GetNozzleState()
        {
            return g_mNozzleState;
        }


        public int getbufferdata(byte[] Buffer, ref int startIndex, int length)
        {
            if (startIndex + length > Buffer.Length)
            {
                return 0;
            }

            byte[] segment = new byte[length];
            Array.Copy(Buffer, startIndex, segment, 0, length);
            startIndex += length;
            int val = Tool.BytesToInt(segment);
            return val;
        }

        public Task StartAsync(CancellationToken cancellationToken)
        {
            _udpClient = new UdpClient(8080); // 监听8080端口
            _logger.LogInformation("开始监听UDP端口 8080");


            for (int i = 0; i < 40; i++)
            {
                NozzleState ns = new NozzleState();
                ns.noz = i + 1;
                ns.warnstate = i % 3;
                ns.oil = i % 2 == 0 ? "92#" : "95#";
                g_mNozzleState.Add(ns.noz, ns);
            }


            Task.Run(async () =>
            {
                while (!cancellationToken.IsCancellationRequested)
                {
                    try
                    {
                        var result = await _udpClient.ReceiveAsync(cancellationToken);
                        var message = Encoding.UTF8.GetString(result.Buffer);

                        //dest-2;source-2;frame-1;length-2;cmd-1


                        int datalength = result.Buffer[5] * 256 + result.Buffer[6];
                        if (datalength + 9 == result.Buffer.Length)
                        {
                            // 计算crc
                            int packlen = result.Buffer.Length;
                            byte[] tmpbuf = result.Buffer;
                            ushort nSum = Tool.chkcrc(tmpbuf, (ushort)(packlen - 2), 0xA001);
                            ushort newSum = nSum;
                            newSum = (ushort)(newSum / 256 + newSum % 256 * 256);
                            ushort oldSum = BitConverter.ToUInt16(tmpbuf, packlen - 2);

                            if (oldSum == newSum)
                            {
                                Console.WriteLine("CRC校验成功");
                            }
                            else
                            {
                                Console.WriteLine("crc校验失败");
                                continue;
                            }
                        }
                        else if (datalength + 9 == result.Buffer.Length + 2)
                        {
                            //旧协议无crc
                        }
                        else
                        {
                            continue;
                        }

                        int cmdtype = result.Buffer[7];

                        int startindex = 8;
                        switch (cmdtype)
                        {
                            case 1:
                                filling_nozzleup up = extractFillingNozzleUP(result.Buffer, startindex);
                                g_mNozzleState[up.noz].nozzlestate = Tool.NozzleState_Filling;
                                break;
                            case 2:
                                filling_process process = extractFillingProcess(result.Buffer, startindex);
                                g_mNozzleState[process.noz].nozzlestate = Tool.NozzleState_Filling;
                                g_mNozzleState[process.noz].VLR = ((double)process.VLR / 1000).ToString("F2");
                                break;
                            case 3:
                                filling_nozzledown down = extractFillingNozzleDown(result.Buffer, startindex);
                                g_mNozzleState[down.noz].nozzlestate = Tool.NozzleState_Idle;
                                break;
                            case 4:
                                filling_record record = extractFillingRecord(result.Buffer, startindex);
                                g_mNozzleState[record.noz].nozzlestate = Tool.NozzleState_Idle;
                                g_mNozzleState[record.noz].VLR = ((double)record.VLR / 1000).ToString("F2");
                                break;



                            default:
                                continue;
                        }



                        string result1 = string.Join(", ", result.Buffer);
                        lock (ReceivedMessages)
                        {
                            ReceivedMessages.Add($"{DateTime.Now:HH:mm:ss} - {message}");
                            if (ReceivedMessages.Count > 100) ReceivedMessages.RemoveAt(0);
                        }
                        _logger.LogInformation($"接收到消息: {message}");


                        // Echo back
                        byte[] responseData = Encoding.UTF8.GetBytes("Echo: " + message);
                        await _udpClient.SendAsync(responseData, responseData.Length, result.RemoteEndPoint);
                    }
                    catch (ObjectDisposedException) when (cancellationToken.IsCancellationRequested)
                    {
                        break;
                    }
                    catch (Exception ex)
                    {
                        _logger.LogError(ex, "接收UDP数据出错");
                    }
                }
            }, cancellationToken);

            return Task.CompletedTask;
        }

        public Task StopAsync(CancellationToken cancellationToken)
        {
            _udpClient?.Close();
            _logger.LogInformation("停止监听UDP端口");
            return Task.CompletedTask;
        }
        public filling_nozzleup extractFillingNozzleUP(byte[] Buffer, int startIndex)
        {
            filling_nozzleup data = new filling_nozzleup();
            BufferHandler handler = new BufferHandler(Buffer, startIndex);
            data.board = handler.getData(1);
            data.noz = handler.getData(1);
            data.fip = data.board;
            data.time = handler.getDataString_BCD(7);
            return data;
        }

        public filling_nozzledown extractFillingNozzleDown(byte[] Buffer, int startIndex)
        {
            filling_nozzledown data = new filling_nozzledown();
            BufferHandler handler = new BufferHandler(Buffer, startIndex);
            data.board = handler.getData(1);
            data.noz = handler.getData(1);
            data.fip = data.board;
            data.time = handler.getDataString_BCD(7);
            return data;
        }
        public filling_process extractFillingProcess(byte[] Buffer, int startIndex)
        {
            filling_process data = new filling_process();
            BufferHandler handler = new BufferHandler(Buffer, startIndex);
            data.board = handler.getData(1);
            data.noz = handler.getData(1);
            data.fip = data.board;
            data.liquidVL = handler.getData(3);
            data.vaporVL = handler.getData(3);
            data.vaporFR = handler.getData(2);
            data.VLR = handler.getData(2);
            data.vaporPA = handler.getData(2);
            data.errornum = handler.getData(2);
            data.liquidFR = handler.getData(2);
            data.pwm = handler.getData(2);
            data.current = handler.getData(2);
            return data;
        }
        public filling_record extractFillingRecord(byte[] Buffer, int startIndex)
        {
            int bufferlen = Buffer.Length;

            filling_record data = new filling_record();
            BufferHandler handler = new BufferHandler(Buffer, startIndex);
            data.board = handler.getData(1);
            data.noz = handler.getData(1);
            data.fip = data.board;
            if (bufferlen != 22)//兼容旧协议，解析顺序改变
            {
                data.ttc = handler.getData(4);
            }
            data.liquidVL = handler.getData(3);
            data.liquidFR = handler.getData(2);
            data.vaporVL = handler.getData(3);
            data.vaporFR = handler.getData(2);
            data.VLR = handler.getData(2);
            data.tmBegin = handler.getDataString_BCD(7);
            data.tmEnd = handler.getDataString_BCD(7);
            data.errornum = handler.getData(2);
            data.vaporPA = handler.getData(2);
            data.pwm = handler.getData(2);
            return data;
        }

        public class BufferHandler
        {
            public byte[] buffer = Array.Empty<byte>();
            public int startIndex = 0;
            public int length = 0;

            public BufferHandler(byte[] buf, int startindex = 0)
            {
                buffer = buf;
                startIndex = startindex;
                length = buf.Length;
            }


            public string getDataString_BCD(int len)
            {
                if (startIndex + len > length)
                {
                    return "";
                }

                byte[] segment = new byte[len];
                Array.Copy(buffer, startIndex, segment, 0, len);
                string result = Tool.BytesToBcd(segment);

                startIndex += len;
                return result;
            }

            public int getData(int len)
            {
                if (startIndex + len > length)
                {
                    return 0;
                }
                byte[] segment = new byte[len];
                Array.Copy(buffer, startIndex, segment, 0, len);
                int val = Tool.BytesToInt(segment);

                startIndex += len;
                return val;
            }

        }


        //public filling_process struct2filling(s_vr_status cmd)
        //{
        //    filling_process data = new filling_process();

        //    //data.liquidVL = (uint)(st.liqvol[0] << 16 | st.liqvol[1] << 8 | st.liqvol[2]);

        //    data.fip = cmd.fip;
        //    data.noz = cmd.noz;
        //    data.liquidVL = Tool.BytesToInt(cmd.liqvol);
        //    data.liquidFR = Tool.BytesToInt(cmd.liqflow);
        //    data.vaporFR = Tool.BytesToInt(cmd.vapflow);
        //    data.vaporVL = Tool.BytesToInt(cmd.vapvol);
        //    data.VLR = Tool.BytesToInt(cmd.vlr);
        //    data.vaporPA = Tool.BytesToInt(cmd.press);
        //    data.pwm = Tool.BytesToInt(cmd.pwm);
        //    data.current = Tool.BytesToInt(cmd.current);


        //    return data;
        //}

        public class NozzleState
        {
            public int noz = 0;
            public string VLR = "0";
            public string oil = string.Empty;
            public int nozzlestate = Tool.NozzleState_Offline;
            public int warnstate = Tool.WarningState_Normal;
        }



        public struct filling_nozzleup
        {
            public int fip;
            public int board;
            public int noz;
            public string time;
            /*	byte cmd;
	byte fip;
	byte noz;
	byte time[7];
	byte product[4];*/
            /*	auto& cmd = src->data.CMD1;
	dst.target = cmd.noz;
	_ubcd_to_str (dst.time, sizeof dst.time, cmd.time, sizeof cmd.time);
	_ubcd_to_str (dst.product, sizeof dst.product, cmd.product, sizeof cmd.product);*/
        }


        public struct filling_nozzledown
        {
            public int fip;
            public int board;
            public int noz;
            public string time;
        }

        public struct filling_record
        {
            public int fip;
            public int board;
            public int noz;
            public int liquidVL;
            public int vaporVL;
            public int liquidFR;
            public int vaporFR;
            public int VLR;
            public int vaporPA;
            public int ttc;
            public int VLR_BEFORE;
            public int VLR_OFFSET;
            public int pwm;
            public string tmBegin;
            public string tmEnd;
            public int overproof;
            public int uploadflag;
            public int uploadflag2;
            public int uploadflag3;
            public int downloadflag1;
            public int yz;
            public int tankpressure;
            public int refuelingseconds;
            public int errorcontrolvalue;
            public int errornum;
            public int callbackflag;
            public string vccerrorinfo;
        }

        public struct filling_process
        {
            public int fip;
            public int board;
            public int noz;
            public int liquidVL;
            public int vaporVL;
            public int liquidFR;
            public int vaporFR;
            public int VLR;
            public int vaporPA;
            public int ttc;
            public int VLR_BEFORE;
            public int VLR_OFFSET;
            public int errornum;
            public int pwm;
            public int current;
        }


        //[StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
        //public struct s_vr_status
        //{
        //    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
        //    public byte[] dest;

        //    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
        //    public byte[] source;

        //    public byte frame;
        //    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
        //    public byte[] length;
        //    public byte cmd;
        //    public byte fip;
        //    public byte noz;
        //    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
        //    public byte[] liqvol;
        //    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
        //    public byte[] vapvol;
        //    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
        //    public byte[] vapflow;
        //    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
        //    public byte[] vlr;
        //    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
        //    public byte[] press;
        //    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
        //    public byte[] errornum;
        //    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
        //    public byte[] liqflow;
        //    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
        //    public byte[] pwm;
        //    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
        //    public byte[] current;
        //    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
        //    public byte[] crc;
        //}

    }
}
