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

namespace YBDevice.NApi.Application.Prescription
{
    /// <summary>
    /// 处方
    /// </summary>
    public class PrescriptionService : BaseService, IPrescriptionService, ITransient
    {
        private readonly ISqlSugarRepository<YB_Family> repository;
        private readonly SqlSugarClient dbClient;
        private readonly IDistributedIDGenerator _idGenerator;
        public PrescriptionService(ISqlSugarRepository<YB_Family> sqlSugarRepository, IDistributedIDGenerator idGenerator)
        {
            repository = sqlSugarRepository;
            dbClient = repository.Context;
            _idGenerator = idGenerator;
        }

        /// <summary>
        /// 获取安邦儿童处方
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public async Task<ChildPrescriptionS2CDto> AB_Child(ChildPrescriptionS2SDto data)
        {
            int heightLevel = GetLevelVal(data.HeightLevel, LevelType.Height);
            int bmilevel = GetLevelVal(data.BMILevel, LevelType.BMI);
            int weightlevel = GetLevelVal(data.WeightLevel, LevelType.Weight);
            var returndata = new ChildPrescriptionS2CDto()
            {
                MoodList = new List<string>(),
                SportList = new List<string>(),
                SleepList = new List<string>(),
                NutritionList = new List<string>()
            };
            //针对营养和运动,选择一个最差的值
            Dictionary<PrescriptionType, int> dics = new Dictionary<PrescriptionType, int>()
            {
                {PrescriptionType.Height,heightLevel},
                {PrescriptionType.BMI,bmilevel},
                {PrescriptionType.Weight,weightlevel}
            };
            var typedata = dics.Where(x => x.Value > 0).OrderBy(x => x.Key).FirstOrDefault();
            List<AB_Prescription> firstdata = new List<AB_Prescription>();
            if (typedata.Key > 0)
            {
                firstdata = await dbClient.Queryable<AB_Prescription>().Where(x => x.Level == typedata.Value && x.Type == typedata.Key).ToListAsync();
            }
            foreach (var item in firstdata)
            {
                returndata.NutritionList.Add(item.Nutrition);
                returndata.SportList.Add(item.Sport);
            }
            var ids = firstdata.Select(x => x.Id).ToList();
            if (ids.Count > 0)
            {
                var datalist = new List<AB_PrescriptionByAge>();
                datalist = await dbClient.Queryable<AB_PrescriptionByAge>().Where(x => x.MaxAge == -1)
                    .Select(x => new AB_PrescriptionByAge
                    {
                        Type = x.Type,
                        Content = x.Content,
                        MaxAge = x.MaxAge
                    })
                    .ToListAsync();
                var tlist = await dbClient.Queryable<AB_PrescriptionByAge>().Where(x => x.MinAge <= data.Age && x.MaxAge >=data.Age)
                     .OrderBy(x => x.MinAge, OrderByType.Asc)
                     .Select(x => new AB_PrescriptionByAge
                     {
                         Type = x.Type,
                         Content = x.Content,
                         MaxAge = x.MaxAge
                     })
                     .ToListAsync();
                foreach (var item in tlist)
                {
                    if (!datalist.Any(x => x.Type == item.Type && x.MaxAge > 0))
                    {
                        datalist.Add(item);
                    }
                }
                foreach (var item in datalist)
                {
                    if (item.Type == PrescriptionAdviceType.Sleep)
                    {
                        returndata.SleepList.Add(item.Content);
                    }
                    else if (item.Type == PrescriptionAdviceType.Sport)
                    {
                        returndata.SportList.Add(item.Content);
                    }
                    else if (item.Type == PrescriptionAdviceType.Mood)
                    {
                        returndata.MoodList.Add(item.Content);
                    }
                }
            }
            return returndata;
        }

        /// <summary>
        /// 获取儿童处方
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public async Task<ChildPrescriptionS2CDto> Child(ChildPrescriptionS2SDto data)
        {
            int heightLevel = GetLevelVal(data.HeightLevel, LevelType.Height);
            int bmilevel = GetLevelVal(data.BMILevel, LevelType.BMI);
            int weightlevel = GetLevelVal(data.WeightLevel, LevelType.Weight);
            var returndata = new ChildPrescriptionS2CDto()
            {
                MoodList = new List<string>(),
                SportList = new List<string>(),
                SleepList = new List<string>(),
                NutritionList = new List<string>()
            };
            //针对营养和运动,选择一个最差的值
            Dictionary<PrescriptionType, int> dics = new Dictionary<PrescriptionType, int>()
            {
                {PrescriptionType.Height,heightLevel},
                {PrescriptionType.BMI,bmilevel},
                {PrescriptionType.Weight,weightlevel}
            };
            var typedata = dics.Where(x => x.Value > 0).OrderBy(x => x.Key).FirstOrDefault();
            //var firstdata = await dbClient.Queryable<YB_ChildrenPrescription>().Where(x => (x.Level == heightLevel && x.Type == 1) || (x.Level == bmilevel && x.Type == 2) || (x.Level == weightlevel && x.Type == 3)).ToListAsync();
            List<YB_ChildrenPrescription> firstdata = new List<YB_ChildrenPrescription>();
            if (typedata.Key > 0)
            {
                firstdata = await dbClient.Queryable<YB_ChildrenPrescription>().Where(x => x.Level == typedata.Value && x.Type == typedata.Key).ToListAsync();
            }
            foreach (var item in firstdata)
            {
                returndata.NutritionList.Add(item.Nutrition);
                returndata.SportList.Add(item.Sport);
            }
            var ids = firstdata.Select(x => x.Id).ToList();
            if (ids.Count > 0)
            {
                var datalist = new List<YB_ChildPrescriptionByAge>();
                datalist = await dbClient.Queryable<YB_ChildPrescriptionByAge>().Where(x => x.MaxAge == -1)
                    .Select(x => new YB_ChildPrescriptionByAge
                    {
                        Type = x.Type,
                        Content = x.Content,
                        MaxAge = x.MaxAge
                    })
                    .ToListAsync();
                var tlist = await dbClient.Queryable<YB_ChildPrescriptionByAge>().Where(x => x.MaxAge <= data.Age && x.MinAge > 0)
                     .OrderBy(x => x.MaxAge, OrderByType.Desc)
                     .Select(x => new YB_ChildPrescriptionByAge
                     {
                         Type = x.Type,
                         Content = x.Content,
                         MaxAge = x.MaxAge
                     })
                     .ToListAsync();
                foreach (var item in tlist)
                {
                    if (!datalist.Any(x => x.Type == item.Type && x.MaxAge > 0))
                    {
                        datalist.Add(item);
                    }
                }
                foreach (var item in datalist)
                {
                    if (item.Type == 2)
                    {
                        returndata.SleepList.Add(item.Content);
                    }
                    else if (item.Type == 1)
                    {
                        returndata.SportList.Add(item.Content);
                    }
                    else if (item.Type == 3)
                    {
                        returndata.MoodList.Add(item.Content);
                    }
                }
            }
            return returndata;
        }
        /// <summary>
        /// 计算儿童体质
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public async Task<ResultInfo> ChildPhysiqueAsync(ChildPhysiqueCalcC2SDto data)
        {
            if (data == null || data.data.Count == 0)
            {
                return new ResultInfo(ResultState.FAIL, "请先完成评测");
            }
            var insertdata = new YB_ChildPhysiqueResult
            {
                Id = _idGenerator.Create().ToGuid(),
                UserId = authInfo.UserId,
                CreateTime = DateTime.Now,
                FamilyId=data.FamilyId
            };
            int totalscore = data.data.Sum(x => x.Value);
            var insertlist = new List<YB_ChildPhysiqueResultDetail>();
            foreach (var item in data.data)
            {
                insertlist.Add(new YB_ChildPhysiqueResultDetail
                {
                    QId = item.Id,
                    ResultId = insertdata.Id
                });
                totalscore += item.Value;
            }
            insertdata.Score = totalscore;
            if (await dbClient.Queryable<YB_ChildPhysiqueResult>().AnyAsync(x => x.UserId == authInfo.UserId))
            {
                await dbClient.Deleteable<YB_ChildPhysiqueResultDetail>().Where(x => SqlFunc.Subqueryable<YB_ChildPhysiqueResult>().Where(e => e.FamilyId == data.FamilyId && e.Id == x.ResultId).Any()).ExecuteCommandAsync();
                await dbClient.Deleteable<YB_ChildPhysiqueResult>().Where(x => x.FamilyId == data.FamilyId).ExecuteCommandAsync();
            }
            await dbClient.Insertable(insertdata).ExecuteCommandAsync();
            await dbClient.Insertable(insertlist).ExecuteCommandAsync();
            return await GetChildPhysiqueAsync(1,data.FamilyId);
        }

        /// <summary>
        /// 获取儿童体质评测列表
        /// </summary>
        /// <param name="isrestart">是否重新测评,1-是,0-否</param>
        /// <param name="familyid">家庭成员ID</param>
        /// <returns></returns>
        public async Task<ResultInfo> GetChildPhysiqueAsync(int isrestart,int familyid)
        {
            var returndata = new ChildPhysiqueResultS2CDto
            {
                list = new List<ChildPhysiqueS2CDto>()
            };
            var list = await dbClient.Queryable<YB_ChildPhysique>()
                .OrderBy(x => x.Type, OrderByType.Asc)
                .OrderBy(x => x.Sort, OrderByType.Asc)
                .Select(x => new ChildPhysiqueS2CDto
                {
                    Type = x.Type,
                    Value = x.Value,
                    Text = x.Text,
                    Id = x.Id
                })
                .ToListAsync();
            int totalscore = 0;
            if (isrestart == 1)
            {
                //获取已经选中的结果
                var selectlist = await dbClient.Queryable<YB_ChildPhysiqueResultDetail>().Where(x => SqlFunc.Subqueryable<YB_ChildPhysiqueResult>().Where(e => e.FamilyId == familyid && e.Id == x.ResultId).Any()).ToListAsync();
                if (selectlist != null && selectlist.Count > 0)
                {
                    list.ForEach(x =>
                    {
                        if (selectlist.Any(e => e.QId == x.Id) && x.Value > 0)
                        {
                            returndata.list.Add(new ChildPhysiqueS2CDto
                            {
                                Id = x.Id,
                                Text = x.Text,
                                Type = x.Type,
                                Value = x.Value
                            });
                            totalscore += x.Value;
                        }
                    });
                }
            }
            if (returndata.list.Count > 0)
            {
                returndata.Result = GetChildPhyiqueResult(totalscore);
            }
            else
            {
                returndata.list = list;
            }
            return new ResultInfo(ResultState.SUCCESS, "success", returndata);
        }
        /// <summary>
        /// 获取当前用户的儿童体质结果
        /// </summary>
        /// <param name="familyid">家庭成员ID</param>
        /// <returns></returns>
        public async Task<string> GetChildPhysiqueResultAsync(int familyid)
        {
            var data = await dbClient.Queryable<YB_ChildPhysiqueResult>().FirstAsync(x => x.FamilyId == familyid);
            return data == null ? string.Empty : GetChildPhyiqueResult(data.Score);
        }

        /// <summary>
        /// 儿童体质结果
        /// </summary>
        /// <param name="score"></param>
        /// <returns></returns>
        private string GetChildPhyiqueResult(int score)
            => score switch
            {
                0 => ChildPhysiqueResultConst.Good,
                <= 3 and > 0 => ChildPhysiqueResultConst.Little,
                <= 5 and > 3 => ChildPhysiqueResultConst.Big,
                > 5 => ChildPhysiqueResultConst.Serious,
                _ => ChildPhysiqueResultConst.Fail
            };

        /// <summary>
        /// 获取等级对应的值
        /// </summary>
        /// <param name="level">等级</param>
        /// <param name="type">类型,1-身高,2-BMI,3-体重</param>
        private int GetLevelVal(string level, LevelType type)
            => (level, type) switch
            {
                (HeightLevelConst.MoreLow, LevelType.Height) or (BMILevelConst.Thin, LevelType.BMI) or (WeightLevelConst.MoreLow, LevelType.Weight) or (WeightLevelConst.Low, LevelType.Weight) or (WeightLevelConst.LittleLow, LevelType.Weight) => 1,
                (HeightLevelConst.Low, LevelType.Height) or (BMILevelConst.Normal, LevelType.BMI) or (WeightLevelConst.Normal, LevelType.Weight) => 2,
                (HeightLevelConst.LittleLow, LevelType.Height) or (BMILevelConst.OverWeight, LevelType.BMI) or (WeightLevelConst.LittleHeight, LevelType.Weight) or (WeightLevelConst.Height, LevelType.Weight) or (WeightLevelConst.MoreHeight, LevelType.Weight) => 3,
                (HeightLevelConst.Normal, LevelType.Height) or (BMILevelConst.Fat, LevelType.BMI) => 4,
                (HeightLevelConst.LittleHeight, LevelType.Height) or (HeightLevelConst.Height, LevelType.Height) or (HeightLevelConst.MoreHeight, LevelType.Height) => 5,
                _ => 0
            };
    }
}
