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

namespace Waste.Application
{
    /// <summary>
    /// 统计管理
    /// </summary>
    public class ReportService : BaseInfoService, IReportService, ITransient
    {
        private readonly ISqlSugarRepository<W_DeviceStatistics> repository;
        private readonly SqlSugarClient dbClient;

        public ReportService(ISqlSugarRepository<W_DeviceStatistics> sqlSugarRepository)
        {
            repository = sqlSugarRepository;
            dbClient = repository.Context;
        }
        /// <summary>
        /// 获取一定时间段内的统计数据,第三方接口对接使用
        /// </summary>
        /// <param name="param"></param>
        /// <param name="appid">第三方授权的appid</param>
        /// <returns></returns>
        public async Task<ResultInfo> GetDataAsync(ApiReportRequestData param, string appid)
        {
            if (string.IsNullOrEmpty(appid))
            {
                return new ResultInfo(ApiResultState.NOAPPID, "缺少appid参数");
            }
            //根据appid获取商户信息
            var bussapi = await repository.Change<W_BusinessAppApi>().FirstOrDefaultAsync(x => x.AppId == appid);
            if (bussapi == null)
            {
                return new ResultInfo(ApiResultState.NONAPPID, "appid无效");
            }
            //检查参数
            if (param.enddate > DateTime.Now.Date.AddDays(-1))
            {
                return new ResultInfo(ApiResultState.PARAMERROR, "时间不可大于昨日");
            }
            if (param.enddate < param.begindate)
            {
                return new ResultInfo(ApiResultState.PARAMERROR, "结束时间不可小于开始时间");
            }
            if (param.begindate < param.enddate.AddDays(-7))
            {
                return new ResultInfo(ApiResultState.PARAMERROR, "时间跨度最多是七日");
            }
            if (param.begindate < DateTime.Now.AddMonths(-6))
            {
                return new ResultInfo(ApiResultState.PARAMERROR, "超过半年的数据无法进行查询");
            }
            var tempquery = dbClient.Queryable<W_DeviceStatistics>();
            tempquery = tempquery.Where(x => x.Businessid == bussapi.Id);
            int totalcount = await tempquery.Clone().CountAsync();
            if (totalcount == 0)
            {
                return new ResultInfo(ApiResultState.NODATA, "无可用数据");
            }
            List<ApiReportBaseData> data = new List<ApiReportBaseData>();
            var list = await tempquery
                .Clone()
                .OrderBy(x => x.CreateTime, OrderByType.Asc)
                .Select(x => new ApiReportBaseDataItem
                {
                    Id = x.Id,
                    CreateTime = x.CreateTime,
                    DevId = x.DevId,
                    DayCount = x.DayCount,
                    DayPureWeight = x.DayPureWeight,
                    DayWeight = x.DayWeight,
                    WasteType = x.WasteType
                })
                .Mapper((it, cache) =>
                {
                    var alldev = cache.Get(list =>
                    {
                        List<Guid> ids = list.Select(x => x.DevId).ToList();
                        List<Guid> newids = ids.IDistinctList();
                        return repository.Change<W_Device>().Context.Queryable<W_Device>().Where(x => newids.Contains(x.Id)).ToList();
                    });
                    var allarea = cache.Get(list =>
                    {
                        var provinces = alldev.Select(x => x.Province).ToList();
                        var citys = alldev.Select(x => x.City).ToList();
                        var areas = alldev.Select(x => x.Area).ToList();
                        provinces = provinces.IDistinctList();
                        citys = citys.IDistinctList();
                        areas = areas.IDistinctList();
                        return repository.Change<W_AreaInfo>().Where(x => provinces.Contains(x.code) || citys.Contains(x.code) || areas.Contains(x.code)).ToList();
                    });
                    var dev = alldev.FirstOrDefault(x => x.Id == it.DevId);
                    if (dev != null)
                    {
                        it.devname = dev.Name;
                        it.devcode = dev.Ecode;

                        var Province = allarea.FirstOrDefault(x => x.code == dev.Province);
                        var City = allarea.FirstOrDefault(x => x.code == dev.City);
                        var Area = allarea.FirstOrDefault(x => x.code == dev.Area);
                        it.address = $"{(Province != null ? Province.name.ToStr() : "")}{(City != null ? City.name.ToStr() : "")}{(Area != null ? Area.name.ToStr() : "")}";
                    }
                    var dto = it.Adapt<ApiReportBaseData>();
                    data.Add(dto);
                })
                .ToListAsync();
            var returndata = new ApiReportBaseData<ApiReportBaseData>()
            {
                list = data,
                totalcount = totalcount
            };
            return new ResultInfo(ResultState.SUCCESS, "success", returndata);
        }

        /// <summary>
        /// 统计列表
        /// </summary>
        /// <param name="param"></param>
        /// <returns></returns>
        public async Task<PageParms<ReportList>> GetListAsync(QueryParams param)
        {
            RefAsync<int> totalnum = 0;
            var temquery = dbClient.Queryable<W_DeviceStatistics>();
            if (param.queryParam != null && param.queryParam.Count > 0)
            {
                List<IConditionalModel> conModels = new List<IConditionalModel>();
                param.queryParam.ForEach(x =>
                {
                    x.Value = x.Value.ToStr();
                    if (!string.IsNullOrEmpty(x.Value))
                    {
                        if (x.Name.ToLower() == "devname")
                        {
                            temquery = temquery.Where(e => SqlFunc.Subqueryable<W_Device>().Where(w => w.Name == x.Value && e.DevId == w.Id).Any());
                        }
                        else
                        {
                            conModels.Add(new ConditionalModel()
                            {
                                FieldName = x.Name,
                                ConditionalType = (ConditionalType)x.Type,
                                FieldValue = x.Value.Trim()
                            });
                        }
                    }
                });
                if (conModels.Count > 0)
                {
                    temquery = temquery.Where(conModels);
                }
            }
            //针对非平台类型,则可以查看下面所有的子账户设备
            if (currentUser.AccountType != (int)AccountType.platform)
            {
                var sql = $"code like '{currentUser.BusinessCode}'+'%' and id = x.businessid";
                temquery = temquery.Where(x => SqlFunc.Subqueryable<W_Business>().Where(sql).Any());
            }
            int totaldaycount = await temquery.Clone().SumAsync(x => x.DayCount);
            decimal totaldaypureweight = await temquery.Clone().SumAsync(x => x.DayPureWeight);
            decimal totaldayweight = await temquery.Clone().SumAsync(x => x.DayWeight);
            string sorts = string.Format("{0} {1}", param.sort, param.order);
            var query = await temquery.OrderBy(sorts)
                .Select(x => new ReportList
                {
                    Id = x.Id,
                    Businessid = x.Businessid,
                    DevId = x.DevId,
                    CreateTime = x.CreateTime,
                    DayCount = x.DayCount,
                    DayPureWeight = x.DayPureWeight,
                    DayWeight = x.DayWeight,
                    WasteType = x.WasteType
                })
                .Mapper((it, cache) =>
                {
                    var allbus = cache.Get(list =>
                    {
                        var ids = list.Where(x => x.Businessid != Guid.Empty).Select(x => x.Businessid).ToList();
                        return repository.Change<W_Business>().Context.Queryable<W_Business>().Where(e => ids.Contains(e.Id)).ToList();
                    });
                    var bus = allbus.FirstOrDefault(x => x.Id == it.Businessid);
                    it.BusinessName = bus != null ? bus.Name : "";
                    var alldev = cache.Get(list =>
                    {
                        var ids = list.Where(x => x.DevId != Guid.Empty).Select(x => x.DevId).ToList();
                        return repository.Change<W_Device>().Context.Queryable<W_Device>().Where(e => ids.Contains(e.Id)).ToList();
                    });
                    var dev = alldev.FirstOrDefault(x => x.Id == it.DevId);
                    it.DevName = dev != null ? dev.Name : "";
                    it.DevCode = dev != null ? dev.Ecode : "";
                    it.DevAddress = dev != null ? dev.Address : "";
                    it.TotalDayCount = totaldaycount;
                    it.TotalDayPureWeight = totaldaypureweight;
                    it.TotalDayWeight = totaldayweight;
                })
                 .ToPageListAsync(param.offset, param.limit, totalnum);
            return new PageParms<ReportList>
            {
                page = param.offset,
                Items = query,
                totalnum = totalnum,
                limit = param.limit
            };
        }
        /// <summary>
        /// 根据商户和垃圾类型进行汇总
        /// </summary>
        /// <param name="param"></param>
        /// <returns></returns>
        public async Task<PageParms<ReportList>> GetListByBusinessAsync(QueryParams param)
        {
            RefAsync<int> totalnum = 0;
            var temquery = repository.Change<W_BusinessStatistics>().Context.Queryable<W_BusinessStatistics>();
            if (param.queryParam != null && param.queryParam.Count > 0)
            {
                List<IConditionalModel> conModels = new List<IConditionalModel>();
                param.queryParam.ForEach(x =>
                {
                    x.Value = x.Value.ToStr();
                    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);
                }
            }
            //针对非平台类型,则可以查看下面所有的子账户设备
            if (currentUser.AccountType != (int)AccountType.platform)
            {
                var sql = $"code like '{currentUser.BusinessCode}'+'%' and id = x.businessid";
                temquery = temquery.Where(x => SqlFunc.Subqueryable<W_Business>().Where(sql).Any());
            }
            int totaldaycount = await temquery.Clone().SumAsync(x => x.DayCount);
            decimal totaldaypureweight = await temquery.Clone().SumAsync(x => x.DayPureWeight);
            decimal totaldayweight = await temquery.Clone().SumAsync(x => x.DayWeight);
            string sorts = string.Format("{0} {1}", param.sort, param.order);
            var query = await temquery.Clone().OrderBy(sorts)
                .Select(x => new ReportList
                {
                    Businessid = x.BusinessId,
                    CreateTime = x.CreateTime,
                    DayCount = x.DayCount,
                    DayPureWeight = x.DayPureWeight,
                    DayWeight = x.DayWeight,
                    WasteType = x.WasteType
                })
                .Mapper((it, cache) =>
                {
                    var allbus = cache.Get(list =>
                    {
                        var ids = list.Where(x => x.Businessid != Guid.Empty).Select(x => x.Businessid).ToList();
                        return repository.Change<W_Business>().Context.Queryable<W_Business>().Where(e => ids.Contains(e.Id)).ToList();
                    });
                    var bus = allbus.FirstOrDefault(x => x.Id == it.Businessid);
                    it.BusinessName = bus != null ? bus.Name : "";
                    it.TotalDayCount = totaldaycount;
                    it.TotalDayPureWeight = totaldaypureweight;
                    it.TotalDayWeight = totaldayweight;
                })
                 .ToPageListAsync(param.offset, param.limit, totalnum);
            return new PageParms<ReportList>
            {
                page = param.offset,
                Items = query,
                totalnum = totalnum,
                limit = param.limit
            };
        }
    }
}
