using Furion.DependencyInjection;
using Nirvana.Common;
using SqlSugar;
using YBDevice.Body.BodyFatHelper;
using YBDevice.Entity;

namespace YBDevice.Body.Level
{
    /// <summary>
    /// 安邦儿童等级
    /// </summary>
    public class AbLevelService : ILevelService, ITransient
    {
        private readonly ISqlSugarRepository<YB_BmiStand> repository;
        private readonly SqlSugarClient dbClient;
        private readonly IBodyFatHelperService _bodyFatHelperService;
        public AbLevelService(ISqlSugarRepository<YB_BmiStand> sqlSugarRepository, IBodyFatHelperService bodyFatHelperService)
        {
            repository = sqlSugarRepository;
            dbClient = repository.Context;
            _bodyFatHelperService = bodyFatHelperService;
        }
        /// <summary>
        /// 标准
        /// </summary>
        /// <param name="sex">性别,1-男,2-女</param>
        /// <param name="month">月龄</param>
        /// <param name="value">值</param>
        /// <param name="type">1-bmi,2-身高,3-体重,4-头围</param>
        /// <returns></returns>
        public async Task<LevelS2SDto> LevelAsync(GenderType sex, decimal month, decimal value, LevelType type)
        {
            YB_NewHeightStand data = null;
            if (type == LevelType.BMI)
            {
                //如果年龄小于6个月则使用6个月的标准
                if (month < 6)
                {
                    data = await dbClient.Queryable<YB_BmiStand>().Where(x => x.Sex == sex && x.Month <= 6).OrderBy(x => x.Month, OrderByType.Desc)
                   .Select(x => new YB_NewHeightStand
                   {
                       f1sd = x.f1sd,
                       median = x.median,
                       z1sd = x.z1sd,
                       z2sd = x.z2sd
                   })
                   .FirstAsync();
                }
                else
                {
                    data = await dbClient.Queryable<YB_BmiStand>().Where(x => x.Sex == sex && x.Month <= month).OrderBy(x => x.Month, OrderByType.Desc)
                    .Select(x => new YB_NewHeightStand
                    {
                        f1sd = x.f1sd,
                        median = x.median,
                        z1sd = x.z1sd,
                        z2sd = x.z2sd
                    })
                    .FirstAsync();
                }
            }
            else if (type == LevelType.Height)
            {
                data = await dbClient.Queryable<AB_HeightStand>().Where(x => x.Sex == sex && x.Month <= month).OrderBy(x => x.Month, OrderByType.Desc)
                    .Select(x => new YB_NewHeightStand
                    {
                        f3sd = x.f3sd,
                        f2sd = x.f2sd,
                        f1sd = x.f1sd,
                        median = x.median,
                        z1sd = x.z1sd,
                        z2sd = x.z2sd,
                        z3sd = x.z3sd
                    })
                    .FirstAsync();
            }
            else if (type == LevelType.Weight)
            {
                //如果月龄小于0.25则使用0.25的
                month = month < 0.25m ? 0.25m : month;
                data = await dbClient.Queryable<AB_WeightStand>().Where(x => x.Sex == sex && x.Month <= month).OrderBy(x => x.Month, OrderByType.Desc)
                    .Select(x => new YB_NewHeightStand
                    {
                        f3sd = x.f3sd,
                        f2sd = x.f2sd,
                        f1sd = x.f1sd,
                        median = x.median,
                        z1sd = x.z1sd,
                        z2sd = x.z2sd,
                        z3sd = x.z3sd
                    })
                    .FirstAsync();
            }
            else if (type == LevelType.Head)
            {
                data = await dbClient.Queryable<YB_HeadStand>().Where(x => x.Sex == sex && x.Month <= month).OrderBy(x => x.Month, OrderByType.Desc)
                   .Select(x => new YB_NewHeightStand
                   {
                       f3sd = x.f3sd,
                       f2sd = x.f2sd,
                       f1sd = x.f1sd,
                       median = x.median,
                       z1sd = x.z1sd,
                       z2sd = x.z2sd,
                       z3sd = x.z3sd
                   })
                   .FirstAsync();
            }
            var returndata = new LevelS2SDto
            {
                Level = GetLevelVal(data, value, type),
                list = data == null ? new List<MeasureInfoItemValue>() : GetStandList(data, type),
                Data = data,
                Media = data != null ? data.median : 0,
                HeightLevel = type == LevelType.Height ? GetHeightLevelVal(data, value) : ChildHeightLevel.Normal
            };
            //如果年龄大于16岁则使用成人BMI标准
            if (month > FamilyTypeLevel.AdultMonth)
            {
                if (type == LevelType.BMI)
                {
                    returndata.list = _bodyFatHelperService.bmi_value(sex, 0).Select(x => new MeasureInfoItemValue
                    {
                        color = x.color,
                        maxvalue = x.maxvalue,
                        minvalue = x.minvalue,
                        text = x.text
                    }).ToList();
                    returndata.Media = _bodyFatHelperService.bmi_stand(sex, 0).minvalue;
                }
            }
            else
            {
                if (data == null)
                {
                    return new LevelS2SDto();
                }
            }
            returndata.Color = GetLevelColor(returndata.Level, type, returndata.list);
            return returndata;
        }
        /// <summary>
        /// 获取等级值
        /// </summary>
        /// <param name="data"></param>
        /// <param name="val">当前值</param>
        /// <param name="type">1-bmi,2-身高,3-体重,4-头围</param>
        /// <returns></returns>
        private string GetLevelVal(YB_NewHeightStand data, decimal val, LevelType type = LevelType.BMI)
            => (data, val, type) switch
            {
                _ when data == null => LevelConst.Error,
                _ when type == LevelType.BMI && val <= data.f1sd && val > 0 => BMILevelConst.Thin,
                _ when type == LevelType.BMI && val <= data.z1sd && val > data.f1sd => BMILevelConst.Normal,
                _ when type == LevelType.BMI && val <= data.z2sd && val > data.z1sd => BMILevelConst.OverWeight,
                _ when type == LevelType.BMI && val > data.z2sd => BMILevelConst.Fat,

                _ when type == LevelType.Height && val <= data.f2sd && val > 0 => AbHeightLevelConst.MoreLow,
                _ when type == LevelType.Height && val <= data.f1sd && val > data.f2sd => AbHeightLevelConst.Low,
                _ when type == LevelType.Height && val <= data.median && val > data.f1sd => AbHeightLevelConst.LittleLow,
                _ when type == LevelType.Height && val <= data.z1sd && val > data.median => AbHeightLevelConst.Normal,
                _ when type == LevelType.Height && val <= data.z2sd && val > data.z1sd => AbHeightLevelConst.LittleHeight,
                _ when type == LevelType.Height && val <= data.z3sd && val > data.z2sd => AbHeightLevelConst.Height,
                _ when type == LevelType.Height && val > data.z3sd => AbHeightLevelConst.MoreHeight,

                _ when type == LevelType.Weight && val <= data.f2sd && val > 0 => AbWeightLevelConst.MoreLow,
                _ when type == LevelType.Weight && val <= data.f1sd && val > data.f2sd => AbWeightLevelConst.Low,
                _ when type == LevelType.Weight && val <= data.median && val > data.f1sd => AbWeightLevelConst.LittleLow,
                _ when type == LevelType.Weight && val <= data.z1sd && val > data.median => AbWeightLevelConst.Normal,
                _ when type == LevelType.Weight && val <= data.z2sd && val > data.z1sd => AbWeightLevelConst.LittleHeight,
                _ when type == LevelType.Weight && val <= data.z3sd && val > data.z2sd => AbWeightLevelConst.LittleHeight,
                _ when type == LevelType.Weight && val > data.z3sd => AbWeightLevelConst.MoreHeight,

                _ when type == LevelType.Head && val <= data.f2sd && val > 0 => AbWeightLevelConst.MoreLow,
                _ when type == LevelType.Head && val <= data.f1sd && val > data.f2sd => AbWeightLevelConst.Low,
                _ when type == LevelType.Head && val <= data.median && val > data.f1sd => AbWeightLevelConst.LittleLow,
                _ when type == LevelType.Head && val <= data.z1sd && val > data.median => AbWeightLevelConst.Normal,
                _ when type == LevelType.Head && val <= data.z2sd && val > data.z1sd => AbWeightLevelConst.LittleHeight,
                _ when type == LevelType.Head && val <= data.z3sd && val > data.z2sd => AbWeightLevelConst.LittleHeight,
                _ when type == LevelType.Head && val > data.z3sd => AbWeightLevelConst.MoreHeight,

                _ => LevelConst.Error
            };

        /// <summary>
        /// 获取身高等级值
        /// </summary>
        /// <param name="data"></param>
        /// <param name="val"></param>
        /// <returns></returns>
        private ChildHeightLevel GetHeightLevelVal(YB_NewHeightStand data, decimal val)
         => (data, val) switch
         {
             _ when data == null => ChildHeightLevel.Error,
             _ when val > 0 && val <= data.f2sd => ChildHeightLevel.MoreLow,
             _ when val > data.f2sd && val <= data.f1sd => ChildHeightLevel.Low,
             _ when val > data.f1sd && val <= data.median => ChildHeightLevel.LittleLow,
             _ when val > data.median && val <= data.z1sd => ChildHeightLevel.Normal,
             _ when val > data.z1sd && val <= data.z2sd => ChildHeightLevel.LittleHeight,
             _ when val > data.z2sd && val <= data.z3sd => ChildHeightLevel.Height,
             _ when val > data.z3sd => ChildHeightLevel.MoreHeight,
             _ => ChildHeightLevel.Error
         };

        /// <summary>
        /// 根据等级获取标准颜色
        /// </summary>
        /// <param name="level">等级标准</param>
        /// <param name="type">1-bmi,2-身高,3-体重,4-头围</param>
        /// <param name="list">标准列表</param>
        /// <returns></returns>
        private string GetLevelColor(string level, LevelType type, List<MeasureInfoItemValue> list)
        {
            var data = list.Where(x => x.text == level).FirstOrDefault();
            if (data == null)
            {
                return LevelColor.Error;
            }
            return data.color;
        }
        /// <summary>
        /// 获取标准列表
        /// </summary>
        /// <param name="data"></param>
        /// <param name="type">1-bmi,2-身高,3-体重,4-头围</param>
        /// <returns></returns>
        private List<MeasureInfoItemValue> GetStandList(YB_NewHeightStand data, LevelType type)
            => type switch
            {
                LevelType.BMI => new List<MeasureInfoItemValue> {
                    new MeasureInfoItemValue{
                        maxvalue = data.f1sd,
                        minvalue=0,
                        text = BMILevelConst.Thin,
                        color = LevelColor.Thin
                    },
                    new MeasureInfoItemValue{
                        maxvalue = data.z1sd,
                        minvalue=data.f1sd,
                        text = BMILevelConst.Normal,
                        color = LevelColor.Normal
                    },
                    new MeasureInfoItemValue{
                        maxvalue = data.z2sd,
                        minvalue=data.z1sd,
                        text = BMILevelConst.OverWeight,
                        color = LevelColor.OverWeight
                    },
                    new MeasureInfoItemValue{
                        maxvalue = 50,
                        minvalue=data.z2sd,
                        text = BMILevelConst.Fat,
                        color = LevelColor.Fat
                    }
                },
                LevelType.Height => new List<MeasureInfoItemValue> {
                    new MeasureInfoItemValue{
                        maxvalue = data.f3sd,
                        minvalue=0,
                        text = "",
                        color = LevelColor.Error,
                        Level = (int)ChildHeightLevel.MoreLow
                    },
                    new MeasureInfoItemValue{
                        maxvalue = data.f2sd,
                        minvalue=data.f3sd,
                        text = AbHeightLevelConst.MoreLow,
                        color = LevelColor.Fat,
                        Level = (int)ChildHeightLevel.MoreLow
                    },
                    new MeasureInfoItemValue{
                        maxvalue = data.f1sd,
                        minvalue=data.f2sd,
                        text = AbHeightLevelConst.Low,
                        color = LevelColor.OverWeight,
                        Level = (int)ChildHeightLevel.Low
                    },
                    new MeasureInfoItemValue{
                        maxvalue = data.median,
                        minvalue=data.f1sd,
                        text = AbHeightLevelConst.LittleLow,
                        color = LevelColor.Thin,
                        Level = (int)ChildHeightLevel.LittleLow
                    },
                    new MeasureInfoItemValue{
                        maxvalue = data.z1sd,
                        minvalue=data.median,
                        text = AbHeightLevelConst.Normal,
                        color = LevelColor.Normal,
                        Level = (int)ChildHeightLevel.Normal
                    },
                    new MeasureInfoItemValue{
                        maxvalue = data.z2sd,
                        minvalue=data.z1sd,
                        text = AbHeightLevelConst.LittleHeight,
                        color = LevelColor.LittleFine,
                        Level = (int)ChildHeightLevel.LittleHeight
                    },
                    new MeasureInfoItemValue{
                        maxvalue = data.z3sd,
                        minvalue=data.z2sd,
                        text = AbHeightLevelConst.Height,
                        color = LevelColor.MoreFine,
                        Level = (int)ChildHeightLevel.Height
                    },
                    new MeasureInfoItemValue{
                        maxvalue = 0,
                        minvalue=data.z3sd,
                        text = AbHeightLevelConst.MoreHeight,
                        color = LevelColor.Fine,
                        Level = (int)ChildHeightLevel.MoreHeight
                    }
                },
                LevelType.Weight => new List<MeasureInfoItemValue> {
                    new MeasureInfoItemValue{
                        maxvalue = data.f3sd,
                        minvalue=0,
                        text = "",
                        color = LevelColor.Error
                    },
                    new MeasureInfoItemValue{
                        maxvalue = data.f2sd,
                        minvalue=data.f3sd,
                        text = AbWeightLevelConst.MoreLow,
                        color = LevelColor.Fat
                    },
                    new MeasureInfoItemValue{
                        maxvalue = data.f1sd,
                        minvalue=data.f2sd,
                        text = AbWeightLevelConst.Low,
                        color = LevelColor.OverWeight
                    },
                    new MeasureInfoItemValue{
                        maxvalue = data.median,
                        minvalue=data.f1sd,
                        text = AbWeightLevelConst.LittleLow,
                        color = LevelColor.Thin
                    },
                    new MeasureInfoItemValue{
                        maxvalue = data.z1sd,
                        minvalue=data.median,
                        text = AbWeightLevelConst.Normal,
                        color = LevelColor.Normal
                    },
                    new MeasureInfoItemValue{
                        maxvalue = data.z2sd,
                        minvalue=data.z1sd,
                        text = AbWeightLevelConst.LittleHeight,
                        color = LevelColor.Thin
                    },
                    new MeasureInfoItemValue{
                        maxvalue = data.z3sd,
                        minvalue=data.z2sd,
                        text = AbWeightLevelConst.Height,
                        color = LevelColor.OverWeight
                    },
                    new MeasureInfoItemValue{
                        maxvalue = 0,
                        minvalue=data.z3sd,
                        text = AbWeightLevelConst.MoreHeight,
                        color = LevelColor.Fat
                    }
                },
                LevelType.Head => new List<MeasureInfoItemValue> {
                    new MeasureInfoItemValue{
                        maxvalue = data.f3sd,
                        minvalue=0,
                        text = "",
                        color = LevelColor.Error
                    },
                     new MeasureInfoItemValue{
                        maxvalue = data.f2sd,
                        minvalue=data.f3sd,
                        text = AbWeightLevelConst.MoreLow,
                        color = LevelColor.Fat
                    },
                    new MeasureInfoItemValue{
                        maxvalue = data.f1sd,
                        minvalue=data.f2sd,
                        text = AbWeightLevelConst.Low,
                        color = LevelColor.OverWeight
                    },
                    new MeasureInfoItemValue{
                        maxvalue = data.median,
                        minvalue=data.f1sd,
                        text = AbWeightLevelConst.LittleLow,
                        color = LevelColor.Thin
                    },
                    new MeasureInfoItemValue{
                        maxvalue = data.z1sd,
                        minvalue=data.median,
                        text = AbWeightLevelConst.Normal,
                        color = LevelColor.Normal
                    },
                    new MeasureInfoItemValue{
                        maxvalue = data.z2sd,
                        minvalue=data.z1sd,
                        text = AbWeightLevelConst.LittleHeight,
                        color = LevelColor.OverWeight
                    },
                    new MeasureInfoItemValue{
                        maxvalue = data.z3sd,
                        minvalue=data.z2sd,
                        text = AbWeightLevelConst.Height,
                        color = LevelColor.Fat
                    },
                    new MeasureInfoItemValue{
                        maxvalue = 0,
                        minvalue=data.z3sd,
                        text = AbWeightLevelConst.MoreHeight,
                        color = LevelColor.Fat
                    }
                },
                _ => new List<MeasureInfoItemValue>()
            };
        /// <summary>
        /// 标准
        /// </summary>
        /// <param name="sex">性别,1-男,2-女</param>
        /// <param name="brithday">出生年龄</param>
        /// <param name="value">值</param>
        /// <param name="type">1-bmi,2-身高,3-体重,4-头围</param>
        /// <returns></returns>
        public async Task<LevelS2SDto> LevelAsync(GenderType sex, DateTime brithday, decimal value, LevelType type)
        {
            decimal month = brithday.ToMonth(true);
            return await LevelAsync(sex, month, value, type);
        }
        /// <summary>
        /// 标准
        /// </summary>
        /// <param name="sex">性别,1-男,2-女</param>
        /// <param name="brithday">出生年龄</param>
        /// <param name="value">值</param>
        /// <param name="type">1-bmi,2-身高,3-体重,4-头围</param>
        /// <returns></returns>
        public async Task<LevelS2SDto> LevelAsync(GenderType sex, DateTime? brithday, decimal value, LevelType type)
        {
            if (brithday == null)
            {
                return new LevelS2SDto();
            }
            decimal month = brithday.Value.ToMonth(true);
            return await LevelAsync(sex, month, value, type);
        }
    }
}
