using Performance.DtoModels;
using Performance.EntityModels;
using Performance.Infrastructure;
using Performance.Repository;
using Performance.Services.AllotCompute;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Performance.Services
{
    /// <summary>
    /// 临床科室主任
    /// </summary>
    public class ComputeDirector : IAutoInjection
    {
        private readonly BaiscNormService baiscNormService;
        private readonly PerforCofdirectorRepository perforCofdirectorRepository;
        private readonly PerforCofworkyearRepository perforCofworkyearRepository;
        private readonly PerforResaccountRepository perforResaccountRepository;
        //private readonly PerforResaccountdoctorRepository perforResAccountdoctorRepository;

        public ComputeDirector(BaiscNormService baiscNormService,
            PerforCofdirectorRepository perforCofdirectorRepository,
            PerforCofworkyearRepository perforCofworkyearRepository,
            PerforResaccountRepository perforResaccountRepository)
        {
            this.baiscNormService = baiscNormService;
            this.perforCofdirectorRepository = perforCofdirectorRepository;
            this.perforCofworkyearRepository = perforCofworkyearRepository;
            this.perforResaccountRepository = perforResaccountRepository;
        }

        #region 老版计算
        ///// <summary>
        ///// 临床科室主任、临床科室副主任、临床科室护士长 计算
        ///// </summary>
        ///// <param name="empolyeeList"></param>
        ///// <param name="nurseList"></param>
        ///// <param name="directorList"></param>
        ///// <returns></returns>
        //public List<ComputeResult> Compute(List<ComputeEmployee> empolyeeList, List<im_accountbasic> accountbasicList, per_allot allot)
        //{
        //    //规模绩效和效率绩效配置表
        //    var directorList = perforCofdirectorRepository.GetEntities(t => t.AllotID == allot.ID);
        //    //取出医生科室
        //    var doctorList = perforResAccountdoctorRepository.GetEntities(t => t.AllotID == allot.ID);
        //    //取出护士科室
        //    var nurseList = perforResAccountnurseRepository.GetEntities(t => t.AllotID == allot.ID);

        //    List<ComputeResult> computeList = new List<ComputeResult>();
        //    // 主任及护士长 对应 效率绩效/规模绩效 关系
        //    // 科室名称 确定绩效计算人员中的人群
        //    // 绩效考核基数参考对象  确定科室下那些考核对象归纳为 科室主任  护士长
        //    // 数据库存放的文本 与枚举 全文字中文匹配
        //    var basicRuleList = new[]
        //    {
        //        new { AccountUnitType = AccountUnitType.临床科室, PerforType = PerforType.临床主任, DirectorType = DirectorType.临床科室主任 },
        //        new { AccountUnitType = AccountUnitType.临床科室, PerforType = PerforType.临床副主任, DirectorType = DirectorType.临床科室副主任 },
        //        new { AccountUnitType = AccountUnitType.医技科室, PerforType = PerforType.医技主任, DirectorType = DirectorType.医技科室主任 },
        //        new { AccountUnitType = AccountUnitType.医技科室, PerforType = PerforType.医技副主任, DirectorType = DirectorType.医技科室副主任 },
        //        new { AccountUnitType = AccountUnitType.临床科室, PerforType = PerforType.护士长, DirectorType = DirectorType.临床科室护士长 },
        //    };
        //    foreach (var basicRule in basicRuleList)
        //    {
        //        var needCompute = empolyeeList.Where(t => t.AccountType == basicRule.AccountUnitType.ToString() && t.FitPeople.Trim() == EnumHelper.GetDescription(basicRule.PerforType));
        //        foreach (var item in needCompute)
        //        {
        //            var accountbasic = accountbasicList.FirstOrDefault(t => t.Department == item.Department);
        //            if (accountbasic == null) continue;

        //            //分别取出对应的 计算 人员 平均值等信息
        //            decimal? number, perforTotal, avg;
        //            if (basicRule.PerforType == PerforType.护士长)
        //            {
        //                if (!accountbasic.NurseHeadNumber.HasValue || accountbasic.NurseHeadNumber.Value == 0) continue;

        //                var resAccount = nurseList.FirstOrDefault(t => t.AccountingUnit == item.AccountingUnit);
        //                number = resAccount?.Number;
        //                perforTotal = resAccount?.PerforTotal;
        //                avg = resAccount?.Avg;
        //            }
        //            else
        //            {
        //                if (!accountbasic.DoctorDirectorNumber.HasValue || accountbasic.DoctorDirectorNumber.Value == 0) continue;

        //                var resAccount = doctorList.FirstOrDefault(t => t.AccountingUnit == item.AccountingUnit);
        //                number = resAccount?.Number;
        //                perforTotal = resAccount?.PerforTotal;
        //                avg = resAccount?.Avg;
        //            }
        //            var efficiency = (basicRule.PerforType == PerforType.护士长) ? accountbasic.NurseEffic : accountbasic.DoctorEffic;
        //            var scale = (basicRule.PerforType == PerforType.护士长) ? accountbasic.NurseScale : accountbasic.DoctorScale;
        //            var grant = (basicRule.PerforType == PerforType.护士长) ? accountbasic.NurseGrant : accountbasic.DoctorGrant;

        //            var compute = new ComputeResult
        //            {
        //                AccountType = item.AccountType,
        //                AccountingUnit = item.AccountingUnit,
        //                EmployeeName = item.DoctorName,
        //                FitPeople = item.FitPeople,
        //                JobTitle = item.JobTitle,

        //                Number = number,
        //                PerforTotal = perforTotal,
        //                Avg = avg,
        //                Efficiency = avg * (efficiency ?? 1),
        //                Scale = perforTotal * (scale ?? 1),
        //                //Grant = item.Grant ?? 1,
        //                ScoreAverageRate = item.ScoreAverageRate,
        //                Punishment = item.Punishment,
        //                OtherPerfor = item.OtherPerfor,
        //                Adjust = item.Adjust,
        //                //Workload = item.Workload
        //            };
        //            //应发管理绩效
        //            compute.ShouldGiveFee = (compute.Efficiency + compute.Scale) * grant;
        //            //绩效合计
        //            compute.PerforSumFee = compute.Avg + compute.ShouldGiveFee;
        //            //应发绩效
        //            compute.GiveFee = compute.PerforSumFee * compute.ScoreAverageRate + (item.Punishment ?? 0) + (item.OtherPerfor ?? 0);
        //            //实发绩效
        //            compute.RealGiveFee = compute.GiveFee * (item.Adjust ?? 1m);
        //            computeList.Add(compute);
        //        }

        //    }
        //    return computeList;
        //} 
        #endregion

        /// <summary>
        /// 临床科室主任、临床科室副主任、临床科室护士长 计算
        /// </summary>
        /// <param name="empolyeeList"></param>
        /// <param name="nurseList"></param>
        /// <param name="directorList"></param>
        /// <returns></returns>
        public List<ComputeResult> Compute(List<ComputeEmployee> empolyeeList, List<im_accountbasic> accountbasicList, List<PerSheet> accountSheet, per_allot allot, bool isMinimum)
        {
            var basicRuleList = new[]
            {
                new { AccountUnitType = AccountUnitType.科主任, UnitType = UnitType.医生组 },
                new { AccountUnitType = AccountUnitType.护士长, UnitType = UnitType.护理组 },
                new { AccountUnitType = AccountUnitType.科主任, UnitType = UnitType.医技组 },
            };
            //取出科室
            List<res_account> dataList = new List<res_account>();
            foreach (var account in accountSheet)
            {
                dataList.AddRange(AutoMapper.Mapper.Map<List<res_account>>(account.PerData.Select(t => (PerDataAccountBaisc)t)));
            }
            var multi = accountbasicList.GroupBy(t => new { t.UnitType, t.DoctorAccountingUnit })
                            .Select(t => new { t.Key.UnitType, t.Key.DoctorAccountingUnit, Count = t.Count(), })
                            .Where(t => t.Count > 1);
            List<ComputeResult> computeList = new List<ComputeResult>();
            foreach (var accountbasic in accountbasicList)
            {
                //if (!accountbasic.ManagerNumber.HasValue || accountbasic.ManagerNumber.Value == 0)
                //    continue;
                if ((!accountbasic.DoctorDirectorNumber.HasValue && "皮肤科" != accountbasic.DoctorAccountingUnit) || (accountbasic.DoctorDirectorNumber.Value == 0 && "皮肤科" != accountbasic.DoctorAccountingUnit))
                    continue;

                //原不存在科主任则跳过科主任绩效计算20190920新都
                //是否共用核算单元
                var isShare = multi.Any(group => group.UnitType == accountbasic.UnitType && group.DoctorAccountingUnit == accountbasic.DoctorAccountingUnit);
                if (isShare
                    && accountbasic.DoctorDirectorNumber.HasValue && accountbasic.DoctorDirectorNumber.Value < 1
                    && accountbasic.Department != accountbasic.DoctorAccountingUnit)
                    continue;
                //分别取出对应的 计算 人员 平均值等信息 
                var resAccount = dataList.Where(t => t.UnitType == accountbasic.UnitType && t.AccountingUnit == accountbasic.DoctorAccountingUnit);
                var number = resAccount.OrderByDescending(t => t.ManagerNumber).Sum(t => t.ManagerNumber + t.Number);
                var perforTotal = resAccount.Sum(t => t.PerforTotal);
                //var avg = resAccount.Average(t => t.Avg);
                //绩效参考标准，不使用实发绩效             
                //var realAvg = resAccount.Sum(t => (t.ManagerNumber + t.Number) == 0 ? 0 : t.RealGiveFee / (t.ManagerNumber + t.Number)) / resAccount.Count();
                //var realAvg = resAccount.Sum(t => t.Number + t.ManagerNumber) == 0 ? 0 : resAccount.Sum(t => t.RealGiveFee) / resAccount.Sum(t => t.Number + t.ManagerNumber);
                decimal? realAvg = 0;
                bool isAvg = true;
                //if ("内五科" == accountbasic.DoctorAccountingUnit && isShare)
                //    realAvg = resAccount.Sum(r => r.Number + r.ManagerNumber) == 0 ? 0 : resAccount.Sum(r => r.RealGiveFee) / resAccount.Sum(r => r.Number);
                //else
                //{
                foreach (var item in resAccount)
                {
                    if ((item.ManagerNumber + item.Number) == 0)
                    {
                        isAvg = false;
                        realAvg = resAccount.Sum(r => r.Number + r.ManagerNumber) == 0 ? 0 : resAccount.Sum(r => r.RealGiveFee) / resAccount.Sum(r => r.Number + r.ManagerNumber);
                        break;
                    }
                    else
                    {
                        realAvg += item.RealGiveFee / (item.ManagerNumber + item.Number);
                    }
                }
                if (isAvg)
                    realAvg = realAvg / resAccount.Count();
                //}

                var realGiveFee = resAccount.Sum(t => t.RealGiveFee);


                var basicRule = basicRuleList.FirstOrDefault(t => t.UnitType == (UnitType)accountbasic.UnitType);
                if (basicRule == null) continue;
                var empolyee = empolyeeList.FirstOrDefault(t => t.AccountType == basicRule.AccountUnitType.ToString() && t.AccountingUnit == accountbasic.DoctorAccountingUnit);

                if (empolyee == null)
                {
                    empolyee = new ComputeEmployee
                    {
                        AccountType = basicRule.AccountUnitType.ToString(),
                        DoctorName = "人员信息缺失",
                        FitPeople = "",
                        ScoreAverageRate = 1,
                        Punishment = 0,
                        OtherPerfor = 0,
                        Adjust = 1,
                    };
                }
                var compute = new ComputeResult
                {
                    UnitType = basicRule.UnitType.ToString(),
                    AccountingUnit = accountbasic.DoctorAccountingUnit,

                    AccountType = empolyee.AccountType,
                    EmployeeName = empolyee.DoctorName,
                    FitPeople = empolyee.FitPeople,
                    JobTitle = empolyee.JobTitle,

                    ScoreAverageRate = empolyee.ScoreAverageRate,
                    Punishment = empolyee.Punishment,
                    OtherPerfor = empolyee.OtherPerfor,

                    Number = number,
                    PerforTotal = realGiveFee,
                    Avg = realAvg,
                    Efficiency = realAvg * (accountbasic.DoctorEffic ?? 1),
                    Scale = perforTotal * (accountbasic.DoctorScale ?? 1),
                    Adjust = empolyee.Adjust,
                    Remark = isShare ? "特殊科室主任，共用核算单元" : ""
                };
                //应发管理绩效
                compute.ShouldGiveFee = (compute.Efficiency + compute.Scale) * accountbasic.DoctorGrant;
                //绩效合计
                compute.PerforSumFee = compute.Avg + compute.ShouldGiveFee;
                //应发绩效
                compute.GiveFee = compute.PerforSumFee;
                //实发绩效
                compute.RealGiveFee = (compute.GiveFee * compute.ScoreAverageRate + (compute.Punishment ?? 0) + (compute.OtherPerfor ?? 0)) * (compute.Adjust ?? 1m);
                // 参考基数专用绩效合计
                compute.BaiscNormPerforTotal = compute.RealGiveFee;

                computeList.Add(compute);
            }
            return computeList;
        }



        /// <summary>
        /// 院领导、业务中层、工勤人员 计算
        /// </summary>
        /// <param name="empolyeeList"></param>
        /// <param name="baiscnormList"></param>
        /// <returns></returns>
        public List<ComputeResult> Compute(List<ComputeEmployee> empolyeeList, per_allot allot, List<res_baiscnorm> baiscnormList)
        {
            //年资系数
            var workyearList = perforCofworkyearRepository.GetEntities(t => t.AllotID == allot.ID);

            List<ComputeResult> computeList = new List<ComputeResult>();

            List<string> involve = new List<string> { AccountUnitType.行政高层.ToString(), AccountUnitType.行政中层.ToString(), AccountUnitType.行政工勤.ToString() };
            var needCompute = empolyeeList.Where(t => involve.Contains(t.AccountType));

            if (!needCompute.Any()) return computeList;

            var perforTypeArray = EnumHelper.GetItems<PerforType>();
            foreach (var item in needCompute)
            {
                var compute = new ComputeResult
                {
                    AccountType = item.AccountType,
                    AccountingUnit = item.AccountingUnit,
                    EmployeeName = item.DoctorName,
                    FitPeople = item.FitPeople,
                    //Grant = item.Grant ?? 1,
                    WorkTime = item.WorkTime,
                    PostCoefficient = item.PostCoefficient,
                    Attendance = item.Attendance,
                    ScoreAverageRate = item.ScoreAverageRate,
                    Punishment = item.Punishment,
                    OtherPerfor = item.OtherPerfor,
                    JobTitle = item.JobTitle,
                    Adjust = item.Adjust,
                    //Workload = item.Workload

                };
                decimal? baiscnorm = 1;
                var perforTypeItem = perforTypeArray.FirstOrDefault(t => t.Description == item.FitPeople);
                if (perforTypeItem != null)
                {
                    var perforType = (PerforType)perforTypeItem.Value;
                    baiscnorm = baiscNormService.GetBaiscNorm(baiscnormList, perforType);

                    //年资系数
                    if (item.FitPeople == AccountUnitType.行政工勤.ToString() && item.WorkTime.HasValue && item.WorkTime.Value > new DateTime(1970, 1, 1))
                    {
                        var years = ((DateTime.Now.Year - item.WorkTime.Value.Year) * 12 + (DateTime.Now.Month - item.WorkTime.Value.Month)) / 12.0m;
                        var value = workyearList.FirstOrDefault(t => t.MinRange < years && years <= t.MaxRange)?.Value;
                        compute.WorkYear = value;
                    }
                }
                //添加参数计算
                compute.BaiscNormValue = baiscnorm * (item.FitPeopleRatio == null || item.FitPeopleRatio == 0 ? 1 : item.FitPeopleRatio);
                //应发绩效
                compute.GiveFee = compute.BaiscNormValue * compute.PostCoefficient * (compute.WorkYear ?? 1) * compute.Attendance * compute.ScoreAverageRate
                   + (compute.OtherPerfor ?? 0) + (compute.Punishment ?? 0);
                //实发绩效
                compute.RealGiveFee = compute.GiveFee * (item.Adjust ?? 1);
                computeList.Add(compute);
            }

            return computeList;
        }
    }


}
