using LY.App.Common;
using LY.App.Common.Redis;
using LY.App.Common.WebSocket;
using LY.App.Extensions.DI;
using LY.App.Model;
using Mapster;
using Microsoft.AspNetCore.SignalR;
using NetTopologySuite.Geometries;
using NetTopologySuite.IO;
using SqlSugar;
using StackExchange.Redis;
using System.Collections.Concurrent;
using System.Reflection;
namespace LY.App.Service
{
    /// 
    /// 报警服务
    /// 
    [ServiceInjection(InjectionType.Transient)]
    public class AlarmService
    {
        private readonly SqlSugarClient _db;
        private readonly IConfiguration _config;
        private readonly RedisService _redisService;
        private readonly PushService _pushService;
        public AlarmService(SqlSugarClient db, IConfiguration config, RedisService redisService, PushService pushService)
        {
            _db = db;
            _config = config;
            _redisService = redisService;
            _pushService = pushService;
        }
        /// 
        /// 新增报警信息
        /// 
        /// 
        /// 
        public async Task AddAlarm(RevData input)
        {
            await SetDeviceStataus(input);
            if (input.data.Any())
            {
                var key = RedisKeyList.DeviceInfo(input.product_ad_id);
                var deviceinfo = await _redisService.GetAsync(key);
                if (deviceinfo == null)
                {
                    deviceinfo = await _db.CopyNew().Queryable().Where(s => s.DeviceSN == input.product_ad_id).FirstAsync();
                    if (deviceinfo == null)
                    {
                        return new ApiResult() { code = 1, msg = "设备不存在" };
                    }
                    await _redisService.SetAsync(key, deviceinfo, TimeSpan.FromDays(1));
                }
                var entity = input.data.Adapt>();
                foreach (var item in entity)
                {
                    item.BatchId = await GetBatId(item.serial_number);
                    item.DeviceId = deviceinfo.Id;
                    item.DeviceName = deviceinfo.Name;
                    item.positionId = deviceinfo.PositionId;
                    item.PostionName = deviceinfo.PositionName;
                    item.Time = input.time;
                    item.distance = GisHelper.HaversineDistance(item.drone_lat, item.drone_lon, item.app_lat, item.app_lon);
                    item.alarmLevel = await GetAlarmLevel(deviceinfo.PositionId, item.drone_lon, item.drone_lat);
                }
                await _db.CopyNew().Insertable(entity).SplitTable().ExecuteReturnSnowflakeIdListAsync();
                //推送报警信息
                await _pushService.SendMessageToAll(new { msgType = "event", data = entity });
            }
            return new ApiResult();
        }
        /// 
        /// 计算入侵级别
        /// 
        /// 
        /// 
        /// 
        /// 
        private async Task GetAlarmLevel(long positionId, double lon, double lat)
        {
            int result = 0;
            if (positionId > 0 && lon > 0 && lat > 0)
            {
                var key = RedisKeyList.PositioinRegion(positionId);
                var geodata = await _redisService.GetAsync(key);
                if (geodata == null)
                {
                    geodata = await _db.CopyNew().Queryable()
                       .Where(s => s.Id == positionId)
                       .Select(s => s.Region)
                       .FirstAsync();
                    await _redisService.SetAsync(key, geodata);
                }
                WKTReader reader = new WKTReader();
                Geometry point = reader.Read($"POINT ({lon} {lat})");
                Geometry multipolygon = reader.Read(geodata);
                if (multipolygon.Contains(point))
                {
                    return 1;
                }
            }
            return result;
        }
        /// 
        /// 推送消息
        /// 
        /// 
        /// 
        public async Task PushMessage(object message)
        {
            //推送前端无人机数据
            await _pushService.SendMessageToAll(message);
        }
        /// 
        /// 设置设备在线状态,并更新数据
        /// 
        /// 
        /// 
        private async Task SetDeviceStataus(RevData input)
        {
            await _redisService.SetAsync(RedisKeyList.DeviceStatus(input.product_ad_id), true, TimeSpan.FromSeconds(5));
            //更新 设备缓存
            var key = RedisKeyList.DeviceInfo(input.product_ad_id);
            var deviceinfo = await _redisService.GetAsync(key);
            if (deviceinfo != null)
            {
                deviceinfo.Lat = input.product_lat;
                deviceinfo.Lon = input.product_lon;
                await _redisService.SetAsync(key, deviceinfo);
            }
        }
        private async Task GetBatId(string droneId)
        {
            var timeSpan = Convert.ToDouble(_config["BatchId"]);
            var key = RedisKeyList.BatchIdBysn(droneId);
            //从redis取出batchid,如果没有,就新加一个,每次访问都重置一下过期时间来模拟滑动过期
            var batchId = await _redisService.GetAsync(key);
            if (batchId == 0)
            {
                batchId = SnowFlakeSingle.Instance.NextId();
            }
            await _redisService.SetAsync(key, batchId, TimeSpan.FromSeconds(timeSpan));
            return batchId;
        }
        /// 
        /// //根据batchId获取报警信息
        /// 
        /// 
        /// 
        public async Task GetByBatchId(long batchId)
        {
            var items = await _db.Queryable().SplitTable()
                  .Where(s => s.BatchId == batchId)
                  .OrderBy(s => s.Id).Select(s => new
                  {
                      Lon = s.drone_lon,
                      Lat = s.drone_lat,
                      Alt = s.height,
                      s.CreateTime,
                      AlarmLevel = s.alarmLevel,
                  }).ToListAsync();
            return new ApiResult() { data = items };
        }
        /// 
        /// 首页统计
        /// 
        /// 
        public async Task> IndexCount()
        {
            Dictionary result = new Dictionary();
            // 获取当前日期和时间
            DateTime currentDate = DateTime.Now;
            // 获取当天的开始时间
            DateTime startDate = currentDate.Date;
            // 获取当天的结束时间(23:59:59)
            DateTime endDate = currentDate.Date.AddDays(1).AddTicks(-1);
            //计算当天
            var todaywaring = await _db.Queryable().SplitTable()
                .Where(s => s.alarmLevel > 0)
                .Where(s => s.CreateTime >= startDate && s.CreateTime <= endDate)
                .GroupBy(s => s.BatchId)
                .Select(s => s.BatchId).CountAsync();
            //计算当天处理次数
            //var todayhandle = _db.Queryable()
            //    .Where(s => s.BatchId > 0)
            //    .Where(s => s.CreateTime >= startDate && s.CreateTime <= endDate);
            //计算总数
            var totalcount = _db.Queryable().SplitTable()
                        .Where(s => s.alarmLevel > 0)
                 .GroupBy(s => s.BatchId)
                 .Select(s => s.BatchId);
            //计算处理总数
            //var totalhandle = _db.Queryable()
            //    .Where(x => x.BatchId > 0);
            //组合查询结果
            //return new
            //{
            //    todaywaring = await todaywaring.CountAsync(),
            //    todayhandle =0,
            //    totalcount = await totalcount.CountAsync(),
            //    totalhandle = 0
            //};
            result.Add("todaywaring", todaywaring);
            result.Add("todayhandle", 0);
            result.Add("totalcount", await totalcount.CountAsync());
            result.Add("totalhandle", 0);
            return result;
        }
        /// 
        /// 分页
        /// 
        /// 
        /// 
        public async Task GetPage(AlarmReq input)
        {
            var result = await CreatePage(input);
            return new ApiResult()
            {
                code = 0,
                data = new
                {
                    total = result.Item1,
                    items = result.Item2
                }
            };
        }
        /// 
        /// 热力图
        /// 
        /// 
        public async Task hotmap()
        {
            var query = await _db.Queryable().SplitTable()
                .GroupBy(x => new { Lon = SqlFunc.Round(x.drone_lon, 4), Lat = SqlFunc.Round(x.drone_lat, 4) }) // 按经纬度分组
                .Select(x => new
                {
                    Lon = SqlFunc.Round(x.drone_lon, 4),
                    Lat = SqlFunc.Round(x.drone_lat, 4),
                    Count = SqlFunc.AggregateCount(x.BatchId), // 统计去重后的BatchId
                })
                .ToListAsync();
            return new ApiResult() { data = query };
        }
        /// 
        /// 列表
        /// 
        /// 
        /// 
        public async Task>> CreatePage(AlarmReq input)
        {
            RefAsync total = 0;
            var items = await _db.Queryable().SplitTable()
                .WhereIF(input.Frequency.HasValue, st => st.freq == input.Frequency.Value)
                .WhereIF(!string.IsNullOrEmpty(input.sn), s => s.serial_number.Contains(input.sn))
                .WhereIF(!string.IsNullOrEmpty(input.model), st => st.device_type == input.model)
                .WhereIF(input.strartDate.HasValue, st => st.CreateTime >= input.strartDate.Value)
                .WhereIF(input.endDate.HasValue, st => st.CreateTime <= input.endDate.Value.AddDays(1))
                .OrderBy(s => s.BatchId, OrderByType.Desc)
                .GroupBy(s => new { s.BatchId, s.serial_number, s.device_type, s.positionId, s.PostionName ,s.freq})
                .Select(st => new AlarmRepDto
                {
                    batchId = st.BatchId.ToString(),
                    startTime = SqlFunc.AggregateMin(st.CreateTime),
                    endTime = SqlFunc.AggregateMax(st.CreateTime),
                    sn = st.serial_number,
                    Frequency = st.freq,
                    duration = (SqlFunc.AggregateMax(st.CreateTime) - SqlFunc.AggregateMin(st.CreateTime)).TotalSeconds,
                    model = st.device_type,
                    positionId = st.positionId,
                    positionName = st.PostionName
                }).MergeTable()//合并查询
                .ToPageListAsync(input.pageNum, input.pageSize, total);
            return Tuple.Create(total.Value, items);
        }
        /// 
        /// 报表统计
        /// 
        /// 
        public async Task GetReport(DateTime? start, DateTime? end)
        {
            start = start.HasValue ? start.Value : DateTime.Now.AddMonths(-1);
            end = end.HasValue ? end.Value.AddDays(1) : DateTime.Now.Date.AddDays(1);
            var query = await _db.Queryable().SplitTable()
                .Where(s => s.alarmLevel > 0)
                .WhereIF(start.HasValue, st => st.CreateTime >= start.Value)
                .WhereIF(end.HasValue, st => st.CreateTime <= end.Value.AddDays(1))
                .GroupBy(s => new { s.BatchId, s.serial_number, s.device_type, s.positionId, s.PostionName, s.DeviceId, s.DeviceName })
                .Select(st => new
                {
                    batchId = st.BatchId,
                    startTime = SqlFunc.AggregateMin(st.CreateTime),
                    endTime = SqlFunc.AggregateMax(st.CreateTime),
                    sn = st.serial_number,
                    Frequency = SqlFunc.AggregateMax(st.freq),
                    duration = (SqlFunc.AggregateMax(st.CreateTime) - SqlFunc.AggregateMin(st.CreateTime)).TotalSeconds,
                    model = st.device_type,
                    positionName = st.PostionName,
                    deviceId = st.DeviceId,
                    deviceName = st.DeviceName
                }).MergeTable()//合并查询
                .ToListAsync();
            return new ApiResult()
            {
                data = new
                {
                    freq = query.GroupBy(s => new { freq = FreqConvert.CoverFreq(s.Frequency) })
                   .Select(b => new
                   {
                       b.Key.freq,
                       count = b.Count()
                   }),
                    model = query.GroupBy(s => new { s.model })
                   .Select(b => new
                   {
                       b.Key.model,
                       count = b.Count()
                   }),
                    position = query.GroupBy(s => new { s.positionName })
                   .Select(s => new
                   {
                       s.Key.positionName,
                       count = s.Count()
                   }),
                    time = query.GroupBy(s => s.startTime.ToString("HH"))
                    .Select(it => new
                    {
                        it.Key,
                        count = it.Count()
                    }),
                    date = query.GroupBy(s => s.startTime.ToString("yyyy-MM-dd"))
                    .Select(it => new
                    {
                        it.Key,
                        count = it.Count()
                    }),
                    device = query.GroupBy(s => new { s.deviceName })
                   .Select(b => new
                   {
                       b.Key.deviceName,
                       count = b.Count()
                   })
                }
            };
        }
        /// 
        /// 热力图,取经纬度4位数
        /// 
        /// 
        /// 
        private async Task