using McProtocol.Mitsubishi;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace 常用工具集.Utility.Network.Mitsubishi
{
    internal class MC3EServer
    {
        public delegate void DataChanged(int address);
        public delegate void LogChanged(string message);
        public event DataChanged DataChangedEvent;
        public event LogChanged LogChangedEvent;

        private TcpListener _listener;
        private bool _isRunning;
        public static ushort[] _dataStorage = new ushort[65535]; // 初始化数据存储区; // 65535个地址数据，类型为ushort


        public MC3EServer(int port)
        {
            _listener = new TcpListener(IPAddress.Any, port);

        }

        public void Start()
        {
            new Thread(() =>
            {
                _isRunning = true;
                _listener.Start();
                LogChangedEvent?.Invoke("MC-3E Protocol Server started...");

                while (_isRunning)
                {
                    try
                    {
                        TcpClient client = _listener.AcceptTcpClient();
                        Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClient));
                        clientThread.Start(client);
                    }
                    catch (SocketException)
                    {
                        continue;
                    }
                    catch (ThreadInterruptedException)
                    {
                        break;
                    }
                }
            }).Start();

        }
        public void Stop()
        {
            _isRunning = false;
            _listener.Stop();
        }

        private void HandleClient(object obj)
        {
            TcpClient client = (TcpClient)obj;
            try
            {
                NetworkStream stream = client.GetStream();

                byte[] buffer = new byte[1024];
                int bytesRead;

                while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) != 0)
                {
                    LogChangedEvent?.Invoke($"Received {bytesRead} bytes from client.");
                    // 解析MC-3E协议请求
                    byte[] response = ProcessMc3ERequest(buffer, bytesRead, out bool write, out int address);
                    // 发送响应
                    stream.Write(response, 0, response.Length);
                    if (write) Task.Run(() => DataChangedEvent?.Invoke(address));
                }

            }
            catch (Exception ex)
            {
                LogChangedEvent?.Invoke(ex.Message);
            }
            client.Close();
        }
        private byte[] ProcessMc3ERequest(byte[] request, int length, out bool write, out int address)
        {
            // MC-3E协议帧格式示例：
            // 子头 (2字节) + 网络编号 (1字节) + PLC编号 (1字节) + 请求目标模块IO编号 (2字节) + 请求目标模块站号 (1字节)
            // + 请求数据长度 (2字节) + 请求数据 (N字节)
            // 解析请求数据
            if (length < 8)
            {
                LogChangedEvent?.Invoke($"Invalid request length.");
                write = false;
                address = 0;
                return BuildErrorResponse();
            }
            McFrame mcFrame = new McFrame();
            mcFrame.Frame = BitConverter.ToUInt16(request, 0); // 假设前两字节为帧类型  0x0050   80
            mcFrame.NetworkNumber = request[2]; // 假设第3字节为网络编号
            mcFrame.PcNumber = request[3]; // 假设第4字节为PLC编号
            mcFrame.IoNumber = BitConverter.ToUInt16(request, 4); // 假设第5-6字节为模块IO编号
            mcFrame.ChannelNumber = request[6]; // 假设第7字节为模块站号
            int dataLength = BitConverter.ToUInt16(request, 7); // 假设第8-9字节为数据长度
            mcFrame.CpuTimer = BitConverter.ToUInt16(request, 9); // 假设第10-11字节为CPU监视定时器
            int mainCommand = BitConverter.ToUInt16(request, 11); // 假设第12-13字节为主命令
            int subCommand = BitConverter.ToUInt16(request, 13); // 假设第14-15字节为子命令 
            mcFrame.Address = request[17] << 16 | request[16] << 8 | request[15];
            mcFrame.Type = (PlcDeviceType)request[18];
            mcFrame.Size = BitConverter.ToUInt16(request, 19);
            byte[] data = new byte[mcFrame.Size * 2];
            for (int i = 0; i < data.Length; i++)
            {
                data[i] = request[21 + i];
            }
            mcFrame.Data = data;
            // 处理读请求
            if (mainCommand == 0x0401)  //读命令
            {
                LogChangedEvent?.Invoke($"Read request: Address={mcFrame.Address},Type={mcFrame.Type} Count={mcFrame.Size}");
                write = false;
                address = 0;
                return HandleReadRequest(mcFrame);
            }
            // 处理写请求
            else if (mainCommand == 0x1401) // 写命令
            {
                LogChangedEvent?.Invoke($"Write request: Address={mcFrame.Address},Type={mcFrame.Type} Count={mcFrame.Size}");
                write = true;
                address = mcFrame.Address;
                return HandleWriteRequest(mcFrame); ;
            }
            else
            {
                LogChangedEvent?.Invoke("Unknown command.");
                write = false;
                address = 0;
                return BuildErrorResponse();
            }
        }

        class McFrame
        {
            public ushort Frame { get; set; }  // 头部
            public byte NetworkNumber { get; set; } // 网络号码
            public byte PcNumber { get; set; }      // 电脑号码
            public ushort IoNumber { get; set; }      // 请求单元 I/O 编号/O番号
            public byte ChannelNumber { get; set; } // 请求单位站号
            public ushort CpuTimer { get; set; }      // 中央处理器监控计时器
            public int Address { get; set; } // 地址
            public PlcDeviceType Type { get; set; }    // 类型

            public uint Size { get; set; } // 大小    
            public byte[] Data { get; set; }
        }

        private byte[] HandleReadRequest(McFrame mcFrame)
        {
            // 读取数据
            List<byte> responseData = new List<byte>(); // 每个ushort占2字节
            for (int i = 0; i < mcFrame.Size; i++)
            {
                byte[] valueBytes = BitConverter.GetBytes(_dataStorage[mcFrame.Address + i]);
                responseData.AddRange(valueBytes);
            }
            // 构建响应帧
            return BuildSuccessResponse(mcFrame, responseData.ToArray());
        }

        private byte[] HandleWriteRequest(McFrame mcFrame)
        {
            for (int i = 0; i < mcFrame.Size; i++)
            {
                _dataStorage[mcFrame.Address + i] = BitConverter.ToUInt16(mcFrame.Data, i * 2);
            }
            LogChangedEvent?.Invoke($"Write successful: Address={mcFrame.Address}, Length={mcFrame.Size}");
            return BuildSuccessResponse(mcFrame, new byte[0]); // 写入成功，返回空响应
        }

        private byte[] BuildSuccessResponse(McFrame mcFrame, byte[] responseData)
        {
            // 构建成功响应帧
            List<byte> response = new List<byte>();
            mcFrame.Frame = 0x00D0;
            response.AddRange(BitConverter.GetBytes(mcFrame.Frame));//0  1
            response.Add(mcFrame.NetworkNumber);  //2
            response.Add(mcFrame.PcNumber);    //3
            response.AddRange(BitConverter.GetBytes(mcFrame.IoNumber));  //4 5 
            response.Add(mcFrame.ChannelNumber);//6
            //response.AddRange(BitConverter.GetBytes(mcFrame.CpuTimer));
            //数据长度
            response.AddRange(BitConverter.GetBytes((short)(responseData.Length + 2)));//7 8
            response.AddRange(BitConverter.GetBytes((short)0));//9 10结束符号
            response.AddRange(responseData);
            return response.ToArray();
        }

        private byte[] BuildErrorResponse()
        {
            // 构建错误响应帧
            byte[] response = new byte[8];

            // 子头 (2字节)
            response[0] = 0xD0;
            response[1] = 0x00;

            // 网络编号 (1字节)
            response[2] = 0x00;

            // PLC编号 (1字节)
            response[3] = 0xFF;

            // 模块IO编号 (2字节)
            response[4] = 0x00;
            response[5] = 0x00;

            // 模块站号 (1字节)
            response[6] = 0x00;

            // 响应数据长度 (2字节)
            response[7] = 0x00;
            response[8] = 0x00;

            return response;
        }
    }
}
