using AutoMapper;
using Microsoft.Extensions.Logging;
using Performance.DtoModels;
using Performance.EntityModels;
using Performance.Infrastructure;
using Performance.Repository;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Performance.Services.AllotCompute
{
    /// <summary>
    /// 最终绩效计算
    /// </summary>
    public class ResultComputeService : IAutoInjection
    {
        private readonly BaiscNormService baiscNormService;
        private readonly ComputeDirector computeDirector;
        private readonly BudgetService budgetService;
        private readonly PerforPeremployeeRepository perforPeremployeeRepository;
        private readonly PerforPerallotRepository perforPerallotRepository;
        private readonly PerforAgcomputeRepository perforAgcomputeRepository;
        private readonly PerforAgsecondallotRepository perforAgsecondallotRepository;
        private readonly PerforResreservedRepository perforresreservedRepository;
        private readonly PerforHospitalRepository hospitalRepository;
        private readonly PerforImemployeeRepository perforImEmployeeRepository;
        private readonly PerforRescomputeRepository perforRescomputeRepository;
        private readonly PerforResbaiscnormRepository perforResbaiscnormRepository;
        private readonly PerforResspecialunitRepository perforResspecialunitRepository;
        private readonly PerforImaccountbasicRepository perforImaccountbasicRepository;
        private readonly PerforResaccountRepository perforResaccountRepository;
        private readonly LogManageService logManageService;
        private readonly PerforImemployeeclinicRepository perforImemployeeclinicRepository;
        private readonly PerforImemployeelogisticsRepository perforImemployeelogisticsRepository;
        private readonly ILogger logger;

        public ResultComputeService(
            PerforHospitalRepository hospitalRepository,
            PerforImemployeeRepository perforImEmployeeRepository,
            PerforRescomputeRepository perforRescomputeRepository,
            PerforResbaiscnormRepository perforResbaiscnormRepository,
            PerforResspecialunitRepository perforResspecialunitRepository,
            PerforImaccountbasicRepository perforImaccountbasicRepository,
            PerforResaccountRepository perforResaccountRepository,
            BaiscNormService baiscNormService, ComputeDirector computeDirector,
            LogManageService logManageService, BudgetService budgetService,
            PerforPeremployeeRepository perforPeremployeeRepository,
            PerforPerallotRepository perforPerallotRepository,
            PerforAgcomputeRepository perforAgcomputeRepository,
            PerforAgsecondallotRepository perforAgsecondallotRepository,
            PerforResreservedRepository perforresreservedRepository,
            PerforImemployeeclinicRepository perforImemployeeclinicRepository,
            PerforImemployeelogisticsRepository perforImemployeelogisticsRepository,
            ILogger<ResultComputeService> logger)
        {
            this.baiscNormService = baiscNormService;
            this.computeDirector = computeDirector;
            this.hospitalRepository = hospitalRepository;
            this.perforImEmployeeRepository = perforImEmployeeRepository;
            this.perforRescomputeRepository = perforRescomputeRepository;
            this.perforResbaiscnormRepository = perforResbaiscnormRepository;
            this.perforResspecialunitRepository = perforResspecialunitRepository;
            this.perforImaccountbasicRepository = perforImaccountbasicRepository;
            this.perforResaccountRepository = perforResaccountRepository;
            this.logManageService = logManageService;
            this.budgetService = budgetService;
            this.perforPeremployeeRepository = perforPeremployeeRepository;
            this.perforPerallotRepository = perforPerallotRepository;
            this.perforAgcomputeRepository = perforAgcomputeRepository;
            this.perforAgsecondallotRepository = perforAgsecondallotRepository;
            this.perforresreservedRepository = perforresreservedRepository;
            this.perforImemployeeclinicRepository = perforImemployeeclinicRepository;
            this.perforImemployeelogisticsRepository = perforImemployeelogisticsRepository;
            this.logger = logger;
        }

        /// <summary>
        /// 计算最终数据
        /// </summary>
        /// <param name="excel"></param>
        public List<res_baiscnorm> Compute(per_allot allot, List<PerSheet> accountSheet)
        {
            //取出人员信息
            var empolyeeList = perforImemployeeclinicRepository.GetEntities(t => t.AllotID == allot.ID);
            var accountbasicList = perforImaccountbasicRepository.GetEntities(t => t.AllotID == allot.ID);

            List<ComputeEmployee> computeEmployees = Mapper.Map<List<ComputeEmployee>>(empolyeeList);

            logManageService.WriteMsg("正在生成绩效", "科室主任、护士长 最终绩效数据计算", 1, allot.ID, "ReceiveMessage");
            var computResult = computeDirector.Compute(computeEmployees, accountSheet, allot);
            //计算 绩效标准 基数（科主任、副主任、护士长 =>> 平均值）
            List<res_baiscnorm> baiscnormList = new List<res_baiscnorm>();
            baiscNormService.ComputeAvg(baiscnormList, computeEmployees, computResult);
            baiscNormService.DocterNurseBaiscnorm(baiscnormList, accountbasicList, accountSheet);

            var empolyeeList2 = perforImEmployeeRepository.GetEntities(t => t.AllotID == allot.ID);
            var computeEmployees2 = Mapper.Map<List<ComputeEmployee>>(empolyeeList2);
            logManageService.WriteMsg("正在生成绩效", "行政中高层 最终绩效数据计算", 1, allot.ID, "ReceiveMessage");
            var computResult2 = computeDirector.Compute(computeEmployees2, allot, baiscnormList);

            var empolyeeList3 = perforImemployeelogisticsRepository.GetEntities(t => t.AllotID == allot.ID);
            var computeEmployees3 = Mapper.Map<List<ComputeEmployee>>(empolyeeList3);
            logManageService.WriteMsg("正在生成绩效", "行政后勤 最终绩效数据计算", 1, allot.ID, "ReceiveMessage");
            var computResult3 = computeDirector.Compute(computeEmployees3, allot, baiscnormList);

            //计算 行政中高层 平均值
            baiscNormService.ComputeOtherAvg(baiscnormList, computResult2, empolyeeList2);
            //计算 行政人员 平均值
            baiscNormService.ComputeOtherAvg(baiscnormList, computResult3, empolyeeList3);

            var computes = Mapper.Map<List<res_compute>>(computResult);
            computes.AddRange(Mapper.Map<List<res_compute>>(computResult2));
            computes.AddRange(Mapper.Map<List<res_compute>>(computResult3));
            computes.ForEach(t => t.AllotID = allot.ID);
            perforRescomputeRepository.AddRange(computes.ToArray());

            baiscnormList.ForEach(t => t.AllotID = allot.ID);
            logManageService.WriteMsg("正在生成绩效", "保存最终绩效数据", 1, allot.ID, "ReceiveMessage");

            return baiscnormList;
        }

        /// <summary>
        /// 特殊科室绩效计算
        /// </summary>
        /// <param name="excel"></param>
        /// <param name="allot"></param>
        public void SpecialUnitCompute(PerExcel excel, per_allot allot, List<res_baiscnorm> baiscnormList)
        {
            var isBudget = budgetService.GetAdjustAndGrant(allot, out decimal adjust, out decimal grant);
            var typeList = EnumHelper.GetItems<PerforType>();

            var specialUnit = excel.PerSheet.FirstOrDefault(t => t.SheetType == SheetType.SpecialUnit);
            if (specialUnit == null || specialUnit.PerData.Count == 0)
                return;

            var dataList = CalculateSpecialUnit(specialUnit, allot, baiscnormList, typeList);

            //取出科室
            var accountList = excel.PerSheet.FirstOrDefault(t => t.SheetType == SheetType.AccountBasic)?.PerData?.Select(t => (PerDataAccountBaisc)t);
            var adjustLaterOtherFee = excel.PerSheet.FirstOrDefault(t => t.SheetType == SheetType.AccountAdjustLaterOtherFee)?.PerData?.Select(t => (PerData)t);

            List<res_specialunit> resDataList = new List<res_specialunit>();

            var groupSpeList = dataList.GroupBy(t => t.AccountingUnit).Select(t => new { AccountingUnit = t.Key, Number = t.OrderBy(w => w.RowNumber).FirstOrDefault().Number, });

            var empolyeeList = perforImemployeeclinicRepository.GetEntities(t => t.AllotID == allot.ID && t.UnitType == UnitType.特殊核算组.ToString());
            List<ComputeEmployee> computeEmployees = Mapper.Map<List<ComputeEmployee>>(empolyeeList);
            List<ComputeResult> computeList = new List<ComputeResult>();

            foreach (var group in groupSpeList)
            {
                // 获取科室测算信息
                var dept = accountList?.FirstOrDefault(t => t.UnitType == UnitType.特殊核算组.ToString() && t.AccountingUnit == group.AccountingUnit);
                //获取需要聚合的科室
                var accountDataList = dataList.Where(t => t.AccountingUnit == group.AccountingUnit);
                //计算量化指标子项合计
                var sumValue = accountDataList.Sum(t =>
                {
                    // 新都医院在特殊科室计算时，如果取核算基数计算时带入人数计算
                    decimal? headcount = null;
                    if (typeList.Any(o => o.Description == t.QuantitativeIndicators))
                        headcount = group.Number;
                    if (!string.IsNullOrEmpty(t.QuantitativeIndicators) && t.QuantitativeIndicators.LastIndexOf("人均绩效") > -1)
                        headcount = group.Number;
                    if (!headcount.HasValue || headcount == 0)
                        headcount = 1;
                    return t.Quantity * t.QuantitativeIndicatorsValue * headcount;
                });

                foreach (var item in accountDataList)
                {
                    //科室奖罚汇总结果
                    //var extra = accountExtras?.FirstOrDefault(w => w.UnitType == UnitType.特殊核算组.ToString() && w.AccountingUnit == dept?.AccountingUnit)?.TotelValue;
                    //var drugExtra = drugExtras?.FirstOrDefault(w => w.UnitType == UnitType.特殊核算组.ToString() && w.AccountingUnit == dept?.AccountingUnit)?.TotelValue;
                    //var materialsExtra = materialsExtras?.FirstOrDefault(w => w.UnitType == UnitType.特殊核算组.ToString() && w.AccountingUnit == dept?.AccountingUnit)?.TotelValue;
                    //var scoreAverage = accountScoreAverages?.FirstOrDefault(w => w.UnitType == UnitType.特殊核算组.ToString() && w.AccountingUnit == dept?.AccountingUnit)?.TotelValue;

                    // 夜班绩效 从医院奖罚的明细项中获取
                    var nightShift = adjustLaterOtherFee?.FirstOrDefault(w => w.UnitType == dept.UnitType && w.AccountingUnit == dept.AccountingUnit && w.TypeName?.Trim() == "夜班绩效")?.CellValue ?? 0;

                    decimal? headcount = null;
                    if (typeList.Any(o => o.Description == item.QuantitativeIndicators))
                        headcount = group.Number;
                    if (!string.IsNullOrEmpty(item.QuantitativeIndicators) && item.QuantitativeIndicators.LastIndexOf("人均绩效") > -1)
                        headcount = group.Number;
                    if (!headcount.HasValue || headcount == 0)
                        headcount = 1;
                    //var xxx = item.Quantity * item.QuantitativeIndicatorsValue * headcount;

                    var res = new res_specialunit
                    {
                        AllotID = allot.ID,
                        AccountingUnit = group.AccountingUnit,
                        Department = group.AccountingUnit,
                        // 优先使用4.1中人数
                        Number = dept?.Number ?? group.Number,
                        QuantitativeIndicators = item.QuantitativeIndicators,
                        Quantity = item.Quantity,
                        QuantitativeIndicatorsValue = item.QuantitativeIndicatorsValue,
                        QuantitativeFee = item.Quantity * item.QuantitativeIndicatorsValue * headcount,
                        //ScoringAverage = scoreAverage.HasValue ? scoreAverage : dept?.ScoringAverage,
                        ScoringAverage = dept?.ScoringAverage ?? 1,
                        //OtherPerfor = dept?.OtherPerfor1,
                        //Punishment = (extra ?? 0),
                        //MedicineExtra = (drugExtra ?? 0),
                        //MaterialsExtra = (materialsExtra ?? 0),
                        Punishment = dept?.Extra ?? 0,
                        MedicineExtra = dept?.MedicineExtra ?? 0,
                        MaterialsExtra = dept?.MaterialsExtra ?? 0,

                        Adjust = (isBudget ? adjust : dept?.AdjustFactor) ?? 1,

                        AssessBeforeOtherFee = dept?.AssessBeforeOtherFee ?? 0,
                        AssessLaterOtherFee = dept?.AssessLaterOtherFee ?? 0,
                        AdjustLaterOtherFee = dept?.AdjustLaterOtherFee ?? 0,
                        NightShiftWorkPerforFee = nightShift,
                    };
                    logger.LogInformation($"特殊核算组-{group.AccountingUnit},sumValue:{sumValue},预算比例:{dept?.BasicFactor ?? -100}");
                    res.ResultsTotalFee = Math.Round((sumValue * (dept?.BasicFactor ?? 1m)) ?? 0);
                    res.PerforTotal = res.ResultsTotalFee + res.AssessBeforeOtherFee;
                    res.GiveFee = Math.Round((res.PerforTotal * res.ScoringAverage + res.MedicineExtra + res.MaterialsExtra + res.Punishment + res.AssessLaterOtherFee) ?? 0);
                    res.RealGiveFee = Math.Round(res.GiveFee * res.Adjust + res.AdjustLaterOtherFee ?? 0);
                    res.Avg = Math.Round((res.Number != 0 ? res.PerforTotal / res.Number : null) ?? 0);


                    resDataList.Add(res);
                }

                if (computeEmployees == null || !computeEmployees.Any()) continue;

                var empolyees = computeEmployees.Where(t => t.AccountingUnit == group.AccountingUnit);
                if (empolyees == null || !empolyees.Any()) continue;

                foreach (var empolyee in empolyees)
                {
                    var resAccount = resDataList.FirstOrDefault(t => t.AccountingUnit == empolyee.AccountingUnit);
                    if (resAccount == null)
                        continue;

                    // 优先取 实际人均绩效
                    var avg = (empolyee.FitPeopleValue.HasValue)
                        ? empolyee.FitPeopleValue
                        : resAccount.Number == 0 ? 0 : resAccount.PerforTotal / resAccount.Number;
                    var effAvg = empolyee.PermanentStaff == 0 ? 0 : resAccount.PerforTotal / empolyee.PermanentStaff;

                    var empolyeeAdjust = isBudget ? adjust : empolyee.Adjust;
                    var compute = new ComputeResult
                    {
                        UnitType = UnitType.特殊核算组.ToString(),
                        AccountingUnit = group.AccountingUnit,

                        AccountType = AccountUnitType.科主任.ToString(),
                        EmployeeName = empolyee.DoctorName,
                        FitPeople = empolyee.FitPeople,
                        JobTitle = empolyee.JobTitle,
                        JobNumber = empolyee.JobNumber,
                        ScoreAverageRate = empolyee.ScoreAverageRate,
                        Punishment = empolyee.Punishment ?? 0,
                        //OtherPerfor = empolyee.OtherPerfor,
                        OtherManagePerfor = empolyee?.OtherManagePerfor ?? 0,
                        Number = resAccount.Number,
                        PermanentStaff = empolyee.PermanentStaff,
                        PerforTotal = resAccount.PerforTotal,
                        Adjust = empolyeeAdjust ?? 1m,
                        Grant = isBudget ? grant : empolyee.Management,
                        Attendance = empolyee.Attendance ?? 0,
                        AssessBeforeOtherFee = empolyee?.AssessBeforeOtherFee ?? 0,
                        AssessLaterOtherFee = empolyee?.AssessLaterOtherFee ?? 0,
                        AdjustLaterOtherFee = empolyee?.AdjustLaterOtherFee ?? 0,
                        Efficiency = effAvg * (empolyee.Efficiency ?? 0),
                        Scale = resAccount.PerforTotal * (empolyee.Scale ?? 0),
                    };

                    compute.Avg = avg * (empolyee.Basics ?? 0) * compute.Attendance;
                    // 考核前管理绩效
                    compute.ShouldGiveFee = Math.Round((compute.Efficiency + compute.Scale) * compute.Grant + compute.OtherManagePerfor ?? 0);
                    // 考核后管理绩效
                    compute.AssessLaterManagementFee = Math.Round(compute.ShouldGiveFee * compute.ScoreAverageRate * compute.Attendance + compute.Punishment ?? 0);
                    // 考核前绩效
                    compute.PerforSumFee = compute.Attendance == 0 ? Math.Round(compute.ShouldGiveFee ?? 0) : Math.Round(compute.Avg / compute.Attendance + compute.ShouldGiveFee ?? 0);
                    // 考核后绩效
                    compute.GiveFee = Math.Round(compute.Avg + compute.AssessLaterManagementFee ?? 0);
                    // 参考基数专用绩效合计
                    compute.BaiscNormPerforTotal = compute.PerforSumFee;
                    // 实发绩效
                    compute.RealGiveFee = Math.Round((compute.Avg + compute.AssessLaterManagementFee) * compute.Adjust + compute.AdjustLaterOtherFee ?? 0);

                    //compute.Efficiency = compute.Avg * (empolyee.Efficiency ?? 1);
                    //compute.Scale = compute.PerforTotal * (empolyee.Scale ?? 1);
                    ////应发管理绩效
                    //compute.ShouldGiveFee = Math.Round((compute.Efficiency + compute.Scale) * compute.Grant ?? 0);
                    ////绩效合计
                    //compute.PerforSumFee = Math.Round(compute.Avg + compute.ShouldGiveFee + compute.AssessBeforeOtherFee ?? 0);
                    ////应发绩效
                    ////compute.GiveFee = compute.PerforSumFee;
                    //compute.GiveFee = Math.Round(compute.PerforSumFee * compute.ScoreAverageRate * compute.Attendance + compute.Punishment + compute.AssessLaterOtherFee ?? 0);
                    ////实发绩效
                    ////compute.RealGiveFee = (compute.GiveFee * compute.ScoreAverageRate + (compute.Punishment ?? 0) + (compute.OtherPerfor ?? 0)) * (compute.Adjust ?? 1m);
                    //compute.RealGiveFee = Math.Round(compute.GiveFee * compute.Adjust + compute.AdjustLaterOtherFee ?? 0);
                    //// 参考基数专用绩效合计
                    //compute.BaiscNormPerforTotal = compute.PerforSumFee;

                    computeList.Add(compute);
                }
            }
            var computes = Mapper.Map<List<res_compute>>(computeList);
            computes.ForEach(t => t.AllotID = allot.ID);
            perforRescomputeRepository.AddRange(computes.ToArray());
            perforResspecialunitRepository.AddRange(resDataList.ToArray());
        }

        private IEnumerable<PerDataSpecialUnit> CalculateSpecialUnit(PerSheet specialUnit, per_allot allot, List<res_baiscnorm> baiscnormList, List<EnumItem> typeList)
        {
            var dataList = specialUnit.PerData.Select(t => (PerDataSpecialUnit)t);
            var specialEmployee = perforImemployeeclinicRepository.GetEntities(t => t.AllotID == allot.ID);

            //替换考核基数
            foreach (var item in dataList)
            {
                if (specialEmployee != null && specialEmployee.FirstOrDefault(t => t.AccountingUnit == item.AccountingUnit) != null)
                {
                    item.Efficiency = specialEmployee.FirstOrDefault(t => t.AccountingUnit == item.AccountingUnit).Efficiency ?? 1;
                    item.Scale = specialEmployee.FirstOrDefault(t => t.AccountingUnit == item.AccountingUnit).Scale ?? 1;
                    item.Management = specialEmployee.FirstOrDefault(t => t.AccountingUnit == item.AccountingUnit).Management ?? 1;
                }
                var type = typeList.FirstOrDefault(o => o.Description == item.QuantitativeIndicators);
                if (type != null)
                {
                    if (type.Value == (int)PerforType.医生护士平均)
                    {
                        var doctor = baiscNormService.GetBaiscNorm(baiscnormList, PerforType.临床医生) ?? 0;
                        var nurse = baiscNormService.GetBaiscNorm(baiscnormList, PerforType.护士) ?? 0;
                        // 添加参数计算
                        item.Quantity = item.Quantity ?? (doctor + nurse) / 2;
                    }
                    else
                    {
                        //var radio = perforImEmployeeRepository.GetEntities(p => p.FitPeople == EnumHelper.GetDescription((PerforType)type.Value) && p.AllotID == allot.ID)
                        //    ?.FirstOrDefault().FitPeopleRatio ?? 1;
                        var basic = baiscNormService.GetBaiscNorm(baiscnormList, (PerforType)type.Value);
                        // 添加参数计算
                        item.Quantity = item.Quantity ?? (basic ?? 0);
                    }
                }
            }
            return dataList;
        }

        #region 预留金额

        /// <summary>
        /// 二次绩效审核通过后修改绩效预留金额
        /// </summary>
        /// <param name="secondId"></param>
        public void SaveSecondReserved(int secondId)
        {
            var second = perforAgsecondallotRepository.GetEntity(t => t.Id == secondId);
            if (second == null)
                throw new PerformanceException("参数信息无效");

            var allot = perforPerallotRepository.GetEntity(t => t.ID == second.AllotId);
            if (allot == null)
                throw new PerformanceException("参数信息无效");

            var again = perforAgcomputeRepository.GetEntities(t => t.AllotId == allot.ID);
            if (again != null && again.Any())
            {
                var empDic = perforPeremployeeRepository.GetEntities(w => w.AllotId == allot.ID);

                var group = again.GroupBy(t => new { t.Department, t.JobNumber, t.PersonName })
                    .Select(t => new ComputeResponse
                    {
                        UnitType = second.UnitType,
                        AccountingUnit = t.Key.Department,
                        JobNumber = t.Key.JobNumber,
                        EmployeeName = t.Key.PersonName,
                        RealGiveFee = t.Sum(g => g.RealGiveFee)
                    });

                AddOrUpdate(allot, empDic, group);
            }
        }

        /// <summary>
        /// 绩效生成完成后修改绩效预留金额
        /// </summary>
        /// <param name="allot"></param>
        public void SaveReserved(per_allot allot)
        {
            var mTypes = new[] { AccountUnitType.护士长.ToString(), AccountUnitType.科主任.ToString(), AccountUnitType.行政中层.ToString(), AccountUnitType.行政高层.ToString() };

            var resComputes = perforRescomputeRepository.GetEntities(t => t.AllotID == allot.ID && mTypes.Contains(t.AccountType))?.OrderByDescending(t => t.AccountingUnit);

            if (resComputes != null && resComputes.Any())
            {
                var empDic = perforPeremployeeRepository.GetEntities(w => w.AllotId == allot.ID);

                var group = resComputes.GroupBy(t => new { t.UnitType, t.AccountingUnit, t.EmployeeName, t.JobNumber })
                      .Select(t => new ComputeResponse
                      {
                          UnitType = t.Key.UnitType,
                          AccountingUnit = t.Key.AccountingUnit,
                          EmployeeName = t.Key.EmployeeName,
                          JobNumber = t.Key.JobNumber,
                          RealGiveFee = t.Sum(g => g.RealGiveFee)
                      });
                AddOrUpdate(allot, empDic, group);
            }
        }

        private void AddOrUpdate(per_allot allot, List<per_employee> empDic, IEnumerable<ComputeResponse> group)
        {
            var reserveds = perforresreservedRepository.GetEntities(w => w.HospitalId == allot.HospitalId && w.Year == allot.Year);
            List<res_reserved> updates = new List<res_reserved>(), inserts = new List<res_reserved>();
            foreach (var item in group)
            {
                var ratio = empDic?.FirstOrDefault(w => w.PersonnelNumber == item.JobNumber)?.ReservedRatio ?? 0;
                var reserved = reserveds?.FirstOrDefault(w => w.AccountingUnit == item.AccountingUnit && w.JobNumber == item.JobNumber);
                if (reserved == null)
                {
                    reserved = new res_reserved
                    {
                        UnitType = item.UnitType,
                        HospitalId = allot.HospitalId,
                        Year = allot.Year,
                        AccountingUnit = item.AccountingUnit,
                        JobNumber = item.JobNumber,
                        EmployeeName = item.EmployeeName,
                    };
                    inserts.Add(reserved);
                }
                else
                    updates.Add(reserved);

                ChangeRealGiveFee(reserved, allot, item.RealGiveFee ?? 0, ratio);
            }
            perforresreservedRepository.AddRange(inserts.ToArray());
            perforresreservedRepository.UpdateRange(updates.ToArray());
        }

        /// <summary>
        /// 修改绩效金额
        /// </summary>
        /// <param name="reserved"></param>
        /// <param name="allot"></param>
        /// <param name="realGiveFee"></param>
        /// <param name="ratio"></param>
        private void ChangeRealGiveFee(res_reserved reserved, per_allot allot, decimal realGiveFee, decimal ratio)
        {
            if (allot.Month == 1)
            {
                reserved.JanFee = realGiveFee;
                reserved.JanRatio = ratio;
            }
            else if (allot.Month == 2)
            {
                reserved.FebFee = realGiveFee;
                reserved.FebRatio = ratio;
            }
            else if (allot.Month == 3)
            {
                reserved.MarFee = realGiveFee;
                reserved.MarRatio = ratio;
            }
            else if (allot.Month == 4)
            {
                reserved.AprFee = realGiveFee;
                reserved.AprRatio = ratio;
            }
            else if (allot.Month == 5)
            {
                reserved.MayFee = realGiveFee;
                reserved.MayRatio = ratio;
            }
            else if (allot.Month == 6)
            {
                reserved.JunFee = realGiveFee;
                reserved.JunRatio = ratio;
            }
            else if (allot.Month == 7)
            {
                reserved.JulFee = realGiveFee;
                reserved.JulRatio = ratio;
            }
            else if (allot.Month == 8)
            {
                reserved.AugFee = realGiveFee;
                reserved.AugRatio = ratio;
            }
            else if (allot.Month == 9)
            {
                reserved.SepFee = realGiveFee;
                reserved.SepRatio = ratio;
            }
            else if (allot.Month == 10)
            {
                reserved.OctFee = realGiveFee;
                reserved.OctRatio = ratio;
            }
            else if (allot.Month == 11)
            {
                reserved.NovFee = realGiveFee;
                reserved.NovRatio = ratio;
            }
            else if (allot.Month == 12)
            {
                reserved.DecFee = realGiveFee;
                reserved.DecRatio = ratio;
            }
        }

        #endregion 预留金额

        /// <summary>
        /// 创建科室二次分配
        /// </summary>
        /// <param name="allot"></param>
        public void GenerateSecondAllot(per_allot allot)
        {
            List<ag_secondallot> tempSecond = new List<ag_secondallot>();
            List<ag_secondallot> insSecond = new List<ag_secondallot>();
            List<ag_secondallot> updSecond = new List<ag_secondallot>();
            List<ag_secondallot> delSecond = new List<ag_secondallot>();

            var types = new List<int> { (int)UnitType.行政高层, (int)UnitType.行政中层, (int)UnitType.行政后勤 };
            //// 获取医院是否开启后勤二次分配
            //var hospital = hospitalRepository.GetEntity(w => w.ID == allot.HospitalId);
            //if (hospital?.IsOpenLogisticsSecondAllot != 1)
            //    types.Add((int)UnitType.行政后勤);

            var accountUnit = perforResaccountRepository.GetEntities(t => t.AllotID == allot.ID && !types.Contains(t.UnitType.Value));
            // 查询需要进行二次分配的行政后勤科室
            var xzAccountUnit = perforResaccountRepository.GetEntities(t => t.AllotID == allot.ID && t.UnitType.Value == (int)UnitType.行政后勤 && t.NeedSecondAllot == "是");
            if (xzAccountUnit != null && xzAccountUnit.Count > 0)
                (accountUnit ?? new List<res_account>()).AddRange(xzAccountUnit);

            var specialList = perforResspecialunitRepository.GetEntities(t => t.AllotID == allot.ID);

            if (accountUnit != null)
            {
                foreach (var item in accountUnit)
                {
                    if (!tempSecond.Any(f => f.UnitType == ((UnitType)item.UnitType).ToString() && f.Department == item.AccountingUnit))
                    {
                        tempSecond.Add(new ag_secondallot
                        {
                            AllotId = allot.ID,
                            Year = allot.Year,
                            Month = allot.Month,
                            UnitType = ((UnitType)item.UnitType).ToString(),
                            Department = item.AccountingUnit,
                            NightShiftWorkPerforFee = item.NightShiftWorkPerforFee,
                            RealGiveFee = item.RealGiveFee,
                        });
                    }
                }
            }
            if (specialList != null)
            {
                foreach (var item in specialList.Select(w => new { w.AccountingUnit, w.NightShiftWorkPerforFee, w.RealGiveFee }).Distinct())
                {
                    if (!tempSecond.Any(f => f.UnitType == UnitType.特殊核算组.ToString() && f.Department == item.AccountingUnit))
                    {
                        tempSecond.Add(new ag_secondallot
                        {
                            AllotId = allot.ID,
                            Year = allot.Year,
                            Month = allot.Month,
                            UnitType = UnitType.特殊核算组.ToString(),
                            Department = item.AccountingUnit,
                            NightShiftWorkPerforFee = item.NightShiftWorkPerforFee,
                            RealGiveFee = item.RealGiveFee,
                        });
                    }
                }
            }

            var secondList = perforAgsecondallotRepository.GetEntities(t => t.AllotId == allot.ID && t.Year == allot.Year && t.Month == allot.Month);

            foreach (var item in tempSecond)
            {
                var second = secondList?.FirstOrDefault(f => f.UnitType == item.UnitType && f.Department == item.Department);
                if (second == null)
                {
                    insSecond.Add(new ag_secondallot
                    {
                        AllotId = allot.ID,
                        Year = allot.Year,
                        Month = allot.Month,
                        UnitType = item.UnitType,
                        Department = item.Department,
                        RealGiveFee = item.RealGiveFee,
                        NightShiftWorkPerforFee = item.NightShiftWorkPerforFee,
                        Status = 1,
                        NursingDeptStatus = 1,
                    });
                }
                else
                {
                    var backResult = Math.Abs((second.RealGiveFee ?? 0) - (item.RealGiveFee ?? 0)) >= 0.5m
                        || Math.Abs((second.NightShiftWorkPerforFee ?? 0) - (item.NightShiftWorkPerforFee ?? 0)) >= 0.5m;
                    if (backResult && second.Status > 1)
                    {
                        second.Status = 4;
                        second.Remark = "科室绩效结果发生变更，需要重新提交";
                        second.NursingDeptStatus = 4;
                        second.NursingDeptRemark = "科室绩效结果发生变更，需要重新提交";
                    }
                    second.RealGiveFee = item.RealGiveFee;
                    second.NightShiftWorkPerforFee = item.NightShiftWorkPerforFee;
                    updSecond.Add(second);
                }
            }

            if (secondList != null && secondList.Any())
            {
                foreach (var item in secondList)
                {
                    var second = tempSecond?.FirstOrDefault(f => f.UnitType == item.UnitType && f.Department == item.Department);
                    if (second == null)
                    {
                        delSecond.Add(item);
                    }
                }
            }

            if (insSecond.Any())
                perforAgsecondallotRepository.AddRange(insSecond.ToArray());

            if (updSecond.Any())
            {
                perforAgsecondallotRepository.UpdateRange(updSecond.ToArray());

                foreach (var item in updSecond.Where(w => w.Status == 4))
                {
                    // 自动驳回，需要清空该科室历史数据 
                    var histories = perforAgcomputeRepository.GetEntities(w => w.SecondId == item.Id);
                    if (histories != null && histories.Any())
                        perforAgcomputeRepository.RemoveRange(histories.ToArray());
                }
            }
            if (delSecond.Any())
            {
                perforAgsecondallotRepository.RemoveRange(delSecond.ToArray());
            }
        }
    }
}
