using MessagePack;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Net.WebSockets;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace WasteConsoleTest
{
    /// <summary>
    /// 向服务端推送测试用垃圾采集数据
    /// </summary>
    [MessagePackObject]
    public class MessageGarbageC2SDto //客户端向服务端请求的DTO
    {
        /// <summary>
        /// 垃圾称重数据,64位浮点进度，单位为千克
        /// </summary>
        [Key("weight")]
        public double Weight { get; set; }

        /// <summary>
        /// 垃圾桶编码
        /// </summary>
        [Key("trash")]
        public string Trash { get; set; }

        /// <summary>
        /// 垃圾类型,缺省类型 : 0,厨余垃圾 : 1,可回收物 : 2,有害垃圾 : 3,其他垃圾 : 4
        /// </summary>
        [Key("type")]
        public int Type { get; set; }

        /// <summary>
        /// 数据扫描时间,UNIX时间戳
        /// </summary>
        [Key("scanningTime")]
        public long ScanningTime { get; set; }

        /// <summary>
        /// 设备状态,使用中 : 0:使用中,异常 : 1,检修 : 2,检修结束 : 3,启用 : 4,未知 : 5
        /// </summary>
        [Key("d_status")]
        public int DStatus { get; set; }
    }

    internal class Program
    {
        private static WSocketClientHelp wSocketClient = null;
        public static string SocketURL = "wss://api.device.suzhou.ljflytjl.cn/device_rpc";

        private static async Task Main(string[] args)
        {
            var builder = new HostBuilder().ConfigureServices((hostContext, services) =>
            {
                services.AddHttpClient();
                services.AddTransient<IMyService, MyService>();
            }).UseConsoleLifetime();
            var host = builder.Build();
            wSocketClient = new WSocketClientHelp(SocketURL);
            wSocketClient.OnOpen -= WSocketClient_OnOpen;
            wSocketClient.OnMessage -= WSocketClient_OnMessage;
            wSocketClient.OnClose -= WSocketClient_OnClose;
            wSocketClient.OnError -= WSocketClient_OnError;

            wSocketClient.OnOpen += WSocketClient_OnOpen;
            wSocketClient.OnMessage += WSocketClient_OnMessage;
            wSocketClient.OnClose += WSocketClient_OnClose;
            wSocketClient.OnError += WSocketClient_OnError;
            wSocketClient.Open();
            var myService = host.Services.GetRequiredService<IMyService>();
            //   SetTimeOut();
            while (true)
            {
                string cmd = Console.ReadLine();
                //退出
                if (cmd == "exit")
                {
                    Console.WriteLine("退出请求");
                    wSocketClient.Close();
                    break;
                }
                else
                //测试sayhello
                if (cmd.ToLower() == "sayhello")
                {
                    var senddata = @"{
    ""type"": 1,
    ""invocationId"": ""Nil"",
    ""target"": ""sayHello"",
    ""arguments"": [
        ""Hello Test Message""
    ]
}";
                    wSocketClient.Send(senddata);
                }
                //获取token
                else if (cmd.ToLower() == "gettoken")
                {
                    var senddata = @"{
    ""type"": 1,
    ""invocationId"": ""Nil"",
    ""target"": ""getToken"",
    ""arguments"": [
        ""sz_data""
    ]
}";
                    wSocketClient.Send(senddata);
                }
                //测试token的有效期
                else if (cmd.ToLower() == "testtoken")
                {
                    await myService.TestTokenAsync();
                }
                //测试上报
                else if (cmd.ToLower() == "postdata")
                {
                    await myService.Garbages();
                }
                //messagepack测试上报
                else if (cmd.Equals("postmessagepack", StringComparison.OrdinalIgnoreCase))
                {
                    await myService.MessageGarbages();
                }
            }
        }

        private static void WSocketClient_OnError(object sender, Exception ex)
        {
            Console.WriteLine($"发生异常:{ex.Message}");
        }

        private static void WSocketClient_OnClose(object sender, EventArgs e)
        {
            Console.WriteLine($"已关闭");
        }

        private static void WSocketClient_OnMessage(object sender, string data)
        {
            //处理的消息错误将会忽略
            try
            {
                //查看数据是否有token
                var jsondata = JsonConvert.DeserializeObject<ResponseData>(data);
                if (jsondata != null && jsondata.type == 1 && !string.IsNullOrEmpty(jsondata.target) && jsondata.target.ToLower() == "token" && jsondata.arguments != null && jsondata.arguments.Count == 1)
                {
                    var token = jsondata.arguments.First();
                    //保存token到文件中
                    var path = AppDomain.CurrentDomain.BaseDirectory + "File";
                    var filePath = path + @"\token.txt";
                    if (!Directory.Exists(path))
                    {
                        Directory.CreateDirectory(path);
                    }
                    if (File.Exists(filePath))
                    {
                        File.Delete(filePath);
                    }
                    using (var fileStream = new FileStream(filePath, FileMode.CreateNew))
                    {
                        byte[] content = Encoding.UTF8.GetBytes(token);
                        fileStream.Write(content, 0, content.Length);
                    }
                }
                //如果收到的消息为type=6心跳包,需要响应Pong
                if (jsondata != null && jsondata.type == 6)
                {
                    var senddata = @"{
    ""type"": 6
}";
                    wSocketClient.Send(senddata);
                }
                Console.WriteLine($"{DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")},收到的消息:{data}");
            }
            catch (Exception)
            {
            }
        }

        public interface IMyService
        {
            /// <summary>
            /// 测试token有效期
            /// </summary>
            Task TestTokenAsync();

            /// <summary>
            /// 传送垃圾数据
            /// </summary>
            /// <returns></returns>
            Task Garbages();

            /// <summary>
            /// Messagepack传送垃圾数据
            /// </summary>
            /// <returns></returns>
            Task MessageGarbages();
        }

        public class MyService : IMyService
        {
            private readonly IHttpClientFactory _clientFactory;

            public MyService(IHttpClientFactory clientFactory)
            {
                _clientFactory = clientFactory;
            }

            /// <summary>
            /// 传送垃圾数据
            /// </summary>
            /// <returns></returns>
            public async Task Garbages()
            {
                try
                {
                    string token = gettoken();
                    if (!string.IsNullOrEmpty(token))
                    {
                        var scantime = GetTimestamp();
                        var garbageC2SDto = new GarbageC2SDto
                        {
                            weight = 42.3,
                            trash = "64424512085",
                            scanningTime = scantime,
                            d_status = 0,
                            type = 4
                        };
                        int nonce = GetNonce();
                        string[] paramlist = new string[] {
                garbageC2SDto.weight.ToString(),garbageC2SDto.trash,garbageC2SDto.type.ToString(),garbageC2SDto.scanningTime.ToString(),garbageC2SDto.d_status.ToString()
            };
                        string sign = GetUserApiSign(WSocketClientHelp.Secret, paramlist);
                        var request = new HttpRequestMessage(HttpMethod.Post,
"https://api.data.suzhou.ljflytjl.cn/api/Garbages?api-version=1.0");
                        request.Headers.Add("Authorization", $"Bearer {token}");
                        request.Headers.Add("secret", WSocketClientHelp.Secret);
                        request.Headers.Add("nonce", nonce.ToString());
                        request.Headers.Add("time", scantime.ToString());
                        request.Headers.Add("sign", sign);
                        var message = JsonConvert.SerializeObject(garbageC2SDto);
                        request.Content = new StringContent(message, Encoding.Default, "application/json");
                        var client = _clientFactory.CreateClient();
                        var response = await client.SendAsync(request);
                        var result = await response.Content.ReadAsStringAsync();
                        if (response.IsSuccessStatusCode)
                        {
                            Console.WriteLine($"上报成功:{result}");
                        }
                        else
                        {
                            Console.WriteLine($"上报失败:{response.StatusCode},{result}");
                        }
                    }
                    else
                    {
                        Console.Write("token未找到");
                    }
                }
                catch (Exception)
                {
                }
            }

            /// <summary>
            /// MessagePack传送垃圾数据
            /// </summary>
            /// <returns></returns>
            public async Task MessageGarbages()
            {
                try
                {
                    string token = gettoken();
                    if (!string.IsNullOrEmpty(token))
                    {
                        var timestamp = GetTimestamp();
                        var garbageC2SDto = new MessageGarbageC2SDto
                        {
                            Weight = 50.2,
                            Trash = "64424509988",
                            ScanningTime = timestamp,
                            DStatus = 0,
                            Type = 4
                        };
                        int nonce = GetNonce();
                        string[] paramlist = new string[] {
                garbageC2SDto.Weight.ToString(),garbageC2SDto.Trash,garbageC2SDto.Type.ToString(),garbageC2SDto.ScanningTime.ToString(),garbageC2SDto.DStatus.ToString()
            };
                        string sign = GetUserApiSign(WSocketClientHelp.Secret, paramlist);
                        var request = new HttpRequestMessage(HttpMethod.Post,
"https://api.data.suzhou.ljflytjl.cn/api/Garbages");
                        request.Headers.Add("Authorization", $"Bearer {token}");
                        request.Headers.Add("secret", WSocketClientHelp.Secret);
                        request.Headers.Add("nonce", nonce.ToString());
                        request.Headers.Add("time", timestamp.ToString());
                        request.Headers.Add("sign", sign);

                        var bytes = MessagePackSerializer.Serialize(garbageC2SDto);
                        request.Content = new ByteArrayContent(bytes);
                        request.Headers.Add("Accept", "application/x-msgpack");
                        request.Content.Headers.Add("Content-Type", "application/x-msgpack");
                        var client = _clientFactory.CreateClient();
                        var response = await client.SendAsync(request);
                        var result = await response.Content.ReadAsStringAsync();
                        if (response.IsSuccessStatusCode)
                        {
                            Console.WriteLine($"上报成功:{result}");
                        }
                        else
                        {
                            Console.WriteLine($"上报失败:{response.StatusCode},{result}");
                        }
                    }
                    else
                    {
                        Console.Write("token未找到");
                    }
                }
                catch (Exception)
                {
                }
            }

            /// <summary>
            /// 测试token有效期
            /// </summary>
            public async Task TestTokenAsync()
            {
                var request = new HttpRequestMessage(HttpMethod.Get,
                   "https://api.data.suzhou.ljflytjl.cn/api/hello/device");
                string token = gettoken();
                if (!string.IsNullOrEmpty(token))
                {
                    request.Headers.Add("Authorization", $"Bearer {token}");
                    var client = _clientFactory.CreateClient();
                    var response = await client.SendAsync(request);
                    var result = await response.Content.ReadAsStringAsync();
                    if (response.IsSuccessStatusCode)
                    {
                        Console.WriteLine($"token可用:{result}");
                    }
                    else
                    {
                        Console.WriteLine($"token已过期:{response.StatusCode},{result}");
                    }
                }
                else
                {
                    Console.Write("token未找到");
                }
            }

            /// <summary>
            /// 获取时间戳
            /// </summary>
            /// <returns></returns>
            private long GetTimestamp()
            {
                DateTime utcTime = TimeZoneInfo.ConvertTimeToUtc(DateTime.Now);
                DateTime utcStartTime = new DateTime(1970, 1, 1, 0, 0, 0, 0);
                var timestamp = Convert.ToInt32((utcTime - utcStartTime).TotalSeconds);
                return timestamp;
            }

            /// <summary>
            /// 获取UTC时间戳
            /// </summary>
            /// <returns></returns>
            public static int CurrentUTCTimeStamp()
            {
                var ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
                var times = Convert.ToInt32(ts.TotalSeconds);
                return times;
            }

            /// <summary>
            /// 获取随机数
            /// </summary>
            /// <returns></returns>
            public int GetNonce()
            {
                var random = new Random();
                int nonce = random.Next(1, Int32.MaxValue);
                return nonce;
            }

            /// <summary>
            /// 获取签名
            /// </summary>
            /// <param name="secret"></param>
            /// <param name="dataparams"></param>
            /// <returns></returns>
            public string GetUserApiSign(string secret, params string[] dataparams)
            {
                StringBuilder sb = new StringBuilder();
                string ApiSecret = "EtifGTppTL0TTjie";
                if (dataparams != null && dataparams.Length > 0)
                {
                    foreach (var item in dataparams)
                    {
                        sb.Append(item);
                    }
                }
                if (!string.IsNullOrEmpty(secret))
                {
                    sb.Append(secret);
                }
                else
                {
                    sb.Append(ApiSecret);
                }
                string str = sb.ToString();
                MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
                string sign = System.BitConverter.ToString(md5.ComputeHash(System.Text.UTF8Encoding.Default.GetBytes(str)), 4, 8).Replace("-", "");
                sign = sign.ToLower();
                return sign;
            }

            /// <summary>
            /// 获取token
            /// </summary>
            /// <returns></returns>
            private string gettoken()
            {
                var filePath = AppDomain.CurrentDomain.BaseDirectory + @"File\token.txt";
                string token = string.Empty;
                if (File.Exists(filePath))
                {
                    token = File.ReadAllText(filePath);
                }
                return token;
            }
        }

        /// <summary>
        /// 向服务端推送测试用垃圾采集数据
        /// </summary>
        public class GarbageC2SDto //客户端向服务端请求的DTO
        {
            /// <summary>
            /// 垃圾称重数据,64位浮点进度，单位为千克
            /// </summary>
            public double weight { get; set; }

            /// <summary>
            /// 垃圾桶编码
            /// </summary>
            public string trash { get; set; }

            /// <summary>
            /// 垃圾类型,缺省类型 : 0,厨余垃圾 : 1,可回收物 : 2,有害垃圾 : 3,其他垃圾 : 4
            /// </summary>

            public int type { get; set; }

            /// <summary>
            /// 数据扫描时间,UNIX时间戳
            /// </summary>
            public long scanningTime { get; set; }

            /// <summary>
            /// 设备状态,使用中 : 0:使用中,异常 : 1,检修 : 2,检修结束 : 3,启用 : 4,未知 : 5
            /// </summary>
            public int d_status { get; set; }
        }

        /// <summary>
        /// 响应的数据
        /// </summary>
        public class ResponseData
        {
            /// <summary>
            /// 类型,6-心跳包,1-token,3-其他
            /// </summary>
            public int type { get; set; }

            /// <summary>
            /// 请求id
            /// </summary>
            public string invocationId { get; set; }

            /// <summary>
            /// 结果
            /// </summary>
            public string result { get; set; }

            /// <summary>
            /// 目标
            /// </summary>
            public string target { get; set; }

            /// <summary>
            /// 参数
            /// </summary>
            public List<string> arguments { get; set; }
        }

        private static void WSocketClient_OnOpen(object sender, EventArgs e)
        {
            Console.WriteLine($"已连接");
        }

        public static void SetTimeOut()
        {
            Task.Run(() =>
            {
                DateTime startime = DateTime.Now;
                while (true)
                {
                    if (wSocketClient.State == WebSocketState.Open)
                    {
                        if ((DateTime.Now - startime).TotalSeconds >= 15)
                        {
                            //发送心跳包
                            var message = @"{
    ""type"": 6
    }";
                            wSocketClient.Send(message);
                            startime = DateTime.Now;
                        }
                    }
                }
            });
        }

        private static byte[] RemoveSeparator(byte[] data)
        {
            List<byte> t = new List<byte>(data);
            t.Remove(0x1e);
            return t.ToArray();
        }
    }
}