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 PerforCofincomeRepository perforCofincomeRepository;
        private PerforCofdrugpropRepository perforCofdrugpropRepository;
        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 LogManageService logManageService;
        private readonly GuaranteeService guaranteeService;

        public ProcessComputService(PerforCofincomeRepository perforCofincomeRepository,
            PerforCofdrugpropRepository perforCofdrugpropRepository,
            PerforPersheetRepository perforPerSheetRepository,
            PerforImdataRepository perforImDataRepository,
            PerforImheaderRepository perforImHeaderRepository,
            PerforImemployeeRepository perforImEmployeeRepository,
            PerforResaccountRepository perforResaccountRepository,
            PerforResbaiscnormRepository perforResbaiscnormRepository,
            PerforCofdrugtypeRepository perforCofdrugtypeRepository,
            PerforCofworkitemRepository perforCofworkitemRepository,
            LogManageService logManageService,
            GuaranteeService guaranteeService)
        {
            this.perforCofincomeRepository = perforCofincomeRepository;
            this.perforCofdrugpropRepository = perforCofdrugpropRepository;
            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.logManageService = logManageService;
            this.guaranteeService = guaranteeService;
        }

        ///// <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

        #region compute
        /// <summary>
        /// 合并计算
        /// </summary>
        public (List<PerSheet> Sheets, List<PerSheet> MergeSheets) MergeCompute(PerExcel excel, int allotid)
        {
            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 confs = GetDrugConfig(excel, allotid);
            var conitem = perforCofworkitemRepository.GetEntities(t => t.AllotID == allotid);
            //医生组 一次计算
            //var onceWorkload1 = workloadCompute.OnceCompute(workload1, confs);
            //医生组 二次计算 
            logManageService.WriteMsg("正在生成绩效", "医生组工作量计算", 1, allotid, "ReceiveMessage");
            var twiceWorkloadResult1 = workloadCompute.TwiceCompute(workload1, confs, conitem);

            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, confs, conitem);

            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="dataList"></param>
        /// <param name="economicData"></param>
        /// <param name="workloadData"></param>
        /// <returns></returns>
        public List<PerSheet> Compute(PerExcel excel, List<PerSheet> perSheet, List<res_baiscnorm> baiscnormList)
        {
            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 pairs = new[]
            {
                new { Name = "医生组临床科室单元核算表", Data = doctorWorkloadData, SheetType = SheetType.ComputeDoctorAccount, UnitTypes = new List<UnitType> { UnitType.医生组, UnitType.医技组, UnitType.专家组, UnitType.其他组 } },
                new { Name = "护理组临床科室单元核算表", Data = nurseWorkloadData, SheetType = SheetType.ComputeNurseAccount, UnitTypes = new List<UnitType> { UnitType.护理组 } },
            };
            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());
                    if (atDataList == null || !atDataList.Any())
                        continue;
                    foreach (var dept in accountList.Where(t => t.UnitType == unitType.ToString()))
                    {
                        if (string.IsNullOrEmpty(dept.AccountingUnit))
                            continue;
                        var econDoctor = economicData.FirstOrDefault(t => t.UnitType == unitType.ToString() && t.AccountingUnit == dept.Department);
                        var workDoctor = info.Data.FirstOrDefault(t => t.UnitType == unitType.ToString() && t.AccountingUnit == dept.Department);
                        if (UnitType.专家组 == unitType || UnitType.其他组 == unitType)
                        {
                            econDoctor = economicData.FirstOrDefault(t => t.AccountingUnit == dept.Department);
                            workDoctor = info.Data.FirstOrDefault(t => t.AccountingUnit == dept.Department);
                        }
                        else if (UnitType.医技组 == unitType && workDoctor == null)
                        {
                            workDoctor = info.Data.FirstOrDefault(t => t.AccountingUnit == dept.Department && t.UnitType == UnitType.医生组.ToString());
                        }
                        //保底绩效
                        if (!string.IsNullOrEmpty(dept.MinimumReference))
                        {
                            string minimumReference = dept.MinimumReference;
                            if (dept.MinimumReference == EnumHelper.GetDescription(MinimumType.自定义保底))
                                minimumReference = GetCustomMinimumName(dept.Department);

                            var minimum = baiscnormList.FirstOrDefault(t => t.PositionName == minimumReference);
                            if (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 = workDoctor?.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.Extra + dept.OtherPerfor2) * dept.AdjustFactor;
                        dept.Avg = dept.ManagerNumber + dept.Number == 0 ? 0 : dept.PerforTotal / (dept.ManagerNumber + dept.Number);
                    }

                    #region 共用核算单元算法调整20190920新都调整

                    var multi = atDataList.GroupBy(t => new { t.UnitType, t.AccountingUnit })
                        .Select(t => new { t.Key.UnitType, t.Key.AccountingUnit, Count = t.Count(), })
                        .Where(t => t.Count > 1);

                    if (multi != null && multi.Any())
                    {
                        foreach (var item in atDataList)
                        {
                            if (multi.Any(group => group.UnitType == item.UnitType && group.AccountingUnit == item.AccountingUnit))
                                item.Remark = "特殊科室，共用核算单元";
                        }
                    }

                    //var multi = atDataList.GroupBy(t => new { t.UnitType, t.AccountingUnit })
                    //   .Select(t => new
                    //   {
                    //       UnitType = t.Key.UnitType,
                    //       AccountingUnit = t.Key.AccountingUnit,
                    //       Count = t.Count(),
                    //       RealGiveFee = t.Sum(p => p.RealGiveFee),
                    //       PerforTotal = t.Sum(p => p.PerforTotal),
                    //       Avg = t.Sum(p => p.ManagerNumber + p.Number) == 0 ? 0 : t.Sum(p => p.RealGiveFee) / t.Sum(p => p.ManagerNumber + p.Number)
                    //   })
                    //   .Where(t => t.Count > 1).ToArray();

                    //if (multi != null && multi.Any())
                    //{
                    //    foreach (var item in atDataList)
                    //    {
                    //        if (multi.Any(group => group.UnitType == item.UnitType && group.AccountingUnit == item.AccountingUnit))
                    //        {
                    //            item.Avg = multi.FirstOrDefault(group => group.AccountingUnit == item.AccountingUnit).Avg;
                    //            item.RealGiveFee = multi.FirstOrDefault(group => group.AccountingUnit == item.AccountingUnit).RealGiveFee;
                    //            item.PerforTotal = multi.FirstOrDefault(group => group.AccountingUnit == item.AccountingUnit).PerforTotal;
                    //            item.Remark = "特殊科室，共用核算单元";
                    //        }
                    //    }
                    //} 
                    #endregion

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


        /// <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 minimum = baiscnormList.FirstOrDefault(t => t.PositionName == dept.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.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),
                    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)
        {
            return $"{EnumHelper.GetDescription(MinimumType.自定义保底)}({department})";
        }

        /// <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);

            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
    }
}
