using DotNetCore.CAP;
using Furion.DependencyInjection;
using Furion.DistributedIDGenerator;
using Mapster;
using Microsoft.AspNetCore.Http;
using Nirvana.Common;
using Nirvana.Common.ApiBase;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using YBDevice.Core;
using YBDevice.Entity;
using YBDevice.NApi.Application.UserInfo;

namespace YBDevice.NApi.Application.BusinessClient.DeviceInfo
{
    /// <summary>
    /// 设备管理
    /// </summary>
    public class DeviceService : BaseApiInfoService, IDeviceService, ITransient
    {
        private readonly ISqlSugarRepository<YB_Device> repository;
        private readonly SqlSugarClient dbClient;
        private readonly IHttpContextAccessor _httpContextAccessor;
        private readonly ICapPublisher _capBus;
        public DeviceService(ISqlSugarRepository<YB_Device> sqlSugarRepository, IHttpContextAccessor httpContextAccessor, ICapPublisher capPublisher)
        {
            repository = sqlSugarRepository;
            dbClient = repository.Context;
            _httpContextAccessor = httpContextAccessor;
            _capBus = capPublisher;
        }
        /// <summary>
        /// 设备激活
        /// </summary>
        /// <returns></returns>
        public async Task<ResultInfo> ActiveAsync(string sn, string code)
        {
            sn = sn.ToStrNoEmpty();
            code = code.ToStrNoEmpty();
            if (code.ToLower().StartsWith("http"))
            {
                var arr = code.Split('?');
                if (arr.Length != 2)
                {
                    return new ResultInfo(ResultState.FAIL, "请扫描产品背后二维码");
                }
                arr = arr[1].Split('=');
                if (arr.Length != 2)
                {
                    return new ResultInfo(ResultState.FAIL, "请扫描产品背后二维码");
                }
                code = arr[1];
            }
            if (sn.ToLower().StartsWith("http://ybapi.ybhdmob.com/body/get"))
            {
                var arr = sn.Split('&');
                if (arr.Length != 3)
                {
                    return new ResultInfo(ResultState.FAIL, "请扫码测量二维码");
                }
                var newarr = arr[1].Split('=');
                if (newarr.Length != 2)
                {
                    return new ResultInfo(ResultState.FAIL, "请扫码测量二维码");
                }
                sn = newarr[1];
            }
            //检查是否存在发货记录
            var productdev = await dbClient.Queryable<YB_OutProductDev>().Where(x => x.DeviceCode == code).FirstAsync();
            if (productdev == null)
            {
                var ua = _httpContextAccessor.HttpContext.Request.Headers["User-Agent"].ToString();
                var business = await dbClient.Queryable<YB_Business>().FirstAsync(x => x.Id == CurrentBusinessId);
                //增加日志
                await _capBus.PublishAsync("system.service.insertnoticelogger", new YB_NoticeLogger
                {
                    UserInfo = $"客户:{(business != null ? business.Name : "")}",
                    Id = IDGen.NextID(),
                    Info = $"设备序列号:{code},机器码:{sn}",
                    FromInfo = "未找到出货记录",
                    UA = ua
                });
                return new ResultInfo(ResultState.FAIL, "未找到出货记录,请联系客服人员");
            }
            var product = await dbClient.Queryable<YB_OutProduct>().FirstAsync(x => x.Id == productdev.OrderId);
            if (product == null)
            {
                var ua = _httpContextAccessor.HttpContext.Request.Headers["User-Agent"].ToString();
                var business = await dbClient.Queryable<YB_Business>().FirstAsync(x => x.Id == CurrentBusinessId);
                //增加日志
                await _capBus.PublishAsync("system.service.insertnoticelogger", new YB_NoticeLogger
                {
                    UserInfo = $"客户:{(business != null ? business.Name : "")}",
                    Id = IDGen.NextID(),
                    Info = $"设备序列号:{code},机器码:{sn}",
                    FromInfo = "未找到出货记录",
                    UA = ua
                });
                return new ResultInfo(ResultState.FAIL, "未找到出货记录,请联系客服人员");
            }
            //检查此sn是否已存在,如果不存在则进行注册,否则继续下一步
            var equ = await dbClient.Queryable<YB_Device>().FirstAsync(x => x.FacCode == code);
            if (equ == null)
            {
                var ua = _httpContextAccessor.HttpContext.Request.Headers["User-Agent"].ToString();
                var business = await dbClient.Queryable<YB_Business>().FirstAsync(x => x.Id == CurrentBusinessId);
                //增加日志
                await _capBus.PublishAsync("system.service.insertnoticelogger", new YB_NoticeLogger
                {
                    UserInfo = $"客户:{(business != null ? business.Name : "")}",
                    Id = IDGen.NextID(),
                    Info = $"设备序列号:{code},机器码:{sn}",
                    FromInfo = "设备未找到",
                    UA = ua
                });
                return new ResultInfo(ResultState.FAIL, "设备未找到,请联系客服人员");
            }
            //检查此设备是否已激活
            if (equ.Status == DeviceStatus.Run)
            {
                var ua = _httpContextAccessor.HttpContext.Request.Headers["User-Agent"].ToString();
                var business = await dbClient.Queryable<YB_Business>().FirstAsync(x => x.Id == CurrentBusinessId);
                //增加日志
                await _capBus.PublishAsync("system.service.insertnoticelogger", new YB_NoticeLogger
                {
                    UserInfo = $"客户:{(business != null ? business.Name : "")}",
                    Id = IDGen.NextID(),
                    Info = $"设备序列号:{code},机器码:{sn}",
                    FromInfo = "设备已运行,重复激活",
                    UA = ua
                });
                return new ResultInfo(ResultState.FAIL, "设备已运行,重复激活");
            }
            if (equ.Status == (int)DeviceStatus.Stop)
            {
                var ua = _httpContextAccessor.HttpContext.Request.Headers["User-Agent"].ToString();
                var business = await dbClient.Queryable<YB_Business>().FirstAsync(x => x.Id == CurrentBusinessId);
                //增加日志
                await _capBus.PublishAsync("system.service.insertnoticelogger", new YB_NoticeLogger
                {
                    UserInfo = $"客户:{(business != null ? business.Name : "")}",
                    Id = IDGen.NextID(),
                    Info = $"设备序列号:{code},机器码:{sn}",
                    FromInfo = "设备已停止运行",
                    UA = ua
                });
                return new ResultInfo(ResultState.FAIL, "设备已停止运行");
            }
            //检查此sn是否已存在
            if (await dbClient.Queryable<YB_Device>().AnyAsync(x => x.Ecode == sn && x.FacCode != code))
            {
                var ua = _httpContextAccessor.HttpContext.Request.Headers["User-Agent"].ToString();
                var business = await dbClient.Queryable<YB_Business>().FirstAsync(x => x.Id == CurrentBusinessId);
                //增加日志
                await _capBus.PublishAsync("system.service.insertnoticelogger", new YB_NoticeLogger
                {
                    UserInfo = $"客户:{(business != null ? business.Name : "")}",
                    Id = IDGen.NextID(),
                    Info = $"设备序列号:{code},机器码:{sn}",
                    FromInfo = "设备编号匹配失败",
                    UA = ua
                });
                return new ResultInfo(ResultState.FAIL, $"设备编号匹配失败,序列号:{code},机器码:{sn}");
            }
            //激活设备
            await dbClient.Updateable<YB_Device>().SetColumns(x => new YB_Device
            {
                ActiveTime = DateTime.Now,
                Status = DeviceStatus.Run,
                BusinessId = CurrentBusinessId,
                Ecode = sn
            }).Where(x => x.FacCode == code).ExecuteCommandAsync();

            //记录分配记录
            var allocdata = new YB_DeviceAlloc
            {
                Id = IDGen.NextID(),
                CreateTime = DateTime.Now,
                EquId = equ.Id,
                FromBusinessId = CurrentBusinessId,
                ToBusinessId = 0,
                Type = DeviceAllocType.ACTIVE
            };
            await dbClient.Insertable(allocdata).ExecuteCommandAsync();
            //更新统计
            int todaydevactivecnt = await dbClient.Queryable<YB_Device>().Where(x => x.BusinessId == CurrentBusinessId && SqlFunc.DateIsSame(x.LastHeartTime, DateTime.Now)).CountAsync();
            int devcnt = await dbClient.Queryable<YB_Device>().Where(x => x.BusinessId == CurrentBusinessId).CountAsync();
            int businesscnt = await dbClient.Queryable<YB_Business>().Where(x => x.ParentId == CurrentBusinessId).CountAsync();
            if (!await dbClient.Queryable<YB_BusinessRealData>().AnyAsync(x => x.BusinessId == CurrentBusinessId))
            {
                await dbClient.Insertable<YB_BusinessRealData>(new YB_BusinessRealData
                {
                    BusinessId = CurrentBusinessId,
                    Balance = 0,
                    BusinessCount = businesscnt,
                    CreateTime = DateTime.Now,
                    DevCount = devcnt,
                    TodayIncome = 0,
                    TodayResultCnt = 0,
                    TotalIncome = 0,
                    TotalResultCnt = 0,
                    TotalTxAmount = 0,
                    TodayDevCount = todaydevactivecnt,
                    TotalRealCnt = 0,
                    TodayRealCnt = 0
                }).ExecuteCommandAsync();
            }
            else
            {
                await dbClient.Updateable<YB_BusinessRealData>().SetColumns(x => new YB_BusinessRealData
                {
                    DevCount = devcnt,
                    TodayDevCount = todaydevactivecnt,
                    BusinessCount = businesscnt
                }).Where(x => x.BusinessId == CurrentBusinessId).ExecuteCommandAsync();
            }
            return new ResultInfo(ResultState.SUCCESS, "设备激活成功");
        }
        /// <summary>
        /// 设备详情
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<ResultInfo> DetailAsync(int id)
        {
            var equ = await dbClient.Queryable<YB_Device>().FirstAsync(x => x.Id == id);
            if (equ == null)
            {
                return new ResultInfo(ResultState.FAIL, "设备未找到");
            }
            var realdata = await dbClient.Queryable<YB_EquRealData>().FirstAsync(x => x.EquId == equ.Id && x.BusinessId == CurrentBusinessId);
            var type = await dbClient.Queryable<YB_DeviceType>().Where(x => equ.Type == x.Code).FirstAsync();
            var data = new DeviceListDto
            {
                DayCnt = realdata != null ? realdata.TodayResultCnt.ToString() : "0",
                TotalCnt = realdata != null ? realdata.TotalResultCnt.ToString() : "0",
                Status = equ.Status,
                FacEcode = equ.FacCode,
                Id = equ.Id,
                LastHeartTime = equ.LastHeartTime.HasValue ? equ.LastHeartTime.ToYearDateTime() : "-",
                Name = equ.Name,
                Type = equ.Type,
                TypeName = type.Name
            };
            return new ResultInfo(ResultState.SUCCESS, "success", data);
        }
        /// <summary>
        /// 获取设备类型列表
        /// </summary>
        /// <param name="appid">小程序appid</param>
        /// <returns></returns>
        public async Task<ResultInfo> GetDevTypeListAsync(string appid)
        {
            List<YB_DeviceTypeExt> list = new List<YB_DeviceTypeExt>();
            //兼容原理的接口，等新的全部更新之后可去除,20211215
            if (string.IsNullOrEmpty(appid))
            {
                list = await dbClient.Queryable<YB_DeviceTypeExt>().Where(x => x.Status == StatusType.Enabled || x.Id == 2).ToListAsync();
            }
            else
            {
                var AppData = await dbClient.Queryable<YB_DeviceTypeApp>().Where(x => x.Status == StatusType.Enabled && x.AppId == appid).FirstAsync();
                if (AppData != null)
                {
                    var ids = AppData.DevType.Split(",").ToList();
                    var types = await dbClient.Queryable<YB_DeviceType>().ToListAsync();
                    types.ForEach(x =>
                    {
                        if (ids.Contains($"{x.Code}"))
                        {
                            list.Add(new YB_DeviceTypeExt
                            {
                                Name = x.ExtName,
                                HeadImg = x.HeadImg,
                                Id = x.Code
                            });
                        }
                    });
                }
            }
            var returnlist = list.Adapt<List<UserDevTypeS2CDto>>();
            return new ResultInfo(ResultState.SUCCESS, "success", returnlist);
        }

        /// <summary>
        /// 名下设备列表
        /// </summary>
        /// <param name="queryParams"></param>
        /// <returns></returns>
        public async Task<ResultInfo> GetListAsync(QueryParams queryParams)
        {
            RefAsync<int> totalnum = 0;
            var temquery = dbClient.Queryable<YB_Device>();
            if (queryParams.queryParam != null && queryParams.queryParam.Count > 0)
            {
                List<IConditionalModel> conModels = new List<IConditionalModel>();
                queryParams.queryParam.ForEach(x =>
                {
                    if (!string.IsNullOrEmpty(x.Value))
                    {
                        conModels.Add(new ConditionalModel()
                        {
                            FieldName = x.Name,
                            ConditionalType = (ConditionalType)x.Type,
                            FieldValue = x.Value.Trim()
                        });
                    }
                });
                if (conModels.Count > 0)
                {
                    temquery = temquery.Where(conModels);
                }
            }
            temquery = temquery.Where(x => x.BusinessId == CurrentBusinessId || x.BindBusinessId == CurrentBusinessId || SqlFunc.Subqueryable<YB_DeviceAlloc>().Where(e => (e.ToBusinessId == CurrentBusinessId || e.FromBusinessId == CurrentBusinessId) && e.EquId == x.Id).Any());

            var query = await temquery.OrderBy(x => x.LastHeartTime, OrderByType.Desc)
                .Select(x => new DeviceListDto
                {
                    Id = x.Id,
                    FacEcode = x.FacCode,
                    LastHeartTime = SqlFunc.ToString(x.LastHeartTime),
                    Name = x.Name,
                    Type = x.Type,
                    Status = x.Status
                })
                .Mapper((it, cache) =>
                {
                    if (!string.IsNullOrEmpty(it.LastHeartTime))
                    {
                        it.LastHeartTime = it.LastHeartTime.ToYearDateTime();
                    }
                    else
                    {
                        it.LastHeartTime = "-";
                    }
                    var alltypes = cache.Get(list =>
                    {
                        var ids = list.Select(x => x.Type).ToList();
                        return dbClient.Queryable<YB_DeviceType>().Where(x => ids.Contains(x.Code)).ToList();
                    });
                    it.TypeName = alltypes.FirstOrDefault(x => x.Code == it.Type)?.Name;

                    var alldata = cache.Get(list =>
                    {
                        var ids = list.Select(x => x.Id).ToList();
                        return dbClient.Queryable<YB_EquRealData>().Where(x => ids.Contains(x.EquId) && x.BusinessId == CurrentBusinessId).ToList();
                    });
                    var data = alldata.FirstOrDefault(x => x.EquId == it.Id);
                    it.DayCnt = data != null ? data.TodayResultCnt.ToString() : "0";
                    var allbus = cache.Get(list =>
                    {
                        var ids = list.Select(x => x.BusinessId).ToList();
                        return dbClient.Queryable<YB_Business>().Where(x => ids.Contains(x.Id)).ToList();
                    });
                    it.BusinessName = allbus.FirstOrDefault(x => x.Id == it.BusinessId)?.Name;
                })
                .ToPageListAsync(queryParams.offset, queryParams.limit, totalnum);
            var result = new PageParms<DeviceListDto>
            {
                page = queryParams.offset,
                Items = query,
                totalnum = totalnum,
                limit = queryParams.limit
            };
            return new ResultInfo(ResultState.SUCCESS, "success", result);
        }
        /// <summary>
        /// 更新设备名称
        /// </summary>
        /// <param name="id"></param>
        /// <param name="name"></param>
        /// <returns></returns>
        public async Task<ResultInfo> UpdateDevName(int id, string name = "")
        {
            var dev = await dbClient.Queryable<YB_Device>().FirstAsync(x => x.Id == id);
            if (dev == null)
            {
                return new ResultInfo(ResultState.FAIL, "设备未找到");
            }
            if (string.IsNullOrEmpty(name))
            {
                return new ResultInfo(ResultState.FAIL, "名称不可为空");
            }
            if (dev.BusinessId != CurrentBusinessId)
            {
                return new ResultInfo(ResultState.FAIL, "您没有修改权限");
            }
            await dbClient.Updateable<YB_Device>().SetColumns(x => new YB_Device
            {
                Name = name
            }).Where(x => x.Id == id).ExecuteCommandAsync();
            return new ResultInfo(ResultState.SUCCESS, "修改成功");
        }
    }
}
