using Furion.DependencyInjection;
using Furion.DistributedIDGenerator;
using Furion.DynamicApiController;
using Microsoft.AspNetCore.Mvc;
using Nirvana.Common;
using Nirvana.Common.ApiBase;
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 BusinessService : BaseInfoService, IBusinessService, ITransient
    {
        private readonly ISqlSugarRepository<W_Business> repository;
        private readonly SqlSugarClient dbClient;

        public BusinessService(ISqlSugarRepository<W_Business> sqlSugarRepository)
        {
            repository = sqlSugarRepository;
            dbClient = repository.Context;
        }
        /// <summary>
        /// 删除商户
        /// </summary>
        /// <param name="keyValue"></param>
        /// <returns></returns>
        public Task<ResultInfo> DeleteFormAsync(Guid keyValue)
        {
            throw new NotImplementedException();
        }
        /// <summary>
        /// 详情
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<BusinessInfo> DetailAsync(Guid id)
        {
            var buss = await dbClient.Queryable<W_Business>().Select(x => new W_Business
            {
                Name = x.Name,
                Address = x.Address,
                Area = x.Area,
                City = x.City,
                Phone = x.Phone,
                Province = x.Province,
                Id = x.Id,
                Remark = x.Remark
            }).Where(x => x.Id == id).FirstAsync();
            var user = await repository.Change<W_Account>().Context.Queryable<W_Account>().FirstAsync(x => x.BusinessId == buss.Id);
            return new BusinessInfo
            {
                AccountType = user.AccountType,
                Name = buss.Name,
                Address = buss.Address,
                Area = buss.Area,
                City = buss.City,
                Phone = buss.Phone,
                Province = buss.Province,
                Remark = buss.Remark,
                Id = buss.Id
            };
        }
        /// <summary>
        /// 获取所有商户
        /// </summary>
        /// <returns></returns>
        public async Task<List<W_Business>> GetAllList(int status = -1)
        {
            var tempquery = dbClient.Queryable<W_Business>();
            if (status >= 0)
            {
                tempquery = tempquery.Where(x => x.Status == status);
            }
            if (currentUser.AccountType != (int)AccountType.platform)
            {
                var sql = $"code like '{currentUser.BusinessCode}'+'%'";
                tempquery = tempquery.Where(sql);
            }
            else
            {
                tempquery = tempquery.Where(x => SqlFunc.Subqueryable<W_Account>().Where(e => e.AccountType == 1 && e.BusinessId == x.Id).Any());
            }
            return await tempquery.ToListAsync();
        }

        /// <summary>
        /// 商户列表
        /// </summary>
        /// <param name="param"></param>
        /// <param name="noadmin">是否包含管理员,true-不包含,false-包含</param>
        /// <returns></returns>
        public async Task<PageParms<BusinessList>> GetListAsync(QueryParams param, bool noadmin = false)
        {
            RefAsync<int> totalnum = 0;
            var temquery = dbClient.Queryable<W_Business>();
            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);
                }
            }
            if (noadmin)
            {
                temquery = temquery.Where(x => SqlFunc.Subqueryable<W_Account>().Where(e => e.AccountType == 1 && e.BusinessId == x.Id).Any());
            }
            //针对非平台类型,则可以查看下面所有的子账户设备
            if (currentUser.AccountType != (int)AccountType.platform)
            {
                var sql = $" code !='{currentUser.BusinessCode}' and code like '{currentUser.BusinessCode}%' and id = x.id";
                temquery = temquery.Where(x => SqlFunc.Subqueryable<W_Business>().Where(sql).Any());
            }
            string sorts = string.Format("{0} {1}", param.sort, param.order);
            var query = await temquery.OrderBy(sorts)
                .Select(x => new BusinessList
                {
                    Id = x.Id,
                    Address = x.Address,
                    CreateTime = x.CreateTime,
                    Status = x.Status,
                    Name = x.Name,
                    Phone = x.Phone
                })
                .Mapper((it, cache) =>
                {
                    if (!noadmin)
                    {
                        var allrealdata = cache.Get(list =>
                        {
                            var ids = list.Select(x => x.Id).ToList();
                            return repository.Change<W_BusinessRealData>().Context.Queryable<W_BusinessRealData>().Where(x => ids.Contains(x.BusinessId)).ToList();
                        });
                        var realdata = allrealdata.FirstOrDefault(x => x.BusinessId == it.Id);
                        if (realdata != null)
                        {
                            it.BusinessCnt = realdata.BusinessCnt;
                            it.DevCnt = realdata.DevCnt;
                            it.TodayDevActiveCnt = realdata.TodayDevActiveCnt;
                            it.TodayCount = realdata.TodayCount;
                            it.TodayWeight = realdata.TodayWeight;
                            it.TodayPureWeight = realdata.TodayPureWeight;
                            it.TotalCount = realdata.TotalCount;
                            it.TotalWeight = realdata.TotalWeight;
                            it.TotalPureWeight = realdata.TotalPureWeight;
                        }
                    }
                })
                 .ToPageListAsync(param.offset, param.limit, totalnum);
            return new PageParms<BusinessList>
            {
                page = param.offset,
                Items = query,
                totalnum = totalnum,
                limit = param.limit
            };
        }
        /// <summary>
        /// 重置密码
        /// </summary>
        /// <param name="id"></param>
        /// <param name="pwd"></param>
        /// <returns></returns>
        public async Task<ResultInfo> ResetPwdAsync(Guid id, string pwd)
        {
            if (string.IsNullOrEmpty(pwd))
            {
                pwd = "123456";
            }
            if (!await dbClient.Queryable<W_Business>().AnyAsync(x => x.Id == id))
            {
                return new ResultInfo(ResultState.FAIL, "此商户未找到");
            }
            if (!await repository.Change<W_Account>().Context.Queryable<W_Account>().AnyAsync(x => x.BusinessId == id))
            {
                return new ResultInfo(ResultState.FAIL, "账户未找到");
            }
            var Secret = Md5.md5(Common.CreateNo(), 16).ToLower();
            var Password = Md5.md5(DESEncrypt.Encrypt(Md5.md5(pwd, 32).ToLower(), Secret).ToLower(), 32).ToLower();
            await repository.Change<W_Account>().Context.Updateable<W_Account>().SetColumns(x => new W_Account
            {
                Secret = Secret,
                Password = Password
            }).Where(x => x.BusinessId == id).ExecuteCommandAsync();
            return new ResultInfo(ResultState.SUCCESS, "密码重置成功");
        }
        /// <summary>
        /// 修改密码
        /// </summary>
        /// <param name="busienssPwd"></param>
        /// <returns></returns>
        public async Task<ResultInfo> ChangePwdAsync(BusienssPwd busienssPwd)
        {
            if (busienssPwd.NewPwd != busienssPwd.ReNewPwd)
            {
                return new ResultInfo(ResultState.FAIL, "两次密码不一致");
            }
            var account = await repository.Change<W_Account>().Context.Queryable<W_Account>().FirstAsync(x => x.Id == currentUser.UserId);
            if (account == null)
            {
                return new ResultInfo(ResultState.FAIL, "账户未找到");
            }
            var oldpassword = Md5.md5(DESEncrypt.Encrypt(Md5.md5(busienssPwd.OldPwd, 32).ToLower(), account.Secret).ToLower(), 32).ToLower();
            if (oldpassword != account.Password)
            {
                return new ResultInfo(ResultState.FAIL, "旧密码错误");
            }
            var newpassword = Md5.md5(DESEncrypt.Encrypt(Md5.md5(busienssPwd.NewPwd, 32).ToLower(), account.Secret).ToLower(), 32).ToLower();
            await dbClient.Updateable<W_Account>().SetColumns(x => new W_Account
            {
                Password = newpassword
            }).Where(x => x.Id == account.Id).ExecuteCommandAsync();
            return new ResultInfo(ResultState.SUCCESS, "密码修改成功");
        }

        /// <summary>
        /// 信息提交
        /// </summary>
        /// <param name="buss"></param>
        /// <returns></returns>
        public async Task<ResultInfo> SubmitFormAsync(BusinessInfo buss)
        {
            buss.Province = buss.Province.ToStr();
            buss.City = buss.City.ToStr();
            buss.Area = buss.Area.ToStr();
            buss.Remark = buss.Remark.ToStr();
            buss.Phone = buss.Phone.ToStr();
            buss.Name = buss.Name.ToStr();
            buss.Address = buss.Address.ToStr();
            if (buss.AccountType <= 0 || buss.AccountType != (int)AccountType.platform)
            {
                buss.AccountType = (int)AccountType.agent;
            }
            Guid roleid = Guid.Parse("39FC70AA-652F-CE76-98A8-5C32D6E5D619");
            if (buss.AccountType == (int)AccountType.platform)
            {
                roleid = Guid.Parse("39FC70AA-1CDA-B9CD-5275-3D144841BEDD");
            }
            if (buss.Id != Guid.Empty)
            {
                if (await dbClient.Queryable<W_Business>().AnyAsync(x => x.Phone == buss.Phone && x.Id != buss.Id))
                {
                    return new ResultInfo() { code = ResultState.FAIL, message = "手机号已注册!" };
                }
                if (await dbClient.Queryable<W_Account>().AnyAsync(x => x.Phone == buss.Phone && x.BusinessId != buss.Id))
                {
                    return new ResultInfo() { code = ResultState.FAIL, message = "手机号已注册!" };
                }
                if (!await dbClient.Queryable<W_Business>().AnyAsync(x => x.Id == buss.Id))
                {
                    return new ResultInfo() { code = ResultState.FAIL, message = "商户未找到!" };
                }
                await dbClient.Updateable<W_Business>().SetColumns(x => new W_Business
                {
                    Address = buss.Address,
                    Phone = buss.Phone,
                    Name = buss.Name,
                    Area = buss.Area,
                    City = buss.City,
                    Province = buss.Province,
                    Remark = buss.Remark
                }).Where(x => x.Id == buss.Id).ExecuteCommandAsync();
                //更新登录账户,如果手机号有变动,则登录账户也变动
                if (currentUser.AccountType != (int)AccountType.platform)
                {
                    await dbClient.Updateable<W_Account>().SetColumns(x => new W_Account
                    {
                        Phone = buss.Phone,
                        RealName = buss.Name,
                        UserName = buss.Phone
                    }).Where(x => x.BusinessId == buss.Id).ExecuteCommandAsync();
                }
                else
                {
                    await dbClient.Updateable<W_Account>().SetColumns(x => new W_Account
                    {
                        Phone = buss.Phone,
                        RealName = buss.Name,
                        UserName = buss.Phone,
                        AccountType = buss.AccountType,
                        RoleId = roleid
                    }).Where(x => x.BusinessId == buss.Id).ExecuteCommandAsync();
                }

                return new ResultInfo(ResultState.SUCCESS, "修改成功");
            }
            else
            {
                if (await dbClient.Queryable<W_Business>().AnyAsync(x => x.Phone == buss.Phone))
                {
                    return new ResultInfo() { code = ResultState.FAIL, message = "手机号已注册!" };
                }
                if (await repository.Change<W_Account>().Context.Queryable<W_Account>().AnyAsync(x => x.Phone == buss.Phone))
                {
                    return new ResultInfo() { code = ResultState.FAIL, message = "手机号已注册!" };
                }
                Guid parentid = Guid.Empty;
                string code = "";
                if (currentUser.AccountType != (int)AccountType.platform)
                {
                    parentid = currentUser.BusinessId;
                    var bcode = currentUser.BusinessCode;
                    var len = bcode.Length;
                    int  cnt = await dbClient.Queryable<W_Business>().Where(x => x.ParentId == parentid).CountAsync();
                    code = GenCode(bcode, cnt);
                }
                else
                {
                    var cnt = (await dbClient.Queryable<W_Business>().Where(x => SqlFunc.Length(x.Code) == 4).MaxAsync(x => x.Code)).ToInt();
                    code = GenCode("", cnt);
                }
                var business = new W_Business
                {
                    ParentId = parentid,
                    Code = code,
                    CreateTime = DateTime.Now,
                    Status = (int)StatusType.Enabled,
                    Address = buss.Address,
                    Area = buss.Area,
                    City = buss.City,
                    Name = buss.Name,
                    Phone = buss.Phone,
                    Province = buss.Province,
                    Remark = buss.Remark,
                    Id = IDGen.NextID()
                };
                await dbClient.Insertable<W_Business>(business).ExecuteCommandAsync();
                //添加登录账户
                if (string.IsNullOrEmpty(buss.Password))
                {
                    buss.Password = buss.Phone;
                }
                var UserSecretKey = Md5.md5(Common.CreateNo(), 16).ToLower();
                var Password = Md5.md5(DESEncrypt.Encrypt(Md5.md5(buss.Password, 32).ToLower(), UserSecretKey).ToLower(), 32).ToLower();
                await dbClient.Insertable<W_Account>(new W_Account
                {
                    UserName = buss.Phone,
                    RealName = buss.Name,
                    Secret = UserSecretKey,
                    BusinessId = business.Id,
                    Password = Password,
                    AccountType = buss.AccountType,
                    CreateTime = DateTime.Now,
                    Id = business.Id,
                    LastVisitIP = "",
                    Status = (int)StatusType.Enabled,
                    LastVisitTime = null,
                    Phone = buss.Phone,
                    RoleId = roleid
                }).ExecuteCommandAsync();
                //插入或者更新实时数据
                await InsertOrUpdateRealDataAsync();
                if (currentUser.AccountType != (int)AccountType.platform)
                {
                    await InsertOrUpdateRealDataAsync(currentUser.BusinessId);
                }
                return new ResultInfo(ResultState.SUCCESS, "添加成功");
            }
        }
        /// <summary>
        /// 生成用户code
        /// </summary>
        /// <param name="code">当前用户的code</param>
        /// <param name="cnt">名下用户数量</param>
        /// <returns></returns>
        private string GenCode(string code, int cnt)
        {
            var ccode = "0001";
            if (cnt < 9)
            {
                ccode = $"000{cnt + 1}";
            }
            else if (cnt >= 9 && cnt < 99)
            {
                ccode = $"00{cnt + 1}";
            }
            else if (cnt >= 99 && cnt < 999)
            {
                ccode = $"0{cnt + 1}";
            }
            else
            {
                ccode = $"{cnt + 1}";
            }
            if (!string.IsNullOrEmpty(code))
            {
                return $"{code}{ccode}";
            }
            return ccode;
        }
        /// <summary>
        /// 更新或者插入实时数据
        /// </summary>
        /// <returns></returns>
        public async Task InsertOrUpdateRealDataAsync()
        {
            //更新总体数据
            var tdbClient = repository.Change<W_RealData>().Context;
            int busiensscnt = await repository.Change<W_Business>().Context.Queryable<W_Business>().CountAsync();
            int devcnt = await dbClient.Queryable<W_Device>().CountAsync();
            int todaydevactivecnt = await dbClient.Queryable<W_Device>().Where(x => SqlFunc.DateIsSame(x.LastHeartTime, DateTime.Now)).CountAsync();
            var data = await tdbClient.Queryable<W_RealData>().FirstAsync();
            if (data == null)
            {
                var realdata = new W_RealData
                {
                    Id = IDGen.NextID(),
                    BusinessCnt = busiensscnt,
                    DevCnt = devcnt,
                    TodayCount = 0,
                    TodayDevActiveCnt = todaydevactivecnt,
                    TodayPureWeight = 0,
                    TodayWeight = 0,
                    TotalCount = 0,
                    TotalPureWeight = 0,
                    TotalWeight = 0
                };
                await tdbClient.Insertable<W_RealData>(realdata).ExecuteCommandAsync();
            }
            else
            {
                await tdbClient.Updateable<W_RealData>().SetColumns(x => new W_RealData
                {
                    DevCnt = devcnt,
                    BusinessCnt = busiensscnt,
                    TodayDevActiveCnt = todaydevactivecnt
                }).Where(x => x.Id == data.Id).ExecuteCommandAsync();
            }
        }
        /// <summary>
        /// 更新或者插入指定商户实时数据
        /// </summary>
        /// <returns></returns>
        public async Task InsertOrUpdateRealDataAsync(Guid BusinessId)
        {
            if (BusinessId != Guid.Empty)
            {
                var tdbClient = repository.Change<W_BusinessRealData>().Context;
                int todaydevactivecnt = await dbClient.Queryable<W_Device>().Where(x => x.Businessid == BusinessId && SqlFunc.DateIsSame(x.LastHeartTime, DateTime.Now)).CountAsync();
                int devcnt = await repository.Change<W_Device>().Context.Queryable<W_Device>().Where(x => x.Businessid == BusinessId).CountAsync();
                int businesscnt = await dbClient.Queryable<W_Business>().Where(x => x.ParentId == BusinessId).CountAsync();
                if (!await tdbClient.Queryable<W_BusinessRealData>().AnyAsync(x => x.BusinessId == BusinessId))
                {
                    var realdata = new W_BusinessRealData
                    {
                        TodayDevActiveCnt = todaydevactivecnt,
                        DevCnt = devcnt,
                        BusinessId = BusinessId,
                        Id = IDGen.NextID(),
                        TodayCount = 0,
                        TodayPureWeight = 0,
                        TodayWeight = 0,
                        TotalCount = 0,
                        TotalPureWeight = 0,
                        TotalWeight = 0,
                        BusinessCnt = businesscnt
                    };
                    await tdbClient.Insertable<W_BusinessRealData>(realdata).ExecuteCommandAsync();
                }
                else
                {
                    await tdbClient.Updateable<W_BusinessRealData>().SetColumns(x => new W_BusinessRealData
                    {
                        DevCnt = devcnt,
                        TodayDevActiveCnt = todaydevactivecnt,
                        BusinessCnt = businesscnt
                    }).Where(x => x.BusinessId == BusinessId).ExecuteCommandAsync();
                }
            }
        }
        /// <summary>
        /// 更新或者插入指定商户实时数据
        /// </summary>
        /// <returns></returns>
        public async Task InsertOrUpdateRealDataAsync(List<Guid> BusinessId)
        {
            if (BusinessId != null && BusinessId.Count > 0)
            {
                foreach (var item in BusinessId)
                {
                    await InsertOrUpdateRealDataAsync(item);
                }
            }
        }
        /// <summary>
        /// 获取账户统计信息
        /// </summary>
        /// <returns></returns>
        public async Task<W_RealData> GetTotalInfoAsync()
        {
            if (currentUser.AccountType != (int)AccountType.platform)
            {
                var data = await repository.Change<W_BusinessRealData>().Context.Queryable<W_BusinessRealData>().FirstAsync(x => x.BusinessId == currentUser.BusinessId);
                if (data == null)
                    return null;
                return new W_RealData
                {
                    DevCnt = data.DevCnt,
                    TodayDevActiveCnt = data.TodayDevActiveCnt,
                    BusinessCnt = 0,
                    TodayCount = data.TodayCount,
                    TodayPureWeight = data.TodayPureWeight,
                    TodayWeight = data.TodayWeight,
                    TotalCount = data.TotalCount,
                    TotalPureWeight = data.TotalPureWeight,
                    TotalWeight = data.TotalWeight
                };
            }
            else
            {
                var data = await repository.Change<W_RealData>().Context.Queryable<W_RealData>().FirstAsync();
                return data;
            }
        }
        /// <summary>
        /// 获取商户的昨天汇总信息
        /// </summary>
        /// <returns></returns>
        public async Task<BusinessReport> GetBusinessTotalInfo()
        {
            DateTime yestodaytime = DateTime.Now.AddDays(-1);
            if (currentUser.AccountType != (int)AccountType.platform)
            {
                //string basesql = $"code like '{currentUser.BusinessCode} %' and id = x.id";
                //string sql = $" code !={currentUser.BusinessCode} and {basesql}";
                //string devicesql = $"code like '{currentUser.BusinessCode} %' and id = x.businessid"; 
                int businesscnt = await dbClient.Queryable<W_Business>().Where(x => SqlFunc.Subqueryable<W_Business>()
                .Where(e=>SqlFunc.StartsWith(e.Code,currentUser.BusinessCode))
                .Where(e=>x.Code != currentUser.BusinessCode)
                .Where(e=>e.Id == x.Id)
                .Any())             
                    .CountAsync();
                int devcnt = await repository.Change<W_Device>().Context.Queryable<W_Device>()
                    .Where(x=>SqlFunc.Subqueryable<W_Business>().Where(e=>SqlFunc.StartsWith(e.Code,currentUser.BusinessCode) && e.Id == x.Businessid).Any())
                    .CountAsync();
                var tempquery = repository.Change<W_DeviceStatistics>().Context.Queryable<W_DeviceStatistics>().Where(x => SqlFunc.DateIsSame(x.CreateTime, yestodaytime) && SqlFunc.Subqueryable<W_Business>().Where(e => SqlFunc.StartsWith(e.Code, currentUser.BusinessCode) && e.Id == x.Businessid).Any());
                int count = await tempquery.Clone().SumAsync(x => x.DayCount);
                decimal weight = await tempquery.Clone().SumAsync(x => x.DayWeight);
                decimal pureweight = await tempquery.Clone().SumAsync(x => x.DayPureWeight);
                return new BusinessReport
                {
                    BusinessCnt = businesscnt,
                    DevCount = devcnt,
                    YestodayCount = count,
                    YestodayPureWeight = pureweight,
                    YestodayWeight = weight
                };
            }
            else
            {
                var tempquery = repository.Change<W_DeviceStatistics>().Where(x => SqlFunc.DateIsSame(x.CreateTime, yestodaytime));
                int count = await tempquery.Clone().SumAsync(x => x.DayCount);
                decimal weight = await tempquery.Clone().SumAsync(x => x.DayWeight);
                decimal pureweight = await tempquery.Clone().SumAsync(x => x.DayPureWeight);
                var data = await repository.Change<W_RealData>().Context.Queryable<W_RealData>().FirstAsync();
                return new BusinessReport { 
                    DevCount = data.DevCnt,
                    BusinessCnt = data.BusinessCnt,
                    YestodayCount = count,
                    YestodayPureWeight = pureweight,
                    YestodayWeight = weight
                };
            }
        }
    }
}
