using Nirvana.Common;
using Nirvana.Common.ApiBase;
using Nirvana.Data;
using Senparc.Weixin.WxOpen.Containers;
using Senparc.Weixin.WxOpen.Entities;
using Senparc.Weixin.WxOpen.Helpers;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Threading.Tasks;
using YBDevice.Entity;

namespace YBDevice.NApi.DBServices
{
    /// <summary>
    /// 注册用户管理
    /// </summary>
    public partial class UserApp : BaseApp
    {
        /// <summary>
        /// 获取用户个人资料
        /// </summary>
        /// <param name="familyid">家庭成员ID</param>
        /// <returns></returns>
        public async Task<ResultInfo> GetUserInfoAsync(int familyid)
        {
            using (var dbClient = ReadDbContext.GetInstance())
            {
                var user = await dbClient.Queryable<YB_RegUser>().Where(x => x.Id == authInfo.UserId).FirstAsync();
                YB_Family family = new YB_Family();
                if (familyid > 0)
                {
                    family = await dbClient.Queryable<YB_Family>().Where(x => x.Id == familyid && x.Type == 1).FirstAsync();
                }
                //试着获取一个最新的
                if (family == null || family.Id <= 0)
                {
                    family = await dbClient.Queryable<YB_Family>().Where(x => x.UserId == user.Id && x.Status != -1 && x.Type == 1).OrderBy(x => x.LastHeartTime, OrderByType.Desc).FirstAsync();
                }
                var target = await dbClient.Queryable<YB_FamilyTarget>().FirstAsync(x => x.familyid == family.Id);
                var data = new UserInfoModel
                {
                    headimg = !string.IsNullOrEmpty(family.HeadImg) ? family.HeadImg : new FamilyApp().HeadImg(family.Sex, family.Type),
                    sex = family.Sex,
                    nickname = family.Name,
                    isbindphone = string.IsNullOrEmpty(user.Headimg) ? false : true,
                    age = family.Age,
                    familyid = family.Id,
                    height = family.Height,
                    targetweight = target != null ? target.weight : 0,
                    targettime = target != null ? target.time.ToYearDate() : "-- --",
                    weight = family.Weight,
                    lasthearttime = family.LastHeartTime.HasValue ? family.LastHeartTime.Value.ToYearDate() : "-- --",
                    Birthday = family.Birthday.ToString("yyyy-MM-dd")
                };
                return new ResultInfo(ResultState.SUCCESS, "success", data);
            }
        }

        /// <summary>
        /// 解密手机号
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public async Task<ResultInfo> DecryptPhoneAsync(WxOpenDecryptSubmitModel model)
        {
            using (var dbClient = ReadDbContext.GetInstance())
            {
                var sessionBag = await SessionContainer.GetSessionAsync(model.sessionId);
                if (sessionBag == null)
                {
                    return new ResultInfo(ResultState.FAIL, "sessionId未找到");
                }
                var phone = EncryptHelper.DecryptPhoneNumberBySessionKey(sessionBag.SessionKey, model.encryptedData, model.iv);
                //更新当前用户的手机号
                await dbClient.Updateable<YB_RegUser>().SetColumns(x => new YB_RegUser
                {
                    Phone = phone.purePhoneNumber
                }).Where(x => x.Id == authInfo.UserId).ExecuteCommandAsync();
                return new ResultInfo(ResultState.SUCCESS, "手机号绑定成功");
            }
        }

        /// <summary>
        /// 获取用户测量数据
        /// </summary>
        /// <returns></returns>
        public async Task<ResultInfo> GetMeasureInfoAsync(UserMeasureInfoModel model)
        {
            if (model.height <= 0)
            {
                return new ResultInfo(ResultState.FAIL, "身高不可小于0");
            }
            using (var dbClient = ReadDbContext.GetInstance())
            {
                //获取此家庭成员的体重信息
                var family = await dbClient.Queryable<YB_Family>().Where(x => x.Id == model.familyid).FirstAsync();
                if (family == null)
                {
                    return new ResultInfo(ResultState.FAIL, "家庭成员未找到");
                }
                int age = model.birthday.ToAge();
                if (age > 100)
                {
                    return new ResultInfo(ResultState.FAIL, "年龄过大");
                }
                //更新家庭成员信息
                await dbClient.Updateable<YB_Family>().SetColumns(x => new YB_Family
                {
                    Height = model.height,
                    Age = age,
                    Sex = model.sex,
                    Birthday = model.birthday
                }).Where(x => x.Id == model.familyid).ExecuteCommandAsync();
                if (!await dbClient.Queryable<YB_Measure>().AnyAsync(x => x.FamilyId == family.Id))
                {
                    //#region 如果没有测量记录,则加载演示数据
                    //var ysfamily = new YSFamily();
                    //var ysdata = BodyFatHelper.CalcBodyFat(ysfamily.ADWeight.ToDouble(), ysfamily.ADHeight.ToDouble(),ysfamily.ADAge, ysfamily.imp, ysfamily.Sex);
                    //List<MeasureModels> yslistcnt = new List<MeasureModels>();
                    //double testheight= ysfamily.ADHeight.ToDouble();
                    //double testweight = ysfamily.ADWeight.ToDouble();
                    //var testdata = new UserMeasureModel();
                    //List<MeasureModels> yslistday = new List<MeasureModels>();
                    //for (var i = 1; i <= 10; i++)
                    //{
                    //    testdata= BodyFatHelper.CalcBodyFat(testweight, testheight,ysfamily.ADAge, ysfamily.imp, ysfamily.Sex);
                    //    var tmpdata = new MeasureModels
                    //    {
                    //        fat_r = testdata.fat_r,
                    //        muscle = testdata.muscle,
                    //        water = testdata.water,
                    //        bone = testdata.bone,
                    //        kcal = testdata.kcal,
                    //        fat_w = testdata.fat_w,
                    //        visceral = testdata.visceral,
                    //        protein = testdata.protein,
                    //        bodyage = testdata.bodyage,
                    //        bmi = testdata.bmi,
                    //        sfr = testdata.sfr,
                    //        muscleval = testdata.muscleval,
                    //        proteinval = testdata.proteinval,
                    //        lbm = testdata.lbm,
                    //        body = testdata.body,
                    //        fatlevlval = testdata.fatlevlval,
                    //        weight = testweight.ToDecimal(),
                    //        timestamp = DateTime.Now.AddDays(-i).ToString()
                    //    };
                    //    yslistcnt.Add(tmpdata);
                    //    yslistday.Add(tmpdata);
                    //    testweight -= 1;
                    //    testheight -= 1;
                    //}
                    //double lheight = (ysfamily.ADHeight - 2).ToDouble();
                    //var yslevelresult = BodyFatHelper.CalcBodyFat(65, lheight, ysfamily.ADAge, ysfamily.imp, ysfamily.Sex);
                    //var yslist = HisList(ysfamily.Sex, yslistcnt, yslistday, ysfamily.ADAge, ysdata, yslevelresult, ysfamily.ADWeight);
                    //#endregion
                    //return new ResultInfo(ResultState.SUCCESS, "success", new UserMeasureInfo
                    //{
                    //    IsTest = true,
                    //    bmi = ysdata.bmi,
                    //    sfr = ysdata.sfr,
                    //    sfrLevel = ysdata.sfrLevel,
                    //    standardbmi = ysdata.standardbmi,
                    //    standardbody = ysdata.standardbody,
                    //    standardbodyage = ysdata.standardbodyage,
                    //    standardbone = ysdata.standardbone,
                    //    standardfatlevel = ysdata.standardfatlevel,
                    //    standardfat_r = ysdata.standardfat_r,
                    //    standardfat_w = ysdata.standardfat_w,
                    //    standardkcal = ysdata.standardkcal,
                    //    standardlbm = ysdata.standardlbm,
                    //    standardmuscle = ysdata.standardmuscle,
                    //    standardmuscleval = ysdata.standardmuscleval,
                    //    standardprotein = ysdata.standardprotein,
                    //    standardproteinval = ysdata.standardproteinval,
                    //    standardsfr = ysdata.standardsfr,
                    //    standardviscera = ysdata.standardviscera,
                    //    standardwater = ysdata.standardwater,
                    //    standardWeight = ysdata.standardWeight,
                    //    bmiLevel = ysdata.bmiLevel,
                    //    body = ysdata.body,
                    //    bodyage = ysdata.bodyage,
                    //    bodyageLevel = ysdata.bodyageLevel,
                    //    bodylevel = ysdata.bodylevel,
                    //    bone = ysdata.bone,
                    //    boneLevel = ysdata.boneLevel,
                    //    cmi = ysdata.cmi,
                    //    fatLevel = ysdata.fatLevel,
                    //    fatlevlval = ysdata.fatlevlval,
                    //    fat_r = ysdata.fat_r,
                    //    fat_rLevel = ysdata.fat_rLevel,
                    //    fat_w = ysdata.fat_w,
                    //    fat_wLevel = ysdata.fat_wLevel,
                    //    Height =ysfamily.ADHeight,
                    //    kcal = ysdata.kcal,
                    //    kcalLevel = ysdata.kcalLevel,
                    //    lbm = ysdata.lbm,
                    //    muscle = ysdata.muscle,
                    //    muscleLevel = ysdata.muscleLevel,
                    //    muscleval = ysdata.muscleval,
                    //    musulevalLevel = ysdata.musulevalLevel,
                    //    protein = ysdata.protein,
                    //    proteinLevel = ysdata.proteinLevel,
                    //    proteinval = ysdata.proteinval,
                    //    proteinvalLevel = ysdata.proteinvalLevel,
                    //    visceral = ysdata.visceral,
                    //    visceralLevel = ysdata.visceralLevel,
                    //    water = ysdata.water,
                    //    waterLevel = ysdata.waterLevel,
                    //    Weight = ysfamily.ADWeight,
                    //    list = yslist
                    //});
                    return new ResultInfo(ResultState.NORESULT, "未找到测量数据");
                }
                var result = await dbClient.Queryable<YB_ResultExt>().Where(x => SqlFunc.Subqueryable<YB_Measure>().Where(e => e.ResultId == x.ResultId && e.FamilyId == family.Id).Any())
                    .OrderBy(x => x.CreateTime, OrderByType.Desc)
                    .FirstAsync();

                var data = BodyFatHelper.CalcBodyFat(result.Weight.ToDouble(), model.height.ToDouble(), age, result.Imp.ToInt(), model.sex);
                var returndata = new UserMeasureInfo
                {
                    bmi = data.bmi,
                    bmiLevel = data.bmiLevel,
                    body = data.body,
                    bodyage = data.bodyage,
                    bodyageLevel = data.bodyageLevel,
                    bodylevel = data.bodylevel,
                    bone = data.bone,
                    boneLevel = data.boneLevel,
                    cmi = data.cmi,
                    fatLevel = data.fatLevel,
                    fatlevlval = data.fatlevlval,
                    fat_r = data.fat_r,
                    fat_rLevel = data.fat_rLevel,
                    fat_w = data.fat_w,
                    fat_wLevel = data.fat_wLevel,
                    kcal = data.kcal,
                    kcalLevel = data.kcalLevel,
                    lbm = data.lbm,
                    muscle = data.muscle,
                    muscleLevel = data.muscleLevel,
                    muscleval = data.muscleval,
                    musulevalLevel = data.musulevalLevel,
                    protein = data.protein,
                    proteinLevel = data.proteinLevel,
                    proteinval = data.proteinval,
                    proteinvalLevel = data.proteinvalLevel,
                    sfr = data.sfr,
                    sfrLevel = data.sfrLevel,
                    standardbmi = data.standardbmi,
                    standardbody = data.standardbody,
                    standardbodyage = data.standardbodyage,
                    standardbone = data.standardbone,
                    standardfatlevel = data.standardfatlevel,
                    standardfat_r = data.standardfat_r,
                    standardfat_w = data.standardfat_w,
                    standardkcal = data.standardkcal,
                    standardlbm = data.standardlbm,
                    standardmuscle = data.standardmuscle,
                    standardmuscleval = data.standardmuscleval,
                    standardprotein = data.standardprotein,
                    standardproteinval = data.standardproteinval,
                    standardsfr = data.standardsfr,
                    standardviscera = data.standardviscera,
                    standardwater = data.standardwater,
                    standardWeight = data.standardWeight,
                    visceral = data.visceral,
                    visceralLevel = data.visceralLevel,
                    water = data.water,
                    waterLevel = data.waterLevel,
                    Height = model.height,
                    Weight = result.Weight
                };
                #region 更新测量结果
                int month = model.birthday.ToMonth();
                await dbClient.Ado.UseStoredProcedure().ExecuteCommandAsync("proc_insertresult", new
                {
                    sex = family.Sex,
                    age = family.Age,
                    month = month,
                    height = model.height,
                    weight = result.Weight,
                    imp = result.Imp,
                    ecode = result.Ecode,
                    familyid = model.familyid,
                    userid = authInfo.UserId,
                    fat_r = data.fat_r,
                    muscle = data.muscle,
                    water = data.water,
                    bone = data.bone,
                    kcal = data.kcal,
                    fat_w = data.fat_w,
                    visceral = data.visceral,
                    protein = data.protein,
                    bodyage = data.bodyage,
                    bmi = data.bmi,
                    cmi = data.cmi,
                    sfr = data.sfr,
                    muscleval = data.muscleval,
                    proteinval = data.proteinval,
                    lbm = data.lbm,
                    body = data.bodylevel,
                    fatlevel = data.fatLevel,
                    resultid = result.ResultId
                });
                #endregion
                //获取每项的历史值
                var dataset = await dbClient.Ado.UseStoredProcedure().GetDataSetAllAsync("proc_getmeasureitem_page", new
                {
                    pagesize = model.pagesize,
                    pagenum = model.pagenum,
                    familyid = model.familyid
                });
                if (dataset.Tables.Count == 0)
                {
                    returndata.list = new List<MeasureInfoItem>();
                }
                else
                {
                    //BMI标准,最大值,最小值,标准范围
                    var listcnt = DataTableListHelper.ToList<MeasureModels>(dataset.Tables[0]);
                    var listday = DataTableListHelper.ToList<MeasureModels>(dataset.Tables[1]);
                    //最近的上上次测量结果
                    var lastresult = await dbClient.Queryable<YB_ResultExt>().Where(x => SqlFunc.Subqueryable<YB_Measure>().Where(e => e.ResultId == x.ResultId && e.FamilyId == family.Id).Any() && x.ResultId != result.ResultId)
                        .OrderBy(x => x.CreateTime, OrderByType.Desc)
                        .FirstAsync();
                    UserMeasureModel levelresult = new UserMeasureModel();
                    if (lastresult != null)
                    {
                        var mresult = await dbClient.Queryable<YB_Measure>().Where(x => x.ResultId == lastresult.ResultId).FirstAsync();
                        levelresult = BodyFatHelper.CalcBodyFat(lastresult.Weight.ToDouble(), mresult.Height.ToDouble(), mresult.Age, lastresult.Imp.ToInt(), mresult.Sex);
                    }
                    returndata.list = HisList(model.sex,listcnt,listday,age,data,levelresult,result.Weight);
                }
                return new ResultInfo(ResultState.SUCCESS, "success", returndata);
            }
        }
        /// <summary>
        /// 历史记录分类
        /// </summary>
        /// <param name="sex"></param>
        /// <param name="listcnt"></param>
        /// <param name="listday"></param>
        /// <param name="age"></param>
        /// <param name="data"></param>
        /// <param name="levelresult"></param>
        /// <param name="weight"></param>
        /// <returns></returns>
        private List<MeasureInfoItem> HisList(int sex,List<MeasureModels> listcnt,List<MeasureModels> listday,int age,UserMeasureModel data, UserMeasureModel levelresult,decimal weight)
        {
            List<MeasureInfoItem> info = new List<MeasureInfoItem>();
            List<string> mlist = new List<string> { "bmi", "fat_r", "muscle", "water", "bone", "kcal", "fat_w", "visceral", "protein", "bodyage","sfr","body",
                        "muscleval","proteinval","lbm","fatlevel","weight" };
            //判定时sex为0-女，1-男，所以这里进行转换
            sex = sex == 2 ? 0 : 1;
            mlist.ForEach(x =>
            {
                var m = new MeasureInfoItem()
                {
                    name = x
                };
                if (x == "bmi")
                {
                    m.list = listcnt.Select(e => new MeasureHisItem { value = e.bmi.ToString(), time = e.timestamp.ToYearDate() }).ToList();
                    m.daylist = listday.Select(e => new MeasureHisItem { value = e.bmi.ToString(), time = e.timestamp.ToYearDate() }).ToList();
                    m.slist = BodyFatHelper.bmi_value(sex, age);
                    m.value = data.bmi;
                    m.lastvalue = m.value - levelresult.bmi;
                }
                else if (x == "fat_r")
                {
                    m.list = listcnt.Select(e => new MeasureHisItem { value = e.fat_r.ToString(), time = e.timestamp.ToYearDate() }).ToList();
                    m.daylist = listday.Select(e => new MeasureHisItem { value = e.fat_r.ToString(), time = e.timestamp.ToYearDate() }).ToList();
                    m.slist = BodyFatHelper.fa_r_value(sex, age);
                    m.value = data.fat_r;
                    m.lastvalue = m.value - levelresult.fat_r;
                }
                else if (x == "muscle")
                {
                    m.list = listcnt.Select(e => new MeasureHisItem { value = e.muscle.ToString(), time = e.timestamp.ToYearDate() }).ToList();
                    m.daylist = listday.Select(e => new MeasureHisItem { value = e.muscle.ToString(), time = e.timestamp.ToYearDate() }).ToList();
                    m.slist = BodyFatHelper.muscle_value(sex, age);
                    m.value = data.muscle;
                    m.lastvalue = m.value - levelresult.muscle;
                }
                else if (x == "water")
                {
                    m.list = listcnt.Select(e => new MeasureHisItem { value = e.water.ToString(), time = e.timestamp.ToYearDate() }).ToList();
                    m.daylist = listday.Select(e => new MeasureHisItem { value = e.water.ToString(), time = e.timestamp.ToYearDate() }).ToList();
                    m.slist = BodyFatHelper.water_value(sex, age);
                    m.value = data.water;
                    m.lastvalue = m.value - levelresult.water;
                }
                else if (x == "bone")
                {
                    m.list = listcnt.Select(e => new MeasureHisItem { value = e.bone.ToString(), time = e.timestamp.ToYearDate() }).ToList();
                    m.daylist = listday.Select(e => new MeasureHisItem { value = e.bone.ToString(), time = e.timestamp.ToYearDate() }).ToList();
                    m.slist = BodyFatHelper.bone_value(sex, age, weight);
                    m.value = data.bone;
                    m.lastvalue = m.value - levelresult.bone;
                }
                else if (x == "kcal")
                {
                    m.list = listcnt.Select(e => new MeasureHisItem { value = e.kcal.ToString(), time = e.timestamp.ToYearDate() }).ToList();
                    m.daylist = listday.Select(e => new MeasureHisItem { value = e.kcal.ToString(), time = e.timestamp.ToYearDate() }).ToList();
                    m.slist = BodyFatHelper.kcal_value(sex, age, weight);
                    m.value = data.kcal;
                    m.lastvalue = m.value - levelresult.kcal;
                }
                else if (x == "fat_w")
                {
                    m.list = listcnt.Select(e => new MeasureHisItem { value = e.fat_w.ToString(), time = e.timestamp.ToYearDate() }).ToList();
                    m.daylist = listday.Select(e => new MeasureHisItem { value = e.fat_w.ToString(), time = e.timestamp.ToYearDate() }).ToList();
                    m.value = data.fat_w;
                    m.lastvalue = m.value - levelresult.fat_w;
                }
                else if (x == "visceral")
                {
                    m.list = listcnt.Select(e => new MeasureHisItem { value = e.visceral.ToString(), time = e.timestamp.ToYearDate() }).ToList();
                    m.daylist = listday.Select(e => new MeasureHisItem { value = e.visceral.ToString(), time = e.timestamp.ToYearDate() }).ToList();
                    m.slist = BodyFatHelper.visceral_value(sex, age);
                    m.value = data.visceral;
                    m.lastvalue = m.value - levelresult.visceral;
                }
                else if (x == "protein")
                {
                    m.list = listcnt.Select(e => new MeasureHisItem { value = e.protein.ToString(), time = e.timestamp.ToYearDate() }).ToList();
                    m.daylist = listday.Select(e => new MeasureHisItem { value = e.protein.ToString(), time = e.timestamp.ToYearDate() }).ToList();
                    m.slist = BodyFatHelper.protein_value(sex, age);
                    m.value = data.protein;
                    m.lastvalue = m.value - levelresult.protein;
                }
                else if (x == "bodyage")
                {
                    m.list = listcnt.Select(e => new MeasureHisItem { value = e.bodyage.ToString(), time = e.timestamp.ToYearDate() }).ToList();
                    m.daylist = listday.Select(e => new MeasureHisItem { value = e.bodyage.ToString(), time = e.timestamp.ToYearDate() }).ToList();
                    m.value = data.bodyage;
                    m.lastvalue = m.value - levelresult.bodyage;
                }
                else if (x == "sfr")
                {
                    m.list = listcnt.Select(e => new MeasureHisItem { value = e.sfr.ToString(), time = e.timestamp.ToYearDate() }).ToList();
                    m.daylist = listday.Select(e => new MeasureHisItem { value = e.sfr.ToString(), time = e.timestamp.ToYearDate() }).ToList();
                    m.slist = BodyFatHelper.sfr_value(sex, age);
                    m.value = data.sfr;
                    m.lastvalue = m.value - levelresult.sfr;
                }
                else if (x == "body")
                {
                    m.list = listcnt
                    .Select(e => new MeasureHisItem { value = e.body, time = e.timestamp.ToYearDate() })
                    .ToList();
                    m.daylist = listday.Select(e => new MeasureHisItem { value = e.body, time = e.timestamp.ToYearDate() }).ToList();
                    m.value = 0;
                    m.lastvalue = 0;
                }
                else if (x == "muscleval")
                {
                    m.list = listcnt.Select(e => new MeasureHisItem { value = e.muscleval.ToString(), time = e.timestamp.ToYearDate() }).ToList();
                    m.daylist = listday.Select(e => new MeasureHisItem { value = e.muscleval.ToString(), time = e.timestamp.ToYearDate() }).ToList();
                    m.value = data.muscleval;
                    m.lastvalue = m.value - levelresult.muscleval;
                }
                else if (x == "proteinval")
                {
                    m.list = listcnt.Select(e => new MeasureHisItem { value = e.proteinval.ToString(), time = e.timestamp.ToYearDate() }).ToList();
                    m.daylist = listday.Select(e => new MeasureHisItem { value = e.proteinval.ToString(), time = e.timestamp.ToYearDate() }).ToList();
                    m.value = data.proteinval;
                    m.lastvalue = m.value - levelresult.proteinval;
                }
                else if (x == "lbm")
                {
                    m.list = listcnt.Select(e => new MeasureHisItem { value = e.lbm.ToString(), time = e.timestamp.ToYearDate() }).ToList();
                    m.daylist = listday.Select(e => new MeasureHisItem { value = e.lbm.ToString(), time = e.timestamp.ToYearDate() }).ToList();
                    m.value = data.lbm;
                    m.lastvalue = m.value - levelresult.lbm; ;
                }
                else if (x == "fatlevel")
                {
                    m.list = listcnt
                    .Select(e => new MeasureHisItem { value = BodyFatHelper.fatlevel(e.fatlevlval.ToDouble()), time = e.timestamp.ToYearDate() }).ToList();
                    m.daylist = listday.Select(e => new MeasureHisItem { value = BodyFatHelper.fatlevel(e.fatlevlval.ToDouble()), time = e.timestamp.ToYearDate() }).ToList();
                    m.value = 0;
                    m.lastvalue = 0;
                }
                else if (x == "weight")
                {
                    m.list = listcnt
                    .Select(e => new MeasureHisItem { value = e.weight.ToString(), time = e.timestamp.ToYearDate() }).ToList();
                    m.daylist = listday.Select(e => new MeasureHisItem { value = e.weight.ToString(), time = e.timestamp.ToYearDate() }).ToList();
                    m.value = data.weight;
                    m.lastvalue = m.value - levelresult.weight;
                }
                info.Add(m);
            });
            return info;
        }
    }
}
