using Furion;
using Furion.DependencyInjection;
using Furion.DistributedIDGenerator;
using Nirvana.Common;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Waste.Domain;

namespace Waste.Application.ThirdApiInfo
{
    /// <summary>
    /// 设备对接接口
    /// </summary>
    public class OpenService : IOpenService, ITransient
    {
        private static string ApiUrl = App.Configuration["SZDevPlatSetting:ApiUrl"];
        private static string UserId = App.Configuration["SZDevPlatSetting:UserId"];
        private static string ApiSecret = App.Configuration["SZDevPlatSetting:ApiSecret"];
        private static string ApiSecretHash = App.Configuration["SZDevPlatSetting:ApiSecretHash"];
        private static string WebSocketUrl = App.Configuration["SZDevPlatSetting:SocketUrl"];

        private readonly ISqlSugarRepository<W_Device> repository;
        private readonly SqlSugarClient dbClient;
        private readonly ISuZhouService _suZhouService;
        private readonly ILoggerService _loggerService;
        public OpenService(ISqlSugarRepository<W_Device> sqlSugarRepository, ISuZhouService suZhouService, ILoggerService loggerService)
        {
            repository = sqlSugarRepository;
            dbClient = repository.Context;
            _suZhouService = suZhouService;
            _loggerService = loggerService;
        }
        /// <summary>
        /// 更新上报状态
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public async Task<ResultInfo> UpdateStatusAsync(UpdateStatusDto data)
        {
            Guid resultid = Guid.Empty;
            if (!string.IsNullOrEmpty(data.ResultId) && Guid.TryParse(data.ResultId, out resultid))
            {
                if (await dbClient.Queryable<W_ResultExt>().AnyAsync(x => x.ResultId == resultid))
                {
                    await dbClient.Updateable<W_ResultExt>().SetColumns(x => new W_ResultExt
                    {
                        Status = data.status
                    }).Where(x => x.ResultId == resultid).ExecuteCommandAsync();
                }
                else
                {
                    var insertdata = new W_ResultExt
                    {
                        Id = IDGen.NextID(),
                        Status = data.status,
                        CreateTime = DateTime.Now,
                        ResultId = resultid
                    };
                    await dbClient.Insertable(insertdata).ExecuteCommandAsync();
                }
                return new ResultInfo(ResultState.SUCCESS, "success");
            }
            return new ResultInfo(ResultState.SUCCESS, "记录id未找到");
        }
        /// <summary>
        /// 获取设备上报相关信息
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public async Task<ResultInfo> GetDevInfoAsync(GetDevInfoRequestDto data)
        {
            //更新上报记录结果
            Guid resultid = Guid.Empty;
            if (!string.IsNullOrEmpty(data.ResultId) && Guid.TryParse(data.ResultId, out resultid))
            {
                var device = await dbClient.Queryable<W_Device>().FirstAsync(x => x.Ecode == data.ECode);
                if (device == null)
                {
                    return new ResultInfo(ResultState.FAIL, "设备未找到");
                }
                var devicesecret = await dbClient.Queryable<W_SZDevice>().FirstAsync(x => x.DeviceId == device.Id);
                if (devicesecret == null || string.IsNullOrEmpty(devicesecret.Secret)
                    || string.IsNullOrEmpty(devicesecret.SecretHash)
                    || string.IsNullOrEmpty(devicesecret.DevId))
                {
                    return new ResultInfo(ResultState.FAIL, "设备还未获取验证信息");
                }
                int timestamp = _suZhouService.GetUTCTimestamp();
                int noncestr = _suZhouService.GetNonce();
                var result = await dbClient.Queryable<W_Result>().FirstAsync(x => x.Id == resultid);
                if (result == null)
                {
                    return new ResultInfo(ResultState.SUCCESS, "记录id未找到");
                }
                var returndata = new GetDevInfoResponseDto
                {
                    DeviceId = devicesecret.DevId,
                    noncestr = noncestr,
                    timestamp = timestamp,
                    Secret = devicesecret.Secret,
                    SecretHash = devicesecret.SecretHash,
                    UserId = UserId,
                    PostUrl = ApiUrl,
                    ScanningTime = timestamp,
                    ResultId = resultid,
                    trash = result.Registration,
                    Weight = result.GrossWeight.ToDouble(),
                    status = 0,
                    IsSuccessed = true,
                    type = TrashType(result.WasteType)
                };
                string[] paramlist = new string[] {
                returndata.Weight.ToString(),returndata.trash,returndata.type.ToString(),returndata.ScanningTime.ToString(),returndata.status.ToString()};
                returndata.sign = _suZhouService.GetUserApiSign(returndata.Secret, paramlist);
                return new ResultInfo(ResultState.SUCCESS, "success", returndata);
            }
            else
            {
                var device = await dbClient.Queryable<W_Device>().FirstAsync(x => x.Ecode == data.ECode);
                if (device == null)
                {
                    return new ResultInfo(ResultState.FAIL, "设备未找到");
                }
                var returndata = new GetDevInfoResponseDto { 
                    ResultId= IDGen.NextID(),
                    UserId = UserId,
                    PostUrl= ApiUrl
                };
                //解析协议,IC卡数据@垃圾桶编号@厨余垃圾@7.91
                // 00000000003031 40 0F00010009 40 C6E4CBFBC0ACBBF8 40 31352E39
                // 00000000003031 40 000F000002 40 C6E4CBFBC0ACBBF8 40 35312E30 0D0A
                if (!string.IsNullOrEmpty(data.data) && data.data.Length > 52)
                {
                    data.data = data.data.Replace(" ", "");
                    //收到的为16进制,对数据进行解析,0-4预留,5-垃圾种类,6-垃圾桶大小,7-@,8-12垃圾桶编号,13@,14-21垃圾种类汉字,22@,23-结束重量, OD OA 回车换行
                    data.data = data.data.Substring(0, data.data.Length - 4);
                    var trashhex = data.data.Substring(16, 10); //垃圾桶编号
                    var typehex = data.data.Substring(28, 16); //垃圾种类
                    var sizehex = data.data.Substring(12, 2);//桶大小,30-小桶,31-大桶
                    var weighthex = data.data.Substring(46, data.data.Length - 46);
                    returndata.trash = HextToDec(trashhex).ToString(); //垃圾桶编号使用10进制
                    var type = GetChsFromHex(typehex);
                    var weight = GetChsFromHex(weighthex);
                    returndata.type = TrashType(type);
                    returndata.Weight = weight.ToDouble();
                    //计算净重,毛重-皮重=净重，如果净重小于等于0则不上报保存
                    returndata.Weight = (returndata.Weight - device.Tare.ToDouble()).ToDouble(2);
                    if (returndata.Weight <= 0)
                    {
                        _loggerService.AddLogger($"重量小于等于0:{returndata.ToJson()}", 1);
                        return new ResultInfo(ResultState.FAIL, "无效的重量");
                    }
                    //检查是否为15分钟内第一次上报
                    var time15 = DateTime.Now.AddMinutes(-15);
                    if(await dbClient.Queryable<W_Result>().AnyAsync(x=>x.DeviceId == device.Id && x.Registration == returndata.trash && x.CreateTime > time15))
                    {
                        _loggerService.AddLogger($"重复垃圾桶编号的数据:{returndata.ToJson()}", 1);
                        return new ResultInfo(ResultState.FAIL, "15分钟内同一垃圾桶编号上报");
                    }
                    returndata.IsSuccessed = true;
                    //保存测量结果
                    var devicedata = await dbClient.Queryable<W_DeviceData>().FirstAsync(x => x.DeviceId == device.Id);
                    DateTime time = DateTime.Now;
                    //检查设备是否为今天第一次上报
                    bool isfrist = false;
                    if (device.LastHeartTime.HasValue && device.LastHeartTime.Value.Date != DateTime.Now.Date)
                    {
                        isfrist = true;
                    }
                    //记录数据
                    data.IMEI = data.IMEI.ToStr();
                    data.ICCID = data.ICCID.ToStr();
                    data.IMSI = data.IMSI.ToStr();
                    await dbClient.Ado.UseStoredProcedure().ExecuteCommandAsync("Proc_InsertResult", new
                    {
                        deviceid = device.Id,
                        businessid = device.Businessid,
                        resultid = returndata.ResultId,
                        imei = data.IMEI,
                        iccid = data.ICCID,
                        imsi = data.IMSI,
                        time = time,
                        latitude = data.Latitude,
                        longitude = data.Longitude,
                        sign = data.GSLQ,
                        city = "",
                        area = returndata.trash,
                        wastetype = type,
                        weigth = weight,
                        isheart = 0,
                        tare = device.Tare,
                        isfrist = isfrist
                    });
                }
                var devicesecret = await dbClient.Queryable<W_SZDevice>().FirstAsync(x => x.DeviceId == device.Id);
                if (devicesecret == null || string.IsNullOrEmpty(devicesecret.Secret)
                    || string.IsNullOrEmpty(devicesecret.SecretHash)
                    || string.IsNullOrEmpty(devicesecret.DevId))
                {
                    return new ResultInfo(ResultState.FAIL, "设备还未获取验证信息");
                }
                int timestamp = _suZhouService.GetUTCTimestamp();
                int noncestr = _suZhouService.GetNonce();
                returndata.DeviceId = devicesecret.DevId;
                returndata.noncestr = noncestr;
                returndata.timestamp = timestamp;
                returndata.Secret = devicesecret.Secret;
                returndata.SecretHash = devicesecret.SecretHash;
                returndata.ScanningTime = timestamp;
                string[] paramlist = new string[] {
                returndata.Weight.ToString(),returndata.trash,returndata.type.ToString(),returndata.ScanningTime.ToString(),returndata.status.ToString()
            };
                returndata.sign = _suZhouService.GetUserApiSign(returndata.Secret, paramlist);
                _loggerService.AddLogger($"发送的数据:{returndata.ToJson()}", 1);
                return new ResultInfo(ResultState.SUCCESS, "success", returndata);
            }
        }
        /// <summary>
        /// 16进制转汉字
        /// </summary>
        /// <param name="hex"></param>
        /// <returns></returns>
        private string GetChsFromHex(string hex)
        {
            if (hex == null)
                return "";
            if (hex.Length % 2 != 0)
            {
                hex += "20";//空格
            }
            // 需要将 hex 转换成 byte 数组。
            byte[] bytes = new byte[hex.Length / 2];
            for (int i = 0; i < bytes.Length; i++)
            {
                try
                {
                    // 每两个字符是一个 byte。
                    bytes[i] = byte.Parse(hex.Substring(i * 2, 2),
                        System.Globalization.NumberStyles.HexNumber);
                }
                catch
                {
                }
            }
            // 获得 GB2312，Chinese Simplified。
            Encoding chs = Encoding.GetEncoding("gb2312");
            return chs.GetString(bytes);
        }
        /// <summary>
        /// 16进制转10进制
        /// </summary>
        /// <param name="hex"></param>
        /// <returns></returns>
        public long HextToDec(string hex)
        {
            char[] nums = hex.ToCharArray();
            long total = 0;
            try
            {
                for (int i = 0; i < nums.Length; i++)
                {
                    String strNum = nums[i].ToString().ToUpper();
                    switch (strNum)
                    {
                        case "A":
                            strNum = "10";
                            break;
                        case "B":
                            strNum = "11";
                            break;
                        case "C":
                            strNum = "12";
                            break;
                        case "D":
                            strNum = "13";
                            break;
                        case "E":
                            strNum = "14";
                            break;
                        case "F":
                            strNum = "15";
                            break;
                        default:
                            break;
                    }
                    double power = Math.Pow(16, Convert.ToDouble(nums.Length - i - 1));
                    total += Convert.ToInt64(strNum) * Convert.ToInt64(power);
                }

            }
            catch (System.Exception ex)
            {
                string strErorr = ex.ToString();
                return 0;
            }


            return total;
        }
        /// <summary>
        /// 心跳数据上报
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public async Task<ResultInfo> PostHeartAsync(DevHeartRequestDto data)
        {
            var device = await dbClient.Queryable<W_Device>().FirstAsync(x => x.Ecode == data.ECode);
            if (device == null)
            {
                return new ResultInfo(ResultState.FAIL, "设备未找到");
            }
            if (await dbClient.Queryable<W_DeviceData>().AnyAsync(x => x.DeviceId == device.Id))
            {
                //更新设备心跳信息
                if (data.Latitude == 0 || data.Longitude == 0)
                {
                    await dbClient.Updateable<W_DeviceData>()
                        .SetColumns(x => new W_DeviceData
                        {
                            LastBeatTime = DateTime.Now
                        })
                        .Where(x => x.DeviceId == device.Id).ExecuteCommandAsync();
                }
                else
                {
                    string longitude = data.Longitude.ToString();
                    string Latitude = data.Latitude.ToString();
                    await dbClient.Updateable<W_DeviceData>()
                     .SetColumns(x => new W_DeviceData
                     {
                         LastBeatTime = DateTime.Now,
                         Longitude = longitude,
                         Latitude = Latitude
                     })
                     .Where(x => x.DeviceId == device.Id).ExecuteCommandAsync();
                }
            }
            else
            {
                var insertdata = new W_DeviceData
                {
                    DeviceId = device.Id,
                    Sign = data.GSLQ.ToString(),
                    IMSI = data.IMSI,
                    ICCID = data.ICCID,
                    IMEI = data.IMEI,
                    LastBeatTime = DateTime.Now,
                    Latitude = data.Latitude.ToString(),
                    Longitude = data.Longitude.ToString()
                };
                await dbClient.Insertable(insertdata).ExecuteCommandAsync();
            }
            return new ResultInfo(ResultState.SUCCESS, "success");
        }
        /// <summary>
        /// 获取设备注册信息,第一次开机使用
        /// </summary>
        /// <param name="ecode"></param>
        /// <returns></returns>
        public async Task<ResultInfo> RegInfoAsync(string ecode)
        {
            var device = await dbClient.Queryable<W_Device>().FirstAsync(x => x.Ecode == ecode);
            if (device == null)
            {
                return new ResultInfo(ResultState.FAIL, "设备未找到", new DevRegInfoResponseDto());
            }
            //更新开机时间
            if (await dbClient.Queryable<W_DeviceData>().AnyAsync(x => x.DeviceId == device.Id))
            {
                await dbClient.Updateable<W_DeviceData>()
                         .SetColumns(x => new W_DeviceData
                         {
                             LastStartTime = DateTime.Now
                         })
                         .Where(x => x.DeviceId == device.Id).ExecuteCommandAsync();
            }
            else
            {
                var insertdata = new W_DeviceData
                {
                    DeviceId = device.Id,
                    Sign = "",
                    IMSI = "",
                    ICCID = "",
                    IMEI = "",
                    Latitude = "0",
                    Longitude = "0",
                    LastStartTime = DateTime.Now
                };
                await dbClient.Insertable(insertdata).ExecuteCommandAsync();
            }
            var data = new DevRegInfoResponseDto
            {
                status = 0,
                WebSocketUrl = WebSocketUrl
            };
            //获取授权信息
            var devicesecret = await dbClient.Queryable<W_SZDevice>().FirstAsync(x => x.DeviceId == device.Id);
            if (devicesecret != null && !string.IsNullOrEmpty(devicesecret.Secret)
                && !string.IsNullOrEmpty(devicesecret.SecretHash)
                && !string.IsNullOrEmpty(devicesecret.DevId))
            {
                data.timestamp = _suZhouService.GetUTCTimestamp();
                data.noncestr = _suZhouService.GetNonce();
                data.UserId = UserId;
                data.Secret = devicesecret.Secret;
                data.SecretHash = devicesecret.SecretHash;
                data.DeviceId = devicesecret.DevId.ToString();
            }
            return new ResultInfo(ResultState.SUCCESS, "success", data);
        }
        private int TrashType(string type)
        {
            if (type == "厨余垃圾") return 1;
            else if (type == "可回收物") return 2;
            else if (type == "有害垃圾") return 3;
            else if (type == "其他垃圾") return 4;
            else return 0;
        }
        private int GetTimestamp(DateTime time)
        {
            DateTime dateTimeStart = TimeZoneInfo.ConvertTimeToUtc(new DateTime(1970, 1, 1, 8, 0, 0));
            int timestamp = Convert.ToInt32((time - dateTimeStart).TotalSeconds);
            return timestamp;
        }
        /// <summary>
        /// 字节数组转16进制
        /// </summary>
        /// <param name="bt"></param>
        /// <returns></returns>
        private string BytesToHexStr(byte[] bt)
        {
            string returnStr = "";
            if (bt != null)
            {
                for (int i = 0; i < bt.Length; i++)
                {
                    returnStr += bt[i].ToString("X2");
                }
            }
            return returnStr;
        }
    }
}
