using AutoMapper;
using Newtonsoft.Json.Linq;
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>
    /// 对excel导入数据进行合并、计算 并保存
    /// </summary>
    public class ProcessComputService : IAutoInjection
    {
        private readonly IMapper _mapper;
        private readonly BudgetService _budgetService;
        private PerforCofincomeRepository perforCofincomeRepository;
        private PerforPersheetRepository perforPerSheetRepository;
        private PerforImdataRepository perforImDataRepository;
        private PerforImheaderRepository perforImHeaderRepository;
        private PerforImemployeeRepository perforImEmployeeRepository;
        private PerforResaccountRepository perforResaccountRepository;
        private PerforResbaiscnormRepository perforResbaiscnormRepository;
        private PerforCofdrugtypeRepository perforCofdrugtypeRepository;
        private PerforCofworkitemRepository perforCofworkitemRepository;
        private readonly PerforRescomputeRepository perforRescomputeRepository;
        private readonly LogManageService logManageService;
        private readonly GuaranteeService guaranteeService;
        private readonly PerforHospitalRepository hospitalRepository;
        private readonly PerforPerallotRepository perallotRepository;

        public ProcessComputService(
            IMapper mapper,
            BudgetService budgetService,
            PerforCofincomeRepository perforCofincomeRepository,
            PerforPersheetRepository perforPerSheetRepository,
            PerforImdataRepository perforImDataRepository,
            PerforImheaderRepository perforImHeaderRepository,
            PerforImemployeeRepository perforImEmployeeRepository,
            PerforResaccountRepository perforResaccountRepository,
            PerforResbaiscnormRepository perforResbaiscnormRepository,
            PerforCofdrugtypeRepository perforCofdrugtypeRepository,
            PerforCofworkitemRepository perforCofworkitemRepository,
            PerforRescomputeRepository perforRescomputeRepository,
            LogManageService logManageService,
            GuaranteeService guaranteeService,
            PerforHospitalRepository hospitalRepository,
            PerforPerallotRepository perallotRepository)
        {
            _mapper = mapper;
            _budgetService = budgetService;
            this.perforCofincomeRepository = perforCofincomeRepository;
            this.perforPerSheetRepository = perforPerSheetRepository;
            this.perforImDataRepository = perforImDataRepository;
            this.perforImHeaderRepository = perforImHeaderRepository;
            this.perforImEmployeeRepository = perforImEmployeeRepository;
            this.perforResaccountRepository = perforResaccountRepository;
            this.perforResbaiscnormRepository = perforResbaiscnormRepository;
            this.perforCofdrugtypeRepository = perforCofdrugtypeRepository;
            this.perforCofworkitemRepository = perforCofworkitemRepository;
            this.perforRescomputeRepository = perforRescomputeRepository;
            this.logManageService = logManageService;
            this.guaranteeService = guaranteeService;
            this.hospitalRepository = hospitalRepository;
            this.perallotRepository = perallotRepository;
        }

        ///// <summary>
        ///// 合并计算并保存
        ///// </summary>
        ///// <param name="excel"></param>
        ///// <param name="allot"></param>
        ///// <returns></returns>
        //public List<PerSheet> MergeAndSave(PerExcel excel, List<res_baiscnorm> baiscnormList, per_allot allot)
        //{
        //    List<PerSheet> list = MergeCompute(excel, allot.ID);
        //    var baiscnormList1 = ComputeMinimum(excel, list, allot.ID);

        //    var sheet = Compute(excel, list, baiscnormList);
        //    list.AddRange(sheet);

        //    Save(list, allot.ID);
        //    return list;
        //}

        #region save

        /// <summary>
        /// 保存计算后的绩效
        /// </summary>
        /// <param name="sheet"></param>
        /// <param name="allotId"></param>
        /// <returns></returns>
        private void SaveComputeAccount(PerSheet sheet, int allotId)
        {
            var imsheet = new per_sheet { AllotID = allotId, SheetName = sheet.SheetName, Source = 2, SheetType = (int)sheet.SheetType };
            perforPerSheetRepository.Add(imsheet);

            var dataList = sheet.PerData.Select(t => (PerDataAccountBaisc)t);
            List<res_account> addList = new List<res_account>();
            foreach (var data in dataList)
            {
                var imdata = _mapper.Map<res_account>(data);
                imdata.SheetID = imsheet.ID;
                imdata.AllotID = allotId;
                addList.Add(imdata);
            }
            perforResaccountRepository.AddRange(addList.ToArray());
        }

        /// <summary>
        /// 保存通用格式
        /// </summary>
        /// <param name="sheet"></param>
        /// <param name="allotId"></param>
        /// <returns></returns>
        private void SaveCommon(PerSheet sheet, int allotId)
        {
            var imsheet = new per_sheet { AllotID = allotId, SheetName = sheet.SheetName, Source = 2, SheetType = (int)sheet.SheetType };
            perforPerSheetRepository.Add(imsheet);

            List<im_header> addHeadList = new List<im_header>();
            foreach (var header in sheet.PerHeader)
            {
                var imheader = _mapper.Map<im_header>(header);
                imheader.SheetID = imsheet.ID;
                imheader.AllotID = allotId;
                perforImHeaderRepository.Add(imheader);
                if (header.IsHasChildren)
                {
                    foreach (var child in header.Children)
                    {
                        var imheaderChild = _mapper.Map<im_header>(child);
                        imheaderChild.SheetID = imsheet.ID;
                        imheaderChild.ParentID = imheader.ID;
                        imheaderChild.AllotID = allotId;
                        addHeadList.Add(imheaderChild);
                    }
                }
            }
            perforImHeaderRepository.AddRange(addHeadList.ToArray());

            List<im_data> addDataList = new List<im_data>();
            var dataList = sheet.PerData.Select(t => (PerData)t);
            foreach (var data in dataList)
            {
                var imdata = _mapper.Map<im_data>(data);
                imdata.SheetID = imsheet.ID;
                imdata.AllotID = allotId;
                addDataList.Add(imdata);
            }
            perforImDataRepository.AddRange(addDataList.ToArray());
        }

        /// <summary>
        /// 保存计算过程数据
        /// </summary>
        /// <param name="perSheets"></param>
        /// <param name="allotId"></param>
        public void Save(List<PerSheet> perSheets, int allotId)
        {
            foreach (var sheet in perSheets)
            {
                logManageService.WriteMsg("正在生成绩效", $"保存核算数据 - {sheet.SheetName}", 1, allotId, "ReceiveMessage");
                if (sheet.SheetType == SheetType.ComputeDoctorAccount || sheet.SheetType == SheetType.ComputeNurseAccount)
                {
                    SaveComputeAccount(sheet, allotId);
                }
                else
                {
                    SaveCommon(sheet, allotId);
                }
            }
        }

        #endregion save

        #region compute

        /// <summary>
        /// 合并计算
        /// </summary>
        public (List<PerSheet> Sheets, List<PerSheet> MergeSheets) MergeCompute(PerExcel excel, int allotid)
        {
            var allot = perallotRepository.GetEntity(t => t.ID == allotid);
            if (allot == null) throw new ArgumentNullException(nameof(per_allot));
            var hospital = hospitalRepository.GetEntity(t => t.ID == allot.HospitalId);
            if (hospital == null) throw new ArgumentNullException(nameof(sys_hospital));

            List<PerSheet> perSheet = new List<PerSheet>();

            //合并科室收入、支出
            var incomeconfs = perforCofincomeRepository.GetEntities();
            var economicCompute = new PerSheetDataComputeEconomic();
            logManageService.WriteMsg("正在生成绩效", "计算科室经济核算汇总表", 1, allotid, "ReceiveMessage");
            var mergeResult = economicCompute.MergeCompute(excel, incomeconfs);
            //一次计算
            logManageService.WriteMsg("正在生成绩效", "计算科室经济核算汇总表 -- 第一次计算", 1, allotid, "ReceiveMessage");
            var onceEconomic = economicCompute.OnceCompute(mergeResult);

            //二次计算
            logManageService.WriteMsg("正在生成绩效", "计算科室经济核算汇总表 -- 第二次计算", 1, allotid, "ReceiveMessage");
            var twiceEconomicResult = economicCompute.TwiceCompute(onceEconomic);

            twiceEconomicResult.Sheet.SheetType = SheetType.ComputeEconomic;
            perSheet.Add(twiceEconomicResult.Sheet);
            logManageService.WriteMsg("正在生成绩效", "计算科室经济核算汇总表 -- 计算完成", 1, allotid, "ReceiveMessage");

            //工作量
            var workloadCompute = new PerSheetDataComputeWorkload();
            var workload1 = excel.PerSheet.FirstOrDefault(t => t.SheetType == SheetType.Workload && t.SheetName.Contains("医生组"));
            workload1.SheetName = "医生组工作量绩效测算表";

            logManageService.WriteMsg("正在生成绩效", "获取药品费用分割比例", 1, allotid, "ReceiveMessage");
            var conitem = perforCofworkitemRepository.GetEntities(t => t.AllotID == allotid);

            var medicineProps = GetFactors(excel, SheetType.WorkloadMedicineProp);
            var cmis = GetFactors(excel, SheetType.WorkloadCMI);
            var inclines = GetFactors(excel, SheetType.WorkloadIncline);

            //医生组 一次计算
            //var onceWorkload1 = workloadCompute.OnceCompute(workload1, confs);
            //医生组 二次计算
            logManageService.WriteMsg("正在生成绩效", "医生组工作量计算", 1, allotid, "ReceiveMessage");
            var twiceWorkloadResult1 = workloadCompute.TwiceCompute(workload1, hospital, conitem, medicineProps, cmis, inclines, true);

            twiceWorkloadResult1.Sheet.SheetType = SheetType.ComputeDoctorWorkload;
            perSheet.Add(twiceWorkloadResult1.Sheet);

            var workload2 = excel.PerSheet.FirstOrDefault(t => t.SheetType == SheetType.Workload && t.SheetName.Contains("护理组"));
            workload2.SheetName = "护理组工作量绩效测算表";
            //护理组 一次计算
            //var onceWorkload2 = workloadCompute.OnceCompute(workload2);
            //护理组 二次计算
            logManageService.WriteMsg("正在生成绩效", "护理组工作量计算", 1, allotid, "ReceiveMessage");
            var twiceWorkloadResult2 = workloadCompute.TwiceCompute(workload2, hospital, conitem, medicineProps, cmis, inclines);

            twiceWorkloadResult2.Sheet.SheetType = SheetType.ComputeNurseWorkload;
            perSheet.Add(twiceWorkloadResult2.Sheet);

            List<PerSheet> mergeSheets = new List<PerSheet>();

            var economicSheet = new PerSheet { SheetType = SheetType.ComputeEconomic, PerData = new List<IPerData>() };
            economicSheet.PerData.AddRange(twiceEconomicResult.PerData);
            var doctorSheet = new PerSheet { SheetType = SheetType.ComputeDoctorWorkload, PerData = new List<IPerData>() };
            doctorSheet.PerData.AddRange(twiceWorkloadResult1.PerData);
            var nurseSheet = new PerSheet { SheetType = SheetType.ComputeNurseWorkload, PerData = new List<IPerData>() };
            nurseSheet.PerData.AddRange(twiceWorkloadResult2.PerData);

            mergeSheets.Add(economicSheet);
            mergeSheets.Add(doctorSheet);
            mergeSheets.Add(nurseSheet);

            return (perSheet, mergeSheets);
        }

        /// <summary>
        /// 计算科室绩效
        /// </summary>
        /// <param name="excel"></param>
        /// <param name="perSheet"></param>
        /// <returns></returns>
        ///
        public List<PerSheet> Compute(PerExcel excel, List<PerSheet> perSheet, per_allot allot)
        {
            var accountList = excel.PerSheet.FirstOrDefault(t => t.SheetType == SheetType.AccountBasic)?.PerData?.Select(t => (PerDataAccountBaisc)t);
            var economicData = perSheet.FirstOrDefault(t => t.SheetType == SheetType.ComputeEconomic)?.PerData?.Select(t => (PerData)t);
            var doctorWorkloadData = perSheet.FirstOrDefault(t => t.SheetType == SheetType.ComputeDoctorWorkload)?.PerData?.Select(t => (PerData)t);
            var nurseWorkloadData = perSheet.FirstOrDefault(t => t.SheetType == SheetType.ComputeNurseWorkload)?.PerData?.Select(t => (PerData)t);
            var adjustLaterOtherFee = excel.PerSheet.FirstOrDefault(t => t.SheetType == SheetType.AccountAdjustLaterOtherFee)?.PerData?.Select(t => (PerData)t);

            var pairs = new[]
            {
                new { Name = "医生组临床科室单元核算表", Data = doctorWorkloadData, SheetType = SheetType.ComputeDoctorAccount,
                    UnitTypes = new List<UnitType> { UnitType.医生组, UnitType.医技组, UnitType.专家组, UnitType.其他医技组,UnitType.其他医生组 } },
                new { Name = "护理组临床科室单元核算表", Data = nurseWorkloadData, SheetType = SheetType.ComputeNurseAccount,
                    UnitTypes = new List<UnitType> { UnitType.护理组, UnitType.其他护理组 } },
            };
            var isBudget = _budgetService.GetAdjustAndGrant(allot, out decimal adjust, out decimal grant);
            List<PerSheet> result = new List<PerSheet>();
            foreach (var info in pairs)
            {
                PerSheet sheet = new PerSheet(info.Name, info.Name, info.SheetType, new List<PerHeader>(), new List<IPerData>());
                foreach (var unitType in info.UnitTypes)
                {
                    var atDataList = accountList?.Where(t => t.UnitType == unitType.ToString() && !string.IsNullOrEmpty(t.AccountingUnit));
                    foreach (var dept in atDataList)
                    {
                        //科室奖罚汇总结果
                        //var extra = extras?.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 econDoctor = economicData?.FirstOrDefault(t => t.UnitType == unitType.ToString() && t.AccountingUnit == dept.AccountingUnit);
                        var workDoctor = info.Data.FirstOrDefault(t => t.UnitType == unitType.ToString() && t.AccountingUnit == dept.AccountingUnit);
                        if (UnitType.专家组 == unitType || UnitType.其他医技组 == unitType || UnitType.其他医生组 == unitType || UnitType.其他护理组 == unitType)
                        {
                            econDoctor = economicData?.FirstOrDefault(t => t.AccountingUnit == dept.AccountingUnit);
                            workDoctor = info.Data.FirstOrDefault(t => t.AccountingUnit == dept.AccountingUnit);
                        }
                        if (UnitType.医技组 == unitType && workDoctor == null)
                            workDoctor = info.Data.FirstOrDefault(t => t.UnitType == UnitType.医生组.ToString() && t.AccountingUnit == dept.AccountingUnit);
                        // 夜班绩效 从医院奖罚的明细项中获取
                        var nightShift = adjustLaterOtherFee?.FirstOrDefault(w => w.UnitType == dept.UnitType && w.AccountingUnit == dept.AccountingUnit && w.TypeName?.Trim() == "夜班绩效")?.CellValue ?? 0;

                        dept.NightShiftWorkPerforFee = nightShift;
                        //dept.MedicineFactor = workDoctor?.MedicineFactor;
                        //dept.ScoringAverage = scoreAverage.HasValue ? scoreAverage ?? 0 : dept.ScoringAverage;
                        dept.ScoringAverage = dept.ScoringAverage;
                        dept.AdjustFactor = (isBudget ? adjust : dept?.AdjustFactor) ?? 1;
                        dept.Income = econDoctor?.CellValue ?? 0;
                        dept.WorkloadFee = workDoctor?.CellValue ?? 0;
                        dept.AssessBeforeOtherFee = dept?.AssessBeforeOtherFee ?? 0;
                        dept.AssessLaterOtherFee = dept?.AssessLaterOtherFee ?? 0;
                        dept.AdjustLaterOtherFee = dept?.AdjustLaterOtherFee ?? 0;
                        //dept.Extra = (extra ?? 0);
                        //dept.MedicineExtra = (drugExtra ?? 0);
                        //dept.MaterialsExtra = (materialsExtra ?? 0);
                        dept.Extra = dept?.Extra ?? 0;
                        dept.MedicineExtra = dept.MedicineExtra ?? 0;
                        dept.MaterialsExtra = dept.MaterialsExtra ?? 0;

                        dept.PerforFee = dept.Income * dept.BasicFactor;
                        //dept.PerforTotal = Math.Round((dept.PerforFee + dept.WorkloadFee + dept.OtherPerfor1 + dept.AssessBeforeOtherFee) ?? 0);
                        dept.PerforTotal = Math.Round((dept.PerforFee + dept.WorkloadFee + dept.AssessBeforeOtherFee) ?? 0, MidpointRounding.AwayFromZero);
                        dept.AssessLaterPerforTotal = Math.Round((dept.PerforTotal * dept.ScoringAverage + dept.MedicineExtra + dept.MaterialsExtra + dept.Extra + dept.AssessLaterOtherFee) ?? 0, MidpointRounding.AwayFromZero);
                        dept.RealGiveFee = Math.Round((dept.AssessLaterPerforTotal * dept.AdjustFactor + dept.AdjustLaterOtherFee) ?? 0, MidpointRounding.AwayFromZero);
                        //dept.Avg = dept.ManagerNumber + dept.Number == 0 ? 0 : dept.PerforTotal / (dept.ManagerNumber + dept.Number);
                        dept.Avg = dept.Number == 0 ? 0 : dept.PerforTotal / dept.Number;

                    }

                    sheet.PerData.AddRange(atDataList);
                }
                result.Add(sheet);
            }
            return result;
        }

        /// <summary>
        /// 计算行政科室绩效
        /// </summary>
        /// <param name="allot"></param>
        /// <param name="excel"></param>
        /// <param name="extras"></param>
        public void ComputeOffice(per_allot allot, PerExcel excel)
        {
            //取出科室
            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<string> involves = new List<string>
            {
                AccountUnitType.行政高层.ToString(), AccountUnitType.行政中层.ToString(), AccountUnitType.行政工勤.ToString()
            };
            var empolyeeList = perforRescomputeRepository.GetEntities(w => w.AllotID == allot.ID && involves.Contains(w.AccountType));
            if (empolyeeList == null || empolyeeList.Count() == 0) return;

            List<PerDataAccountBaisc> perDatas = new List<PerDataAccountBaisc>();
            // 取出科室
            var dataList = empolyeeList.Select(w => new { w.AccountType, w.AccountingUnit }).Distinct();
            var isBudget = _budgetService.GetAdjustAndGrant(allot, out decimal adjust, out decimal grant);

            foreach (var account in dataList)
            {
                var resAccount = accountList.FirstOrDefault(t => t.UnitType == account.AccountType && t.AccountingUnit == account.AccountingUnit);
                var empolyees = empolyeeList.Where(w => w.AccountingUnit == account.AccountingUnit && w.AccountType == account.AccountType);

                if (!empolyees.Any()) continue;

                //科室奖罚汇总结果
                //var extra = extras?.FirstOrDefault(w => w.UnitType == account.AccountType.ToString() && w.AccountingUnit == account.AccountingUnit)?.TotelValue;
                //var drugExtra = drugExtras.FirstOrDefault(w => w.UnitType == account.AccountType.ToString() && w.AccountingUnit == resAccount.AccountingUnit)?.TotelValue;
                //var materialsExtra = materialsExtras.FirstOrDefault(w => w.UnitType == account.AccountType.ToString() && w.AccountingUnit == resAccount.AccountingUnit)?.TotelValue;

                var dept = new PerDataAccountBaisc();
                dept.Number = empolyees.Count();
                dept.AccountingUnit = account.AccountingUnit;
                dept.UnitType = account.AccountType;
                dept.Income = empolyees.Sum(w => w.PerforTotal ?? 0);
                dept.NeedSecondAllot = empolyees.Any(w => w.NeedSecondAllot == "是") ? "是" : "否";

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

                    dept.NightShiftWorkPerforFee = nightShift;
                    dept.ScoringAverage = resAccount?.ScoringAverage == null ? 0 : resAccount.ScoringAverage;
                    dept.AdjustFactor = (isBudget ? adjust : resAccount?.AdjustFactor) ?? 1;
                    dept.Extra = resAccount?.Extra ?? 0;
                    dept.MedicineExtra = resAccount?.MedicineExtra ?? 0;// (drugExtra ?? 0);
                    dept.MaterialsExtra = resAccount?.MaterialsExtra ?? 0;//(materialsExtra ?? 0);

                    dept.AssessBeforeOtherFee = resAccount?.AssessBeforeOtherFee ?? 0;
                    dept.AssessLaterOtherFee = resAccount?.AssessLaterOtherFee ?? 0;
                    // 行政后勤 没有 调节后其他绩效
                    dept.AdjustLaterOtherFee = resAccount?.AdjustLaterOtherFee ?? 0;
                }
                else
                {
                    dept.ScoringAverage = 1;
                    dept.AdjustFactor = 1;
                    dept.Extra = empolyees?.Sum(w => w.Punishment) ?? 0;
                    dept.MedicineExtra = 0;// (drugExtra ?? 0);
                    dept.MaterialsExtra = 0;//(materialsExtra ?? 0);

                    dept.AssessBeforeOtherFee = empolyees?.Sum(w => w.AssessBeforeOtherFee) ?? 0;
                    dept.AssessLaterOtherFee = empolyees?.Sum(w => w.AssessLaterOtherFee) ?? 0;
                    dept.AdjustLaterOtherFee = empolyees?.Sum(w => w.AdjustLaterOtherFee) ?? 0;
                }

                //dept.Extra = (extra ?? 0);
                //dept.MedicineExtra = 0;// (drugExtra ?? 0);
                //dept.MaterialsExtra = 0;//(materialsExtra ?? 0);

                dept.PerforFee = empolyees.Sum(w => w.PerforTotal ?? 0);
                dept.PerforTotal = Math.Round(empolyees.Sum(w => w.GiveFee ?? 0), MidpointRounding.AwayFromZero);
                dept.AssessLaterPerforTotal = Math.Round((dept.PerforTotal * dept.ScoringAverage + dept.MedicineExtra + dept.MaterialsExtra + dept.Extra) ?? 0, MidpointRounding.AwayFromZero);
                dept.RealGiveFee = Math.Round((dept.AssessLaterPerforTotal * dept.AdjustFactor + dept.AdjustLaterOtherFee) ?? 0, MidpointRounding.AwayFromZero);
                //dept.Avg = dept.ManagerNumber + dept.Number == 0 ? 0 : dept.PerforTotal / (dept.ManagerNumber + dept.Number);
                dept.Avg = dept.Number == 0 ? 0 : dept.PerforTotal / dept.Number;

                perDatas.Add(dept);
            }

            List<res_account> addList = new List<res_account>();
            foreach (var data in perDatas)
            {
                var imdata = _mapper.Map<res_account>(data);
                imdata.AllotID = allot.ID;
                addList.Add(imdata);
            }
            perforResaccountRepository.AddRange(addList.ToArray());
        }

        /// <summary>
        /// 获取科室奖罚汇总结果
        /// </summary>
        /// <param name="excel"></param>
        public IEnumerable<AccountUnitTotal> GetAccountExtra(PerExcel excel, SheetType sheetType, bool isTotal = false)
        {
            var assessList = excel.PerSheet
                .FirstOrDefault(t => t.SheetType == sheetType)
                ?.PerData
                ?.Select(t => (PerData)t);

            assessList = (isTotal)
                ? assessList?.Where(w => w.IsTotal == 1)
                : assessList?.Where(w => w.IsTotal != 1);
            return assessList?.Select(t => new EmpolyeeTotal
            {
                UnitType = t.UnitType,
                AccountingUnit = t.AccountingUnit,
                JobNumber = t.JobNumber,
                EmployeeName = t.EmployeeName,
                TotelValue = t.CellValue
            });
        }

        /// <summary>
        /// 业务中层行政中高层医院奖罚
        /// </summary>
        /// <param name="excel"></param>
        public IEnumerable<EmpolyeeTotal> GetEmployeeExtra(PerExcel excel)
        {
            var assessList = excel.PerSheet
                .FirstOrDefault(t => t.SheetType == SheetType.PersonExtra)
                ?.PerData
                ?.Select(t => (PerData)t)
                ?.Where(w => w.IsTotal == 1);

            return assessList?.Select(t => new EmpolyeeTotal
            {
                UnitType = t.UnitType,
                AccountingUnit = t.AccountingUnit,
                JobNumber = t.JobNumber,
                EmployeeName = t.EmployeeName,
                TotelValue = t.CellValue
            });
        }

        /// <summary>
        /// 获取科室考核得分率
        /// </summary>
        /// <param name="excel"></param>
        public IEnumerable<AccountUnitTotal> GetAccountScoreAverage(PerExcel excel, SheetType sheetType, bool isTotal = false)
        {
            var assessList = excel.PerSheet
                .FirstOrDefault(t => t.SheetType == sheetType)
                ?.PerData
                ?.Select(t => (PerData)t);

            assessList = (isTotal)
                ? assessList?.Where(w => w.IsTotal == 1)
                : assessList?.Where(w => w.IsTotal != 1);

            return assessList
                ?.GroupBy(t => new { t.UnitType, t.AccountingUnit })
                ?.Select(t => new AccountUnitTotal { UnitType = t.Key.UnitType, AccountingUnit = t.Key.AccountingUnit, TotelValue = t.Sum(g => g.CellValue) });
        }

        ///// <summary>
        ///// 计算保底绩效参考标准
        ///// </summary>
        ///// <param name="baiscnormList"></param>
        ///// <param name="allotId"></param>
        //public List<res_baiscnorm> ComputeMinimum(PerExcel excel, List<PerSheet> perSheet, int allotId)
        //{
        //    var deptAccounting = excel.PerSheet.FirstOrDefault(t => t.SheetType == SheetType.AccountBasic);
        //    var accountList = deptAccounting.PerData.Select(t => (PerDataAccountBaisc)t);

        //    var economicData = perSheet.FirstOrDefault(t => t.SheetType == SheetType.ComputeEconomic)?.PerData.Select(t => (PerData)t);
        //    var doctorWorkloadData = perSheet.FirstOrDefault(t => t.SheetType == SheetType.ComputeDoctorWorkload)?.PerData.Select(t => (PerData)t);
        //    var nurseWorkloadData = perSheet.FirstOrDefault(t => t.SheetType == SheetType.ComputeNurseWorkload)?.PerData.Select(t => (PerData)t);

        //    var basicRuleList = new[]
        //    {
        //        new { Data = doctorWorkloadData, MinimumType = MinimumType.保底临床医生, UnitType = UnitType.医生组 },
        //        new { Data = doctorWorkloadData, MinimumType = MinimumType.保底医技医生, UnitType = UnitType.医技组 },
        //        new { Data = nurseWorkloadData, MinimumType = MinimumType.保底护士, UnitType = UnitType.护理组 },
        //    };
        //    List<res_baiscnorm> baiscnormList = new List<res_baiscnorm>();

        //    foreach (var rule in basicRuleList)
        //    {
        //        var dataList = accountList.Where(t => t.UnitType == rule.UnitType.ToString());
        //        var count = dataList.Sum(t => t.ManagerNumber + t.Number);
        //        decimal totalValue = 0m;
        //        foreach (var dept in dataList)
        //        {
        //            var econDoctor = economicData.FirstOrDefault(t => t.UnitType == rule.UnitType.ToString() && t.AccountingUnit == dept.Department);
        //            var workDoctor = rule.Data.FirstOrDefault(t => t.UnitType == rule.UnitType.ToString() && t.AccountingUnit == dept.Department);

        //            var income = econDoctor?.CellValue ?? 0;
        //            var workloadFee = workDoctor?.CellValue ?? 0;
        //            var perforFee = income * (dept.BasicFactor + dept.SlopeFactor);
        //            var perforTotal = perforFee + workloadFee;

        //            totalValue += perforTotal;
        //        }
        //        var baiscnorm = new res_baiscnorm
        //        {
        //            AllotID = allotId,
        //            PositionName = EnumHelper.GetDescription(rule.MinimumType),
        //            TotelNumber = count,
        //            TotelValue = totalValue,
        //            AvgValue = count == 0 ? 0 : totalValue / count
        //        };
        //        baiscnormList.Add(baiscnorm);
        //    }

        //    return baiscnormList;
        //}

        ///// <summary>
        ///// 计算科室自定义保底绩效范围(根据配置的科室范围计算人均绩效)
        ///// </summary>
        ///// <param name="excel"></param>
        ///// <param name="perSheet"></param>
        ///// <param name="baiscnormList"></param>
        ///// <param name="allotId"></param>
        //public void ComputeCustomMinimum(PerExcel excel, List<PerSheet> perSheet, List<res_baiscnorm> baiscnormList, int allotId)
        //{
        //    var guaranteeList = guaranteeService.Guarantee(allotId);
        //    if (guaranteeList == null || !guaranteeList.Any())
        //        return;

        //    var guaranteeGroupList = guaranteeList
        //        .Where(t => !string.IsNullOrEmpty(t.Target) && !string.IsNullOrEmpty(t.Source))
        //        .GroupBy(t => new { t.UnitType, t.Target })
        //        .Select(t => new { t.Key.UnitType, t.Key.Target, Priority = t.Min(m => m.Priority), Items = t.Select(m => m.Source) });

        //    var deptAccounting = excel.PerSheet.FirstOrDefault(t => t.SheetType == SheetType.AccountBasic);
        //    var accountList = deptAccounting.PerData.Select(t => (PerDataAccountBaisc)t);

        //    var economicData = perSheet.FirstOrDefault(t => t.SheetType == SheetType.ComputeEconomic)?.PerData.Select(t => (PerData)t);
        //    var doctorWorkloadData = perSheet.FirstOrDefault(t => t.SheetType == SheetType.ComputeDoctorWorkload)?.PerData.Select(t => (PerData)t);
        //    var nurseWorkloadData = perSheet.FirstOrDefault(t => t.SheetType == SheetType.ComputeNurseWorkload)?.PerData.Select(t => (PerData)t);

        //    var basicRuleList = new[]
        //    {
        //        new { Data = doctorWorkloadData, UnitType = UnitType.医生组 },
        //        new { Data = doctorWorkloadData, UnitType = UnitType.医技组 },
        //        new { Data = nurseWorkloadData, UnitType = UnitType.护理组 },
        //    };
        //    List<res_baiscnorm> newBaiscnormList = new List<res_baiscnorm>();
        //    foreach (var guaranteeGroup in guaranteeGroupList)
        //    {
        //        var unitType = (UnitType)guaranteeGroup.UnitType;
        //        var dataList = accountList.Where(t => t.UnitType == unitType.ToString() && guaranteeGroup.Items.Contains(t.Department));
        //        var count = dataList.Sum(t => t.ManagerNumber + t.Number);
        //        decimal totalValue = 0m;
        //        foreach (var dept in dataList)
        //        {
        //            var econDoctor = economicData.FirstOrDefault(t => t.UnitType == unitType.ToString() && t.AccountingUnit == dept.Department);
        //            var workdata = basicRuleList.FirstOrDefault(t => t.UnitType == unitType)?.Data;
        //            var workload = workdata == null ? null : workdata.FirstOrDefault(t => t.UnitType == unitType.ToString() && t.AccountingUnit == dept.Department);

        //            //保底绩效
        //            var minimumReference = dept.MinimumReference;
        //            if (dept.MinimumReference == EnumHelper.GetDescription(MinimumType.自定义保底))
        //                minimumReference = GetCustomMinimumName(dept.Department, unitType.ToString());
        //            var minimum = baiscnormList.FirstOrDefault(t => t.PositionName == minimumReference);
        //            if (!string.IsNullOrEmpty(dept.MinimumReference) && minimum != null)
        //                dept.MinimumFee = minimum.AvgValue * (dept.MinimumFactor ?? 0) * (dept.ManagerNumber + dept.Number);

        //            dept.ScoringAverage = dept.ScoringAverage == 0m ? 1 : dept.ScoringAverage;
        //            dept.AdjustFactor = dept.AdjustFactor == 0m ? 1 : dept.AdjustFactor;
        //            dept.Income = econDoctor?.CellValue ?? 0;
        //            dept.WorkloadFee = workload?.CellValue ?? 0;
        //            dept.PerforFee = dept.Income * (dept.BasicFactor + dept.SlopeFactor);
        //            dept.PerforTotal = dept.PerforFee + dept.WorkloadFee + dept.OtherPerfor1 + (dept.MinimumFee ?? 0);
        //            dept.RealGiveFee = (dept.PerforTotal * dept.ScoringAverage + dept.MedicineExtra + dept.MaterialsExtra + dept.Extra + dept.OtherPerfor2) * dept.AdjustFactor;
        //            dept.Avg = dept.ManagerNumber + dept.Number == 0 ? 0 : dept.PerforTotal / (dept.ManagerNumber + dept.Number);

        //            totalValue += (dept.PerforTotal ?? 0);
        //        }
        //        var baiscnorm = new res_baiscnorm
        //        {
        //            AllotID = allotId,
        //            PositionName = GetCustomMinimumName(guaranteeGroup.Target, unitType.ToString()),
        //            TotelNumber = count,
        //            TotelValue = totalValue,
        //            AvgValue = count == 0 ? 0 : totalValue / count
        //        };
        //        baiscnormList.Add(baiscnorm);
        //    }
        //}

        ///// <summary>
        ///// 生成自定义保底名称
        ///// </summary>
        ///// <param name="department"></param>
        ///// <returns></returns>
        //private string GetCustomMinimumName(string department, string unitType)
        //{
        //    return $"{EnumHelper.GetDescription(MinimumType.自定义保底)}({unitType}-{department})";
        //}

        /// <summary>
        /// 获取药占比分割比例
        /// </summary>
        /// <param name="excel"></param>
        /// <param name="sheetType"></param>
        /// <returns></returns>
        private IEnumerable<CofDrugProp> GetFactors(PerExcel excel, SheetType sheetType)
        {
            var perDatas = excel.PerSheet.FirstOrDefault(t => t.SheetType == sheetType)?.PerData.Select(w => (PerData)w);
            var factors = perDatas
                ?.Where(w => w.IsTotal == 1)
                .Select(w => new CofDrugProp
                {
                    AccountingUnit = w.AccountingUnit,
                    UnitType = w.UnitType,
                    Factor = w.CellValue ?? 1
                });
            return factors ?? new List<CofDrugProp>();
        }

        ///// <summary>
        ///// 获取药占比分割比例
        ///// </summary>
        ///// <param name="excel"></param>
        ///// <returns></returns>
        //private List<CofDrugProp> GetDrugConfig(PerExcel excel, int allotid)
        //{
        //    //计算药占比
        //    List<CofDrugProp> cofs = new List<CofDrugProp>();

        //    var incomeSheet = excel.PerSheet.FirstOrDefault(t => t.SheetType == SheetType.Income && t.SheetName.Contains("门诊") && t.SheetName.Contains("开单"));
        //    var datalist = incomeSheet.PerData.Select(t => (PerData)t);
        //    var drugtype = perforCofdrugtypeRepository.GetEntities(t => t.AllotID == allotid && t.ChargeType == "药费")?.Select(t => t.Charge).ToList();

        //    var drugData = datalist.Where(t => drugtype.Contains(t.TypeName)).GroupBy(t => t.AccountingUnit).Select(t => new { AccountingUnit = t.Key, SumValue = t.Sum(s => s.CellValue) });
        //    if (drugtype == null)
        //    {
        //        drugData = null;
        //        //throw new PerformanceException("未配置药占比类型");
        //    }

        //    var allData = datalist.GroupBy(t => t.AccountingUnit).Select(t => new { AccountingUnit = t.Key, SumValue = t.Sum(s => s.CellValue) });

        //    var cofList = perforCofdrugpropRepository.GetEntities(t => t.AllotID == allotid);
        //    if (cofList == null || !cofList.Any()) return cofs;

        //    var unitList = (drugData?.Select(t => t.AccountingUnit) ?? new List<string>()).Union(allData.Select(t => t.AccountingUnit));

        //    foreach (var unit in unitList)
        //    {
        //        var dsv = drugData?.FirstOrDefault(t => t.AccountingUnit == unit)?.SumValue;
        //        var asv = allData.FirstOrDefault(t => t.AccountingUnit == unit)?.SumValue;

        //        var prop = asv.HasValue && asv.Value > 0 ? Math.Round((dsv ?? 0) / asv.Value, 2) : 0;
        //        var fvalue = cofList.FirstOrDefault(t => prop > t.MinRange && prop <= t.MaxRange)?.Value ?? 0;
        //        cofs.Add(new CofDrugProp { AccoutingUnit = unit, Factor = fvalue, Prop = prop });
        //    }
        //    return cofs;
        //}

        #endregion compute
    }
}
