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

namespace YBDevice.CommonService.LevelInfo
{
    /// <summary>
    /// 获取等级标准信息
    /// </summary>
    public class LevelService : ILevelService, ITransient
    {
        private readonly ISqlSugarRepository<YB_BmiStand> repository;
        private readonly SqlSugarClient dbClient;
        private readonly IBodyFatHelperService _bodyFatHelperService;
        public LevelService(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">BMI值</param>
        /// <param name="type">1-bmi,2-身高,3-体重,4-头围</param>
        /// <returns></returns>
        public async Task<LevelS2SDto> LevelAsync(GenderType sex, decimal month, decimal value, int type = 1)
        {
            YB_NewHeightStand data = null;
            if (type == 1)
            {
                //如果年龄小于6个月则使用6个月的标准
                if (month < 6)
                {
                    data = await dbClient.Queryable<YB_BmiStand>().Where(x => x.Sex == (int)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 == (int)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 == 2)
            {
                data = await dbClient.Queryable<YB_NewHeightStand>().Where(x => x.Sex == (int)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 == 3)
            {
                //如果月龄小于0.25则使用0.25的
                month = month < 0.25m ? 0.25m : month;
                data = await dbClient.Queryable<YB_NewWeightStand>().Where(x => x.Sex == (int)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 == 4)
            {
                data = await dbClient.Queryable<YB_HeadStand>().Where(x => x.Sex == (int)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),
                Media = data == null ? data.median : 0
            };
            //如果年龄大于16岁则使用成人BMI标准
            if (month > 16 * 12)
            {
                if (type == 1)
                {
                    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);
            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, int type = 1)
            => (data, val, type) switch
            {
                _ when data == null => LevelConst.Error,
                _ when type == 1 && val <= data.f1sd && val > 0 => BMILevelConst.Thin,
                _ when type == 1 && val <= data.z1sd && val > data.f1sd => BMILevelConst.Normal,
                _ when type == 1 && val <= data.z2sd && val > data.z1sd => BMILevelConst.OverWeight,
                _ when type == 1 && val > data.z2sd => BMILevelConst.Fat,
                //_ when type == 2 && val <= data.f3sd && val > 0 => HeightLevelConst.MoreLow,
                _ when type == 2 && val <= data.f2sd && val > 0 => HeightLevelConst.Low,
                _ when type == 2 && val <= data.f1sd && val > data.f2sd => HeightLevelConst.LittleLow,
                _ when type == 2 && val <= data.z1sd && val > data.f1sd => HeightLevelConst.Normal,
                _ when type == 2 && val <= data.z2sd && val > data.z1sd => HeightLevelConst.LittleHeight,
                _ when type == 2 && val > data.z2sd => HeightLevelConst.Height,
                //_ when type == 2 && val > data.f2sd => HeightLevelConst.MoreHeight,
                //_ when type == 3 && val <= data.f3sd && val > 0 => WeightLevelConst.MoreLow,
                _ when type == 3 && val <= data.f2sd && val > 0 => WeightLevelConst.Low,
                _ when type == 3 && val <= data.f1sd && val > data.f2sd => WeightLevelConst.LittleLow,
                _ when type == 3 && val <= data.z1sd && val > data.f1sd => WeightLevelConst.Normal,
                _ when type == 3 && val <= data.z2sd && val > data.z1sd => WeightLevelConst.LittleHeight,
                _ when type == 3 && val > data.z2sd => WeightLevelConst.Height,
                //_ when type == 3 && val > data.z2sd => WeightLevelConst.MoreHeight,
                //_ when type == 4 && val <= data.f3sd && val > 0 => HeadLevelConst.MoreLow,
                _ when type == 4 && val <= data.f2sd && val > 0 => HeadLevelConst.Low,
                _ when type == 4 && val <= data.f1sd && val > data.f2sd => HeadLevelConst.LittleLow,
                _ when type == 4 && val <= data.z1sd && val > data.f1sd => HeadLevelConst.Normal,
                _ when type == 4 && val <= data.z2sd && val > data.z1sd => HeadLevelConst.LittleHeight,
                _ when type == 4 && val > data.z2sd => HeadLevelConst.Height,
                //_ when type == 4 && val > data.z2sd => HeadLevelConst.MoreHeight,
                _ => LevelConst.Error
            };
        /// <summary>
        /// 根据等级获取标准颜色
        /// </summary>
        /// <param name="level">等级标准</param>
        /// <param name="type">1-bmi,2-身高,3-体重,4-头围</param>
        /// <returns></returns>
        private string GetLevelColor(string level, int type = 0)
            => (level, type) switch
            {
                //BMI消瘦,身高偏矮,体重偏低,头围偏低
                (BMILevelConst.Thin, 1)
                or (HeightLevelConst.LittleLow, 2)
                or (WeightLevelConst.LittleLow, 3)
                or (HeadLevelConst.LittleLow, 4)
                => LevelColor.Thin,
                //BMI正常,身高标准,体重标准,头围标准
                (BMILevelConst.Normal, 1)
                or (HeightLevelConst.Normal, 2)
                or (WeightLevelConst.Normal, 3)
                or (HeadLevelConst.Normal, 4)
                => LevelColor.Normal,
                //BMI超重,身高矮,体重低,体重偏高,头围低,头围偏高
                (BMILevelConst.OverWeight, 1)
                or (HeightLevelConst.Low, 2)
                or (WeightLevelConst.Low, 3)
                or (WeightLevelConst.LittleHeight, 3)
                or (HeadLevelConst.Low, 4)
                or (HeadLevelConst.LittleHeight, 4)
                => LevelColor.OverWeight,
                //BMI肥胖,身高严重偏矮,体重严重偏低,体重高,体重严重偏高,头围严重偏低,头围严重偏高,头围高
                (BMILevelConst.Fat, 1)
                or (HeightLevelConst.MoreLow, 2)
                or (WeightLevelConst.MoreLow, 3)
                or (WeightLevelConst.Height, 3)
                or (WeightLevelConst.MoreHeight, 3)
                or (HeadLevelConst.Height, 4)
                or (HeadLevelConst.MoreLow, 4)
                or (HeadLevelConst.MoreHeight, 4)
                => LevelColor.Fat,
                //身高偏高
                (HeightLevelConst.LittleHeight, 2)
                => LevelColor.LittleFine,
                //身高高
                (HeightLevelConst.Height, 2)
                => LevelColor.MoreFine,
                //身高优秀
                (HeightLevelConst.MoreHeight, 2)
                => LevelColor.Fine,
                _ => LevelColor.Error
            };
        /// <summary>
        /// 获取标准列表
        /// </summary>
        /// <param name="data"></param>
        /// <param name="type">1-bmi,2-身高,3-体重,4-头围</param>
        /// <returns></returns>
        private List<MeasureInfoItemValue> GetStandList(YB_NewHeightStand data, int type = 1)
            => type switch
            {
                1 => 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
                    }
                },
                2 => new List<MeasureInfoItemValue> {
                    //new MeasureInfoItemValue{
                    //    maxvalue = data.f3sd,
                    //    minvalue=0,
                    //    text = HeightLevelConst.MoreLow,
                    //    color = LevelColor.Fat
                    //},
                    new MeasureInfoItemValue{
                        maxvalue = data.f2sd,
                        minvalue=0,
                        text = HeightLevelConst.Low,
                        color = LevelColor.OverWeight
                    },
                    new MeasureInfoItemValue{
                        maxvalue = data.f1sd,
                        minvalue=data.f2sd,
                        text = HeightLevelConst.LittleLow,
                        color = LevelColor.Thin
                    },
                    new MeasureInfoItemValue{
                        maxvalue = data.z1sd,
                        minvalue=data.f1sd,
                        text = HeightLevelConst.Normal,
                        color = LevelColor.Normal
                    },
                    new MeasureInfoItemValue{
                        maxvalue = data.z2sd,
                        minvalue=data.z1sd,
                        text = HeightLevelConst.LittleHeight,
                        color = LevelColor.LittleFine
                    },
                    new MeasureInfoItemValue{
                        maxvalue = data.z3sd,
                        minvalue=data.z2sd,
                        text = HeightLevelConst.Height,
                        color = LevelColor.MoreFine
                    },
                    //new MeasureInfoItemValue{
                    //    maxvalue = data.z3sd,
                    //    minvalue=data.z2sd,
                    //    text = HeightLevelConst.MoreHeight,
                    //    color = LevelColor.Fine
                    //}
                },
                3 => new List<MeasureInfoItemValue> {
                    //new MeasureInfoItemValue{
                    //    maxvalue = data.f3sd,
                    //    minvalue=0,
                    //    text = WeightLevelConst.MoreLow,
                    //    color = LevelColor.Fat
                    //},
                    new MeasureInfoItemValue{
                        maxvalue = data.f2sd,
                        minvalue=0,
                        text = WeightLevelConst.Low,
                        color = LevelColor.OverWeight
                    },
                    new MeasureInfoItemValue{
                        maxvalue = data.f1sd,
                        minvalue=data.f2sd,
                        text = WeightLevelConst.LittleLow,
                        color = LevelColor.Thin
                    },
                    new MeasureInfoItemValue{
                        maxvalue = data.z1sd,
                        minvalue=data.f1sd,
                        text = WeightLevelConst.Normal,
                        color = LevelColor.Normal
                    },
                    new MeasureInfoItemValue{
                        maxvalue = data.z2sd,
                        minvalue=data.z1sd,
                        text = WeightLevelConst.LittleHeight,
                        color = LevelColor.OverWeight
                    },
                    new MeasureInfoItemValue{
                        maxvalue = data.z3sd,
                        minvalue=data.z2sd,
                        text = WeightLevelConst.Height,
                        color = LevelColor.Fat
                    },
                    //new MeasureInfoItemValue{
                    //    maxvalue = data.z3sd,
                    //    minvalue=data.z2sd,
                    //    text = WeightLevelConst.MoreHeight,
                    //    color = LevelColor.Fat
                    //}
                },
                4 => new List<MeasureInfoItemValue> {
                    //new MeasureInfoItemValue{
                    //    maxvalue = data.f3sd,
                    //    minvalue=0,
                    //    text = HeadLevelConst.MoreLow,
                    //    color = LevelColor.Fat
                    //},
                    new MeasureInfoItemValue{
                        maxvalue = data.f2sd,
                        minvalue=0,
                        text = HeadLevelConst.Low,
                        color = LevelColor.OverWeight
                    },
                    new MeasureInfoItemValue{
                        maxvalue = data.f1sd,
                        minvalue=data.f2sd,
                        text = HeadLevelConst.LittleLow,
                        color = LevelColor.Thin
                    },
                    new MeasureInfoItemValue{
                        maxvalue = data.z1sd,
                        minvalue=data.f1sd,
                        text = HeadLevelConst.Normal,
                        color = LevelColor.Normal
                    },
                    new MeasureInfoItemValue{
                        maxvalue = data.z2sd,
                        minvalue=data.z1sd,
                        text = HeadLevelConst.LittleHeight,
                        color = LevelColor.OverWeight
                    },
                    new MeasureInfoItemValue{
                        maxvalue = data.z3sd,
                        minvalue=data.z2sd,
                        text = HeadLevelConst.Height,
                        color = LevelColor.Fat
                    },
                    //new MeasureInfoItemValue{
                    //    maxvalue = data.z3sd,
                    //    minvalue=data.z2sd,
                    //    text = HeadLevelConst.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, int 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, int type)
        {
            if (brithday == null)
            {
                return new LevelS2SDto();
            }
            decimal month = brithday.Value.ToMonth(true);
            return await LevelAsync(sex, month, value, type);
        }
    }
}
