using Furion.DependencyInjection;
using Furion.DistributedIDGenerator;
using Mapster;
using Nirvana.Common;
using Nirvana.Common.ApiBase;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Data.SqlTypes;
using System.Linq;
using System.Threading.Tasks;
using YBDevice.Core;
using YBDevice.Entity;

namespace YBDevice.Application.DeviceInfo
{
    /// <summary>
    /// 设备管理
    /// </summary>
    public class DeviceService : IDeviceService, ITransient
    {
        private readonly ISqlSugarRepository<YB_Device> repository;
        private readonly SqlSugarClient dbClient;
        private readonly ICommonService _commonService;
        private readonly OperatorModel currentUser;
        public DeviceService(ISqlSugarRepository<YB_Device> sqlSugarRepository, ICommonService commonService)
        {
            repository = sqlSugarRepository;
            dbClient = repository.Context;
            _commonService = commonService;
            currentUser = BaseInfoService.GetUserInfo();
        }

        /// <summary>
        /// 设备批量操作
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public async Task<ResultInfo> BatchSetAsync(DeviceBatchModel data)
        {
            //设备所属商户列表
            var busslist = await dbClient.Queryable<YB_Device>().Where(x => data.codes.Contains(x.Id) && x.BusinessId != 0).Select(x => x.BusinessId).ToListAsync();
            //分配
            if (data.type == 1)
            {
                busslist.Add(data.BusinessId);
                //如果是管理员分配,激活设备
                if (currentUser.AccountType == AccountType.platform)
                {
                    if (data.isactive == 1)
                    {
                        await dbClient.Updateable<YB_Device>().SetColumns(x => new YB_Device
                        {
                            BusinessId = data.BusinessId,
                            ActiveTime = DateTime.Now,
                            Status = DeviceStatus.Run
                        }).Where(x => data.codes.Contains(x.Id))
                         .EnableDiffLogEvent(new AduitLogS2SDto
                         {
                             Title = AuditOpConst.AllocDevice
                         })
                        .ExecuteCommandAsync();
                    }
                    else
                    {
                        await dbClient.Updateable<YB_Device>().SetColumns(x => new YB_Device
                        {
                            BusinessId = data.BusinessId
                        }).Where(x => data.codes.Contains(x.Id))
                        .EnableDiffLogEvent(new AduitLogS2SDto
                        {
                            Title = AuditOpConst.AllocDevice
                        })
                        .ExecuteCommandAsync();
                    }
                    //清理原先的记录
                    await dbClient.Deleteable<YB_DeviceAlloc>().Where(x => data.codes.Contains(x.EquId))
                        .EnableDiffLogEvent(new AduitLogS2SDto
                        {
                            Title = AuditOpConst.ClearAllocDevice
                        })
                        .ExecuteCommandAsync();
                    //增加分配记录
                    await _commonService.InsertAllocAsync(data.codes, currentUser.BusinessId, data.BusinessId, DeviceAllocType.ACTIVE);
                    await _commonService.InsertOrUpdateCombinedAsync();
                }
                else
                {
                    //检查设备已经有激活的情况,如果有则不可再分配
                    if (await dbClient.Queryable<YB_Device>().AnyAsync(x => x.Status == DeviceStatus.Run && data.codes.Contains(x.Id)))
                    {
                        return new ResultInfo(ResultState.FAIL, "有设备已激活不可再分配");
                    }
                    await dbClient.Updateable<YB_Device>().SetColumns(x => new YB_Device
                    {
                        BusinessId = data.BusinessId
                    }).Where(x => data.codes.Contains(x.Id))
                     .EnableDiffLogEvent(new AduitLogS2SDto
                     {
                         Title = AuditOpConst.AllocDevice
                     })
                    .ExecuteCommandAsync();
                    busslist.Add(currentUser.BusinessId);
                    //增加分配记录
                    await _commonService.InsertAllocAsync(data.codes, currentUser.BusinessId, data.BusinessId, DeviceAllocType.ALLOC);
                }
                await _commonService.InsertOrUpdateRealDataAsync(busslist);
                return new ResultInfo(ResultState.SUCCESS, "设备分配成功");
            }
            else
            {
                //如果是管理员回收
                if (currentUser.AccountType == AccountType.platform)
                {
                    await dbClient.Updateable<YB_Device>().SetColumns(x => new YB_Device
                    {
                        BusinessId = 0,
                        ActiveTime = null,
                        Status = DeviceStatus.UnActive,
                        Ecode = ""
                    }).Where(x => data.codes.Contains(x.Id))
                     .EnableDiffLogEvent(new AduitLogS2SDto
                     {
                         Title = AuditOpConst.RebackDevice
                     })
                    .ExecuteCommandAsync();

                    //清理原先的记录
                    await dbClient.Deleteable<YB_DeviceAlloc>().Where(x => data.codes.Contains(x.EquId))
                         .EnableDiffLogEvent(new AduitLogS2SDto
                         {
                             Title = AuditOpConst.ClearAllocDevice
                         })
                        .ExecuteCommandAsync();
                    //增加分配记录
                    await _commonService.InsertAllocAsync(data.codes, currentUser.BusinessId, data.BusinessId, DeviceAllocType.RETURN);
                    await _commonService.InsertOrUpdateCombinedAsync();
                }
                else
                {
                    await dbClient.Updateable<YB_Device>().SetColumns(x => new YB_Device
                    {
                        BusinessId = currentUser.BusinessId
                    }).Where(x => data.codes.Contains(x.Id))
                     .EnableDiffLogEvent(new AduitLogS2SDto
                     {
                         Title = AuditOpConst.RebackDevice
                     })
                    .ExecuteCommandAsync();
                    busslist.Add(currentUser.BusinessId);
                }
                await _commonService.InsertOrUpdateRealDataAsync(busslist);
                return new ResultInfo(ResultState.SUCCESS, "设备回收成功");
            }
        }
        /// <summary>
        /// 设备类型关联的小程序删除
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public async Task<ResultInfo> DeleteDeviceAppAsync(DeviceAppDeleteC2SDto data)
        {
            await dbClient.Deleteable<YB_DeviceTypeApp>().Where(x => x.Id == data.Id).ExecuteCommandAsync();
            return new ResultInfo(ResultState.SUCCESS, "删除成功");
        }

        /// <summary>
        /// 设备详情
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<YB_Device> DetailAsync(int id)
        {
            return await dbClient.Queryable<YB_Device>().FirstAsync(x => x.Id == id);
        }
        /// <summary>
        /// 查询设备分配记录
        /// </summary>
        /// <param name="id">设备ID</param>
        /// <returns></returns>
        public async Task<List<DeviceAllocListSCDto>> GetDeviceAllocListAsync(int id)
        {
            var alloclist = await dbClient.Queryable<YB_DeviceAlloc>().Where(x => x.EquId == id)
                .OrderBy(x=>x.CreateTime,OrderByType.Desc)
                .Select(x=>new DeviceAllocListS2SDto
                {
                    FromBusinessId = x.FromBusinessId,
                    ToBusinessId = x.ToBusinessId,
                    Time = x.CreateTime,
                    Type = x.Type
                })
                .Mapper((it, cache) =>
                {
                    var allbuss = cache.Get(list => {
                        var ids = new List<int>();
                        foreach(var item in list)
                        {
                            if (!ids.Contains(item.FromBusinessId))
                            {
                                ids.Add(item.FromBusinessId);
                            }
                            if (!ids.Contains(item.ToBusinessId))
                            {
                                ids.Add(item.ToBusinessId);
                            }
                        }
                        return dbClient.Queryable<YB_Business>().Where(x => ids.Contains(x.Id)).ToList();
                    });
                    var buss = allbuss.FirstOrDefault(x => x.Id == it.FromBusinessId);
                    it.FromBusiness = buss != null ? buss.Name : "";
                    buss = allbuss.FirstOrDefault(x => x.Id == it.ToBusinessId);
                    it.ToBusiness = buss != null ? buss.Name : "";
                })
                .ToListAsync();
            var list = alloclist.Adapt<List<DeviceAllocListSCDto>>();
            return list;
        }

        /// <summary>
        /// 设备类型关联的小程序详情
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<YB_DeviceTypeApp> GetDeviceAppAsync(Guid id)
        {
            return await dbClient.Queryable<YB_DeviceTypeApp>().FirstAsync(x => x.Id == id);
        }

        /// <summary>
        /// 设备类型关联的小程序列表
        /// </summary>
        /// <param name="param"></param>
        /// <returns></returns>
        public async Task<ResultInfo> GetDeviceAppListAsync(QueryParams param)
        {
            RefAsync<int> totalnum = 0;
            var temquery = dbClient.Queryable<YB_DeviceTypeApp>();
            if (param.queryParam != null && param.queryParam.Count > 0)
            {
                List<IConditionalModel> conModels = new List<IConditionalModel>();
                param.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);
                }
            }
            var query = await temquery.OrderBy(x => x.CreateTime, OrderByType.Desc)
                .Select(x => new DeviceAppListS2CDto
                {
                    Id = x.Id,
                    DevType = x.DevType,
                    AppId = x.AppId,
                    Status = x.Status
                })
                .Mapper((it, cache) =>
                {
                    var alloff = cache.Get(list =>
                    {
                        var ids = list.Select(x => x.AppId).ToList();
                        return dbClient.Queryable<YB_OfficlaAccount>().Where(x => ids.Contains(x.authorizer_appid)).ToList();
                    });
                    it.AppName = alloff.FirstOrDefault(x => x.authorizer_appid == it.AppId)?.nick_name;
                })
                .ToPageListAsync(param.offset, param.limit, totalnum);
            var result = new PageParms<DeviceAppListS2CDto>
            {
                page = param.offset,
                Items = query,
                totalnum = totalnum,
                limit = param.limit
            };
            return new ResultInfo(ResultState.SUCCESS, "success", result);
        }

        /// <summary>
        /// 设备列表
        /// </summary>
        /// <param name="param"></param>
        /// <returns></returns>
        public async Task<PageParms<DeviceListModel>> GetListAsync(QueryParams param)
        {
            RefAsync<int> totalnum = 0;
            var temquery = dbClient.Queryable<YB_Device>();
            if (param.queryParam != null && param.queryParam.Count > 0)
            {
                List<IConditionalModel> conModels = new List<IConditionalModel>();
                param.queryParam.ForEach(x =>
                {
                    if (!string.IsNullOrEmpty(x.Value))
                    {
                        conModels.Add(new ConditionalModel()
                        {
                            FieldName = x.Name,
                            ConditionalType = (ConditionalType)x.Type,
                            FieldValue = x.Value.ToStr()
                        });
                    }
                });
                if (conModels.Count > 0)
                {
                    temquery = temquery.Where(conModels);
                }
            }
            //非管理员可以查看名下所有级
            if (currentUser.AccountType != AccountType.platform)
            {
                temquery = temquery.Where(x => x.BusinessId == currentUser.BusinessId || x.BindBusinessId == currentUser.BusinessId || SqlFunc.Subqueryable<YB_DeviceAlloc>().Where(e => e.ToBusinessId == currentUser.BusinessId && e.EquId == x.Id).Any());
            }
            string sorts = string.Format("{0} {1}", param.sort, param.order);
            var query = await temquery.OrderBy(sorts)
                .Select(x => new DeviceListModel
                {
                    Id = x.Id,
                    Name = x.Name,
                    Ecode = x.Ecode,
                    ActiveTime = x.ActiveTime,
                    BusinessId = x.BusinessId,
                    CreateTime = x.CreateTime,
                    EndTime = x.EndTime,
                    FacCode = x.FacCode,
                    LastHeartTime = x.LastHeartTime,
                    Status = x.Status,
                    Type = x.Type
                })
                .Mapper((it, cache) =>
                {
                    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;
                    var alltype = 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 = alltype.FirstOrDefault(x => x.Code == it.Type)?.Name;

                    var allrealdata = cache.Get(list =>
                    {
                        var ids = list.Select(x => x.Id).ToList();
                        return dbClient.Queryable<YB_EquRealData>().Where(x => ids.Contains(x.EquId)).ToList();
                    });
                    var realdata = allrealdata.FirstOrDefault(x => x.BusinessId == it.BusinessId && x.EquId == it.Id);
                    it.todayresultcnt = realdata != null ? realdata.TodayResultCnt : 0;
                    it.totalresultcnt = realdata != null ? realdata.TotalResultCnt : 0;
                    it.time = it.LastHeartTime.HasValue && it.LastHeartTime.Value != SqlDateTime.MinValue.Value ? it.LastHeartTime.Value.ToYearDateTimes() : "-";
                })
                 .ToPageListAsync(param.offset, param.limit, totalnum);
            return new PageParms<DeviceListModel>
            {
                page = param.offset,
                Items = query,
                totalnum = totalnum,
                limit = param.limit
            };
        }
        /// <summary>
        /// 设备类型列表
        /// </summary>
        /// <returns></returns>
        public async Task<List<YB_DeviceType>> GetTypeListAsync()
        {
            return await dbClient.Queryable<YB_DeviceType>().ToListAsync();
        }
        /// <summary>
        /// 设备类型列表
        /// </summary>
        /// <param name="param"></param>
        /// <returns></returns>
        public async Task<PageParms<YB_DeviceType>> GetTypeListAsync(QueryParams param)
        {
            RefAsync<int> totalnum = 0;
            var temquery = dbClient.Queryable<YB_DeviceType>();
            if (param.queryParam != null && param.queryParam.Count > 0)
            {
                List<IConditionalModel> conModels = new List<IConditionalModel>();
                param.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);
                }
            }
            var query = await temquery.OrderBy(x => x.CreateTime, OrderByType.Desc)
                               .ToPageListAsync(param.offset, param.limit, totalnum);
            return new PageParms<YB_DeviceType>
            {
                page = param.offset,
                Items = query,
                totalnum = totalnum,
                limit = param.limit
            };
        }
        /// <summary>
        /// 设备停用
        /// </summary>
        /// <param name="id"></param>
        /// <param name="status">0-停用,1-启用</param>
        /// <returns></returns>
        public async Task<ResultInfo> StopDevAsync(int id, DeviceStatus status)
        {
            if (!await dbClient.Queryable<YB_Device>().AnyAsync(x => x.Id == id))
            {
                return new ResultInfo(ResultState.FAIL, "设备未找到");
            }
            await dbClient.Updateable<YB_Device>().SetColumns(x => new YB_Device
            {
                Status = status
            }).Where(x => x.Id == id)
             .EnableDiffLogEvent(new AduitLogS2SDto
             {
                 Title = AuditOpConst.DeviceStopOrStart
             })
            .ExecuteCommandAsync();
            string msg = status == 0 ? "设备已停用" : "设备已启用";
            return new ResultInfo(ResultState.SUCCESS, msg);
        }

        /// <summary>
        /// 信息编辑
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public async Task<ResultInfo> SubmitAsync(YB_Device model)
        {
            //if (string.IsNullOrEmpty(model.Ecode))
            //{
            //    return new ResultInfo(ResultState.FAIL, "机器码不可为空");
            //}
            if (string.IsNullOrEmpty(model.Name))
            {
                return new ResultInfo(ResultState.FAIL, "设备名称不可为空");
            }
            if (string.IsNullOrEmpty(model.FacCode))
            {
                return new ResultInfo(ResultState.FAIL, "序列号不可为空");
            }
            model.Remark = model.Remark.ToStr();
            model.Ecode = model.Ecode.ToStr();
            if (model.Id > 0)
            {
                //检查机器码是否已存在
                if (!model.Ecode.IsEmpty() && await dbClient.Queryable<YB_Device>().AnyAsync(x => x.Ecode == model.Ecode && x.Id != model.Id))
                {
                    return new ResultInfo(ResultState.FAIL, "机器码已存在");
                }
                //检查序列号是否已存在
                if (await dbClient.Queryable<YB_Device>().AnyAsync(x => x.FacCode == model.FacCode && x.Id != model.Id))
                {
                    return new ResultInfo(ResultState.FAIL, "序列号已存在");
                }
                //更新
                //如果是管理员可以修改机器码和序列号
                if (currentUser.AccountType != AccountType.platform)
                {
                    await dbClient.Updateable<YB_Device>().SetColumns(x => new YB_Device
                    {
                        Name = model.Name,
                        Remark = model.Remark
                    }).Where(x => x.Id == model.Id)
                    .EnableDiffLogEvent(new AduitLogS2SDto
                    { 
                        Title= AuditOpConst.UpdateDevInfo
                    })
                    .ExecuteCommandAsync();
                }
                else
                {
                    await dbClient.Updateable<YB_Device>().SetColumns(x => new YB_Device
                    {
                        FacCode = model.FacCode,
                        Ecode = model.Ecode,
                        Name = model.Name,
                        Remark = model.Remark,
                        Type = model.Type
                    }).Where(x => x.Id == model.Id)
                    .EnableDiffLogEvent(new AduitLogS2SDto
                    {
                        Title = AuditOpConst.UpdateDevInfo
                    })
                    .ExecuteCommandAsync();
                }
                return new ResultInfo(ResultState.SUCCESS, "更新成功");
            }
            else
            {
                //检查机器码是否已存在
                if (!model.Ecode.IsEmpty() && await dbClient.Queryable<YB_Device>().AnyAsync(x => x.Ecode == model.Ecode))
                {
                    return new ResultInfo(ResultState.FAIL, "机器码已存在");
                }
                //检查序列号是否已存在
                if (await dbClient.Queryable<YB_Device>().AnyAsync(x => x.FacCode == model.FacCode))
                {
                    return new ResultInfo(ResultState.FAIL, "序列号已存在");
                }
                model.Status = DeviceStatus.UnActive;
                model.CreateTime = DateTime.Now;
                model.ActiveTime = null;
                model.BusinessId = 0;
                model.LastHeartTime = null;
                model.EndTime = null;
                await dbClient.Insertable<YB_Device>(model)
                     .EnableDiffLogEvent(new AduitLogS2SDto
                     {
                         Title = AuditOpConst.AddDevice
                     })
                    .ExecuteCommandAsync();
                //更新汇总表
                await _commonService.InsertOrUpdateCombinedAsync();
                return new ResultInfo(ResultState.SUCCESS, "添加成功");
            }
        }
        /// <summary>
        /// 设备类型关联的小程序提交
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public async Task<ResultInfo> SubmitDeviceAppAsync(DeviceAppC2SDto data)
        {
            if (data.Id != Guid.Empty)
            {
                if (await dbClient.Queryable<YB_DeviceTypeApp>().AnyAsync(x => x.AppId == data.AppId && x.Id != data.Id))
                {
                    return new ResultInfo(ResultState.FAIL, "此小程序已配置");
                }
                await dbClient.Updateable<YB_DeviceTypeApp>().SetColumns(x => new YB_DeviceTypeApp
                {
                    DevType = data.DevType,
                    AppId = data.AppId
                }).Where(x => x.Id == data.Id)
                 .EnableDiffLogEvent(new AduitLogS2SDto
                 {
                     Title = AuditOpConst.UpdateDeviceTypeApp
                 })
                .ExecuteCommandAsync();
                return new ResultInfo(ResultState.SUCCESS, "修改成功");
            }
            else
            {
                if (await dbClient.Queryable<YB_DeviceTypeApp>().AnyAsync(x => x.AppId == data.AppId))
                {
                    return new ResultInfo(ResultState.FAIL, "此设备类型已配置");
                }
                var insertdata = new YB_DeviceTypeApp
                {
                    DevType = data.DevType,
                    Status = StatusType.Enabled,
                    AppId = data.AppId,
                    CreateTime = DateTime.Now,
                    Id = IDGen.NextID()
                };
                await dbClient.Insertable(insertdata)
                     .EnableDiffLogEvent(new AduitLogS2SDto
                     {
                         Title = AuditOpConst.AddDeviceTypeApp
                     })
                    .ExecuteCommandAsync();
                return new ResultInfo(ResultState.SUCCESS, "添加成功");
            }
        }

        /// <summary>
        /// 信息编辑
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public async Task<ResultInfo> SubmitTypeAsync(YB_DeviceType model)
        {
            if (string.IsNullOrEmpty(model.Name))
            {
                return new ResultInfo(ResultState.FAIL, "名称不可为空");
            }
            model.Remark = model.Remark.ToStr();
            model.HeadImg = model.HeadImg.ToStr();
            model.ExtName = model.ExtName.ToStr();
            if (model.Id > 0)
            {
                //检查此类型编号是否已存在
                if (await dbClient.Queryable<YB_DeviceType>().AnyAsync(x => x.Code == model.Code && x.Id != model.Id))
                {
                    return new ResultInfo(ResultState.FAIL, "此类型已存在");
                }
                await dbClient.Updateable<YB_DeviceType>().SetColumns(x => new YB_DeviceType
                {
                    Name = model.Name,
                    Code = model.Code,
                    ProType = model.ProType,
                    VerType = model.VerType,
                    Remark = model.Remark,
                    HeadImg = model.HeadImg,
                    Content = model.Content,
                    ExtName = model.ExtName
                }).Where(x => x.Id == model.Id)
                 .EnableDiffLogEvent(new AduitLogS2SDto
                 {
                     Title = AuditOpConst.UpdateDeviceType
                 })
                .ExecuteCommandAsync();
                return new ResultInfo(ResultState.SUCCESS, "更新成功");
            }
            else
            {
                //检查此类型编号是否已存在
                if (await dbClient.Queryable<YB_DeviceType>().AnyAsync(x => x.Code == model.Code))
                {
                    return new ResultInfo(ResultState.FAIL, "此类型已存在");
                }
                await dbClient.Insertable(model)
                     .EnableDiffLogEvent(new AduitLogS2SDto
                     {
                         Title = AuditOpConst.AddDeviceType
                     })
                    .ExecuteCommandAsync();
                return new ResultInfo(ResultState.SUCCESS, "添加成功");
            }
        }
        /// <summary>
        /// 设备类型详情
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<YB_DeviceType> TypeDetailAsync(int id)
        {
            return await dbClient.Queryable<YB_DeviceType>().Where(x => x.Id == id).FirstAsync();
        }
    }
}
