using AutoMapper;
using Performance.DtoModels;
using Performance.EntityModels;
using Performance.Infrastructure;
using Performance.Repository;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Text.RegularExpressions;
using Performance.DtoModels.Request;
using Performance.DtoModels.Response;

namespace Performance.Services
{
    public class ComputeService : IAutoInjection
    {
        private readonly PerforResaccountRepository perforResaccountRepository;
        private readonly PerforPersheetRepository _perforPerSheetRepository;
        private readonly PerforImdataRepository _perforImDataRepository;
        private readonly PerforImheaderRepository _perforImheaderRepository;
        private readonly PerforRescomputeRepository _perforRescomputeRepository;
        private readonly PerforResspecialunitRepository _perforResspecialunitRepository;
        private readonly PerforResbaiscnormRepository perforResbaiscnormRepository;
        private readonly PerforAgsecondallotRepository _perforAgsecondallotRepository;
        private readonly PerforAgcomputeRepository _perforAgcomputeRepository;
        private readonly PerforImemployeeclinicRepository _perforImemployeeclinicRepository;
        private readonly PerforImemployeeRepository _perforImemployeeRepository;
        private readonly PerforPerallotRepository perforPerallotRepository;
        private readonly PerforHospitalRepository hospitalRepository;
        private readonly PerforPerapramountRepository perapramountRepository;
        private readonly PerforPeremployeeRepository perforPeremployeeRepository;
        private readonly PerforCofworkitemRepository cofworkitemRepository;

        public ComputeService(PerforResaccountRepository perforResaccountRepository,
            PerforPersheetRepository perforPerSheetRepository,
            PerforImdataRepository perforImDataRepository,
            PerforImheaderRepository perforImheaderRepository,
            PerforRescomputeRepository perforRescomputeRepository,
            PerforResspecialunitRepository perforResspecialunitRepository,
            PerforResbaiscnormRepository perforResbaiscnormRepository,
            PerforAgsecondallotRepository perforAgsecondallotRepository,
            PerforAgcomputeRepository perforAgcomputeRepository,
            PerforImemployeeclinicRepository perforImemployeeclinicRepository,
            PerforImemployeeRepository perforImemployeeRepository,
            PerforPerallotRepository perforPerallotRepository,
            PerforHospitalRepository hospitalRepository,
            PerforPerapramountRepository perapramountRepository,
            PerforPeremployeeRepository perforPeremployeeRepository,
            PerforCofworkitemRepository cofworkitemRepository)
        {
            this.perforResaccountRepository = perforResaccountRepository;
            this._perforPerSheetRepository = perforPerSheetRepository;
            this._perforImDataRepository = perforImDataRepository;
            this._perforImheaderRepository = perforImheaderRepository;
            this._perforRescomputeRepository = perforRescomputeRepository;
            this._perforResspecialunitRepository = perforResspecialunitRepository;
            this.perforResbaiscnormRepository = perforResbaiscnormRepository;
            this._perforAgsecondallotRepository = perforAgsecondallotRepository;
            this._perforAgcomputeRepository = perforAgcomputeRepository;
            this._perforImemployeeclinicRepository = perforImemployeeclinicRepository;
            this._perforImemployeeRepository = perforImemployeeRepository;
            this.perforPerallotRepository = perforPerallotRepository;
            this.hospitalRepository = hospitalRepository;
            this.perapramountRepository = perapramountRepository;
            this.perforPeremployeeRepository = perforPeremployeeRepository;
            this.cofworkitemRepository = cofworkitemRepository;
        }

        public int IsShowManage(int allotId)
        {
            var allot = perforPerallotRepository.GetEntity(t => t.ID == allotId);
            if (allot == null)
                throw new PerformanceException("绩效信息无效");

            return hospitalRepository.GetEntity(t => t.ID == allot.HospitalId)?.IsShowManage ?? 1;
        }

        /// <summary>
        /// 返回绩效发放列表
        /// </summary>
        /// <param name="allotId">绩效ID</param>
        /// <param name="type">绩效基数核算参考对象</param>
        /// <returns></returns>
        public List<ResComputeResponse> GetCompute(int allotId, int type)
        {
            var data = new List<ResComputeResponse>();

            var items = EnumHelper.GetItems<AccountUnitType>();
            if (!items.Any(t => t.Value == type))
                throw new PerformanceException("参数错误，type无效");

            Dictionary<int, List<string>> pairs = new Dictionary<int, List<string>>
            {
                { (int)AccountUnitType.科主任, new List<string>{ UnitType.医生组.ToString(), UnitType.医技组.ToString() } },
                { (int)AccountUnitType.护士长, new List<string>{ UnitType.护理组.ToString() } },
                { (int)AccountUnitType.Null, new List<string>
                    {
                        UnitType.特殊核算组.ToString(),
                        UnitType.其他医生组.ToString(),
                        UnitType.其他护理组.ToString(),
                        UnitType.其他医技组.ToString()
                    }
                },
            };
            var isShowManage = IsShowManage(allotId);

            var apramounts = perapramountRepository.GetEntities(t => t.AllotId == allotId && t.Status == 3);
            if (pairs.Keys.Any(t => t == type))
            {
                #region MyRegion

                //var employees = _perforImemployeeclinicRepository.GetEntities(t => t.AllotID == allotId && pairs[type].Contains(t.UnitType));
                //if (employees == null || !employees.Any()) return new List<ResComputeResponse>();

                //string[] accountunittype = new string[] { AccountUnitType.行政中层.ToString(), AccountUnitType.行政工勤.ToString(), AccountUnitType.行政高层.ToString() };
                //var computes = _perforRescomputeRepository.GetEntities(t => t.AllotID == allotId && !accountunittype.Contains(t.AccountType));
                //if (computes == null || !computes.Any()) return new List<ResComputeResponse>();

                //var joinData = employees.Join(computes, outer => new { outer.AccountingUnit, EmployeeName = outer.DoctorName },
                //    inner => new { inner.AccountingUnit, inner.EmployeeName }, (outer, inner) => inner).ToList();
                //if (joinData == null || !joinData.Any()) return new List<ResComputeResponse>();

                //if (type != (int)AccountUnitType.Null)
                //{
                //    var accountUnit = computes.Where(t => t.AccountType == ((AccountUnitType)type).ToString() && joinData.Select(join => join.EmployeeName).Contains(t.EmployeeName));

                //    if (accountUnit != null && accountUnit.Any())
                //    {
                //        accountUnit.ToList().ForEach(t =>
                //        {
                //            var compute = joinData.First(join => join.EmployeeName == t.EmployeeName);
                //            if (compute.AccountingUnit != t.AccountingUnit && !joinData.Any(w => w.EmployeeName == t.EmployeeName && w.AccountingUnit == t.AccountingUnit))
                //                joinData.Add(t);
                //        });
                //    }
                //}
                //else
                //{
                //    var accountUnit = computes.Where(t => joinData.Select(join => join.EmployeeName).Contains(t.EmployeeName));
                //    if (accountUnit != null && accountUnit.Any())
                //    {
                //        var delData = new List<res_compute>();
                //        foreach (var item in joinData)
                //        {
                //            accountUnit.Where(join => join.EmployeeName == item.EmployeeName).ToList().ForEach(t =>
                //            {
                //                if (item.AccountType == t.AccountType && item.AccountingUnit != t.AccountingUnit)
                //                    delData.Add(item);
                //            });
                //        }
                //        if (delData.Count > 0)
                //            joinData.RemoveAll(t => delData.Select(d => d.ID).Contains(t.ID));
                //    }
                //}
                //if (joinData == null || !joinData.Any()) return new List<ResComputeResponse>();

                //data = Mapper.Map<List<ResComputeResponse>>(joinData);

                #endregion MyRegion

                var employees = _perforImemployeeclinicRepository.GetEntities(t => t.AllotID == allotId && pairs[type].Contains(t.UnitType));
                if (employees == null || !employees.Any()) return new List<ResComputeResponse>();

                var computes = _perforRescomputeRepository.GetEntities(t => t.AllotID == allotId && pairs[type].Contains(t.UnitType));
                if (computes == null || !computes.Any()) return new List<ResComputeResponse>();

                data = Mapper.Map<List<ResComputeResponse>>(computes);

                data.ForEach(t =>
                {
                    //t.WorkTime = string.IsNullOrEmpty(t.WorkTime) ? null : Convert.ToDateTime(t.WorkTime).ToString("yyyy-MM-dd");
                    if (isShowManage == 2)
                    {
                        t.PerforSumFee = (t.ShouldGiveFee ?? 0) + (t.AssessBeforeOtherFee ?? 0);
                        var employee = employees.FirstOrDefault(e => e.DoctorName == t.EmployeeName && e.AccountingUnit == t.AccountingUnit && pairs[type].Contains(e.UnitType));
                        var scoreAverageRate = t.ScoreAverageRate ?? employee.ScoreAverageRate ?? 1;
                        var attendance = t.Attendance ?? employee.Attendance ?? 0;
                        t.GiveFee = (t.ShouldGiveFee ?? 0) * scoreAverageRate * attendance + (t.OtherPerfor ?? 0) + (t.Punishment ?? 0) + (t.AssessLaterOtherFee ?? 0);
                        t.RealGiveFee = t.GiveFee * (t.Adjust ?? 1m) + (t.AdjustLaterOtherFee ?? 0);
                        t.BaiscNormValue = (t.RealGiveFee ?? 0);
                    }

                    var aprAmount = apramounts?.Where(w => !(string.IsNullOrEmpty(w.DoctorName) && string.IsNullOrEmpty(w.PersonnelNumber)) && w.DoctorName?.Trim() == t.EmployeeName?.Trim() && w.PersonnelNumber?.Trim() == t.JobNumber?.Trim());
                    t.OtherPerformance = aprAmount?.Sum(w => w.Amount);
                });
                return data.Distinct().OrderByDescending(t => t.AccountingUnit).ToList();
            }
            else
            {
                var compute = _perforRescomputeRepository.GetEntities(t => t.AllotID == allotId && t.AccountType == items.FirstOrDefault(p => p.Value == type).Name);
                if (type == (int)AccountUnitType.行政工勤)
                    compute = compute?.Where(w => w.NeedSecondAllot == "否")?.ToList();

                if (compute == null || !compute.Any()) return new List<ResComputeResponse>();

                data = Mapper.Map<List<ResComputeResponse>>(compute);
                data = data.OrderByDescending(t => t.RealGiveFee).ThenBy(t => t.FitPeople).ThenBy(t => t.AccountingUnit).ToList();
                data.ForEach(t =>
                {
                    //t.WorkTime = string.IsNullOrEmpty(t.WorkTime) ? null : Convert.ToDateTime(t.WorkTime).ToString("yyyy-MM-dd");
                    var aprAmount = apramounts?.Where(w => !(string.IsNullOrEmpty(w.DoctorName) && string.IsNullOrEmpty(w.PersonnelNumber)) && w.DoctorName?.Trim() == t.EmployeeName?.Trim() && w.PersonnelNumber?.Trim() == t.JobNumber?.Trim());
                    t.OtherPerformance = aprAmount?.Sum(w => w.Amount);
                });
                return data.Distinct().OrderByDescending(t => t.AccountingUnit).ToList();
            }
        }

        public List<res_baiscnorm> AllComputeAvg(int allotId, List<ComputeResponse> list)
        {
            List<res_baiscnorm> avgs = new List<res_baiscnorm>();
            var emps = perforPeremployeeRepository.GetEntities(w => w.AllotId == allotId);
            var jobCategory = emps?.Select(w => string.IsNullOrEmpty(w.JobCategory) ? "未知" : w.JobCategory).Distinct() ?? new List<string>();
            var basicnorm = perforResbaiscnormRepository.GetEntities(t => t.AllotID == allotId);
            var position = basicnorm?.Select(t => string.IsNullOrEmpty(t.PositionName) ? "" : t.PositionName).Distinct() ?? new List<string>();
            foreach (var item in jobCategory)
            {
                if (position.Contains(item))
                {
                    avgs.Add(basicnorm.First(t => t.PositionName == item));
                    continue;
                }
                var sumfee = (from com in list
                              join emp in emps?.Where(w => w.JobCategory == item)
                              on com.JobNumber equals emp.PersonnelNumber
                              select com.ShouldGiveFee).Sum(w => w);
                var count = emps?.Where(w => w.JobCategory == item).Select(emp => emp.PersonnelNumber).Distinct().Count() ?? 0;
                avgs.Add(new res_baiscnorm
                {
                    PositionName = item,
                    TotelNumber = count,
                    TotelValue = sumfee,
                    AvgValue = count == 0 ? 0 : Math.Round(sumfee / count ?? 0),
                });
            }
            return avgs;
        }

        /// <summary>
        /// 返回特殊科室发放列表
        /// </summary>
        /// <param name="allotId">绩效ID</param>
        /// <returns></returns>
        public List<res_specialunit> GetSpecial(int allotId)
        {
            var list = _perforResspecialunitRepository.GetEntities(t => t.AllotID == allotId);
            if (list != null && list.Any())
            {
                list = list.OrderByDescending(t => t.AccountingUnit).ThenBy(t => t.RealGiveFee).ToList();
                return Mapper.Map<List<res_specialunit>>(list);
            }
            return new List<res_specialunit>();
        }

        /// <summary>
        /// 返回医生组科室绩效
        /// </summary>
        /// <param name="allotId">绩效ID</param>
        /// <returns></returns>
        public List<DeptResponse> GetDoctorPerformance(int allotId)
        {
            List<int> types = new List<int> { (int)UnitType.医生组, (int)UnitType.医技组 };
            var list = perforResaccountRepository.GetEntities(t => types.Contains(t.UnitType.Value) && t.AllotID == allotId)?.OrderBy(t => t.UnitType).ThenByDescending(t => t.AccountingUnit);
            List<DeptResponse> doctor = Mapper.Map<List<DeptResponse>>(list);
            doctor?.ForEach(t => t.UnitName = ((UnitType)t.UnitType).ToString());
            return doctor;
        }

        /// <summary>
        /// 返回护理组科室绩效
        /// </summary>
        /// <param name="allotId">绩效ID</param>
        /// <returns></returns>
        public List<DeptResponse> GetNursePerformance(int allotId)
        {
            var list = perforResaccountRepository.GetEntities(t => t.UnitType == (int)UnitType.护理组 && t.AllotID == allotId)?.OrderBy(t => t.UnitType).ThenByDescending(t => t.AccountingUnit);
            List<DeptResponse> nurse = Mapper.Map<List<DeptResponse>>(list);
            nurse?.ForEach(t => t.UnitName = ((UnitType)t.UnitType).ToString());
            return nurse;
        }

        /// <summary>
        /// 返回其他组科室绩效
        /// </summary>
        /// <param name="allotId">绩效ID</param>
        /// <returns></returns>
        public List<DeptResponse> GetOtherPerformance(int allotId)
        {
            var unitType = new List<int> { (int)UnitType.其他医技组, (int)UnitType.其他医生组, (int)UnitType.其他护理组, (int)UnitType.专家组 };
            var list = perforResaccountRepository.GetEntities(t => unitType.Contains(t.UnitType.Value) && t.AllotID == allotId)?.OrderBy(t => t.UnitType).ThenByDescending(t => t.AccountingUnit);
            List<DeptResponse> other = Mapper.Map<List<DeptResponse>>(list);
            other?.ForEach(t => t.UnitName = ((UnitType)t.UnitType).ToString());
            return other;
        }

        /// <summary>
        /// 返回行政科室绩效列表
        /// </summary>
        /// <param name="allotId">绩效ID</param>
        /// <returns></returns>
        public List<DeptResponse> GetOfficePerformance(int allotId)
        {
            var unitType = new List<int> { (int)UnitType.行政后勤 };

            var list = perforResaccountRepository.GetEntities(t => unitType.Contains(t.UnitType.Value) && t.AllotID == allotId && t.NeedSecondAllot == "是")
                ?.OrderBy(t => t.UnitType)
                .ThenByDescending(t => t.AccountingUnit);
            List<DeptResponse> other = Mapper.Map<List<DeptResponse>>(list);
            other?.ForEach(t => t.UnitName = ((UnitType)t.UnitType).ToString());
            return other;
        }

        ///// <summary>
        ///// 返回院领导、中层、工勤组绩效
        ///// </summary>
        ///// <param name="allotId">绩效ID</param>
        ///// <returns></returns>
        //public List<DeptResponse> GetAdminPerformance(int allotId)
        //{














        //    var result = new List<DeptResponse>();
        //    var resData = perforResaccountRepository.GetEntities(t => t.AllotID == allotId);
        //    if (resData != null && resData.Any())
        //    {
        //        result.AddRange(Mapper.Map<List<DeptResponse>>(resData));
        //        result.ForEach(t =>
        //        {
        //            t.UnitName = ((UnitType)t.UnitType).ToString();
        //            t.AssessLaterPerforTotal = Math.Round((t.PerforTotal * t.ScoringAverage + (t.MedicineExtra ?? 0) + (t.MaterialsExtra ?? 0) + (t.Extra ?? 0) + (t.AssessLaterOtherFee ?? 0)) ?? 0);
        //        });
        //        result = result.OrderBy(t => t.UnitType).ThenBy(t => t.AccountingUnit).ToList();
        //    }

        //    var list = _perforRescomputeRepository.GetEntities(t => t.AllotID == allotId);
        //    if (list == null || !list.Any()) return result;

        //    var isShowManage = IsShowManage(allotId);

        //    Dictionary<string, string> dict = new Dictionary<string, string>
        //    {
        //        { "科主任", "医生组" },
        //        { "护士长", "护理组" },
        //        { AccountUnitType.行政高层.ToString(), AccountUnitType.行政高层.ToString() },
        //        { AccountUnitType.行政中层.ToString(), AccountUnitType.行政中层.ToString() },
        //        { AccountUnitType.行政工勤.ToString(), AccountUnitType.行政工勤.ToString() }
        //    };
        //    var doctors = new string[] { "医生组", "护理组", "医技组" };
        //    List<DeptResponse> adminPerfor = list.GroupBy(t => new { t.AccountingUnit, t.AccountType, t.UnitType }).Select(t =>
        //       {
        //           string unitName = !string.IsNullOrEmpty(t.Key.UnitType) ? t.Key.UnitType : result.Where(w => !dict.Values.Contains(w.UnitName)).FirstOrDefault(w => w.AccountingUnit == t.Key.AccountingUnit)?.UnitName ?? "";
        //           var data = new DeptResponse
        //           {
        //               UnitName = !dict.Values.Contains(unitName) && !string.IsNullOrEmpty(unitName) ? unitName : dict.ContainsKey(t.Key.AccountType) ? dict[t.Key.AccountType] : "未知",
        //               AccountingUnit = t.Key.AccountingUnit,
        //               Department = t.Key.AccountingUnit,
        //               Number = t.Count(),
        //           };
        //           if (doctors.Contains(data.UnitName))
        //           {
        //               data.AssessLaterManagementFee = isShowManage == 1
        //                   ? t.Sum(group => group.RealGiveFee ?? 0) + t.Sum(group => group.OtherPerfor ?? 0)  //实发绩效
        //                   : Math.Round((t.Max(m => m.ShouldGiveFee) * t.Max(m => m.ScoreAverageRate) * t.Max(m => m.Attendance) ?? 0.0M) + t.Max(m => m.Punishment ?? 0.0M)); //考核后管理绩效
        //           }
        //           return data;
        //       }).ToList();

        //    result.AddRange(adminPerfor);

        //    var aprAmounts = perapramountRepository.GetEntities(t => t.AllotId == allotId && t.Status == 3) ?? new List<per_apr_amount>();
        //    var employees = perforPeremployeeRepository.GetEntities(t => t.AllotId == allotId) ?? new List<per_employee>();

        //    var otherPerformances = aprAmounts.Join(employees,
        //        outer => new { outer.AccountingUnit, outer.PersonnelNumber },
        //        inner => new { inner.AccountingUnit, inner.PersonnelNumber },
        //        (outer, inner) => new
        //        {
        //            AccountingUnit = outer.AccountingUnit,
        //            UnitType = inner.UnitType,
        //            PersonnelNumber = inner.PersonnelNumber,
        //            PersonnelName = outer.DoctorName,
        //            Amount = outer.Amount
        //        })?.GroupBy(t => new { t.AccountingUnit, t.UnitType }).Select(t => new
        //        {
        //            AccountingUnit = t.Key.AccountingUnit,
        //            UnitType = t.Key.UnitType,
        //            Amount = t.Sum(s => s.Amount)
        //        });

        //    result = result.GroupBy(t => new { t.AccountingUnit, t.UnitName }).Select(t => new DeptResponse
        //    {
        //        UnitName = t.Key.UnitName,
        //        AccountingUnit = t.Key.AccountingUnit,
        //        Department = t.Key.AccountingUnit,
        //        PerforFee = t.Sum(group => group.PerforFee),
        //        WorkloadFee = t.Sum(group => group.WorkloadFee),
        //        AssessBeforeOtherFee = t.Sum(group => group.AssessBeforeOtherFee),
        //        ScoringAverage = t.Sum(group => group.ScoringAverage),
        //        MedicineExtra = t.Sum(group => group.MedicineExtra),
        //        Extra = t.Sum(group => group.Extra),
        //        AssessLaterOtherFee = t.Sum(group => group.AssessLaterOtherFee),
        //        AdjustFactor = t.Max(group => group.AdjustFactor),
        //        AdjustLaterOtherFee = t.Sum(group => group.AdjustLaterOtherFee),
        //        PerforTotal = t.Sum(group => group.PerforTotal),
        //        AssessLaterPerforTotal = t.Sum(group => group.AssessLaterPerforTotal),
        //        AssessLaterManagementFee = t.Sum(group => group.AssessLaterManagementFee),
        //        AprPerforAmount = otherPerformances?.FirstOrDefault(w => w.AccountingUnit == t.Key.AccountingUnit && w.UnitType == t.Key.UnitName)?.Amount ?? 0,
        //        RealGiveFee = t.Sum(group => group.RealGiveFee) + t.Sum(group => group.AssessLaterManagementFee)
        //        + (otherPerformances?.FirstOrDefault(w => w.AccountingUnit == t.Key.AccountingUnit && w.UnitType == t.Key.UnitName)?.Amount ?? 0),
        //    }).ToList();

        //    var specialData = _perforResspecialunitRepository.GetEntities(t => t.AllotID == allotId);
        //    if (specialData != null && specialData.Any())
        //    {
        //        result.AddRange(specialData.GroupBy(t => new { t.AccountingUnit, t.Department }).Select(t =>
        //        {
        //            var data = new DeptResponse
        //            {
        //                UnitName = "特殊核算组",
        //                AccountingUnit = t.Key.AccountingUnit,
        //                Department = t.Key.Department,
        //                PerforFee = t.Max(max => max.GiveFee),
        //                WorkloadFee = 0,
        //                AssessBeforeOtherFee = t.Max(max => max.AssessBeforeOtherFee),
        //                PerforTotal = t.Max(max => max.PerforTotal),
        //                ScoringAverage = t.Max(max => max.ScoringAverage),
        //                MedicineExtra = t.Max(max => max.MedicineExtra),
        //                MaterialsExtra = t.Max(max => max.MaterialsExtra),
        //                Extra = 0,
        //                AssessLaterOtherFee = t.Max(max => max.AssessLaterOtherFee),
        //                AdjustFactor = t.Max(max => max.Adjust),
        //                AdjustLaterOtherFee = t.Max(max => max.AdjustLaterOtherFee),
        //                AssessLaterManagementFee = 0,
        //                AprPerforAmount = 0,
        //                RealGiveFee = t.Max(max => max.RealGiveFee),
        //            };
        //            data.AssessLaterPerforTotal = Math.Round(((data.PerforTotal * data.ScoringAverage) ?? 0) + (data.MedicineExtra ?? 0) + (data.MaterialsExtra ?? 0) + (data.AssessLaterOtherFee ?? 0));
        //            return data;
        //        }));
        //    }

        //    var enumItems = EnumHelper.GetItems<AccountUnitType>();

        //    result = result.OrderBy(t => enumItems.FirstOrDefault(e => e.Name == t.UnitName)?.Value)/*.ThenBy(t => t.AccountingUnit)*/.ToList();
        //    return result;
        //}


        /// <summary>
        /// 返回院领导、中层、工勤组绩效
        /// </summary>
        /// <param name="allotId">绩效ID</param>
        /// <returns></returns>
        public List<DeptResponse> GetAdminPerformance(int allotId)
        {
            var result = new List<DeptResponse>();
            var amounts = perapramountRepository.GetEntities(t => t.AllotId == allotId && t.Status == 3) ?? new List<per_apr_amount>();
            var employees = perforPeremployeeRepository.GetEntities(t => t.AllotId == allotId) ?? new List<per_employee>();
            // 获取各科室 医院其他绩效
            var otherPerformances = amounts.Join(employees,
                outer => new { outer.AccountingUnit, outer.PersonnelNumber },
                inner => new { inner.AccountingUnit, inner.PersonnelNumber },
                (outer, inner) => new
                {
                    AccountingUnit = outer.AccountingUnit,
                    UnitType = inner.UnitType,
                    PersonnelNumber = inner.PersonnelNumber,
                    PersonnelName = outer.DoctorName,
                    Amount = outer.Amount
                })?.GroupBy(t => new { t.AccountingUnit, t.UnitType }).Select(t => new
                {
                    AccountingUnit = t.Key.AccountingUnit,
                    UnitType = t.Key.UnitType == "行政后勤" ? "行政工勤" : t.Key.UnitType,
                    Amount = t.Sum(s => s.Amount)
                });

            var clinicalTypes = new UnitType[] { UnitType.医生组, UnitType.其他医生组, UnitType.医技组, UnitType.其他医技组, UnitType.护理组, UnitType.其他护理组, UnitType.特殊核算组 };
            var clinicalTypesString = clinicalTypes.Select(w => w.ToString()).ToList();
            var clinicalTypesInt = clinicalTypes.Select(w => (int)w).ToList();
            var clinicalComputes = _perforRescomputeRepository.GetEntities(t => t.AllotID == allotId && clinicalTypesString.Contains(t.UnitType)) ?? new List<res_compute>();
            var clinicalEmployees = _perforImemployeeclinicRepository.GetEntities(t => t.AllotID == allotId && clinicalTypesString.Contains(t.UnitType));
            var isShowManage = IsShowManage(allotId);
            // 计算 科主任/护士长 管理绩效
            clinicalComputes?.ForEach(t =>
            {
                if (isShowManage == 2)
                {
                    var employee = clinicalEmployees.FirstOrDefault(e => e.PersonnelNumber == t.JobNumber && e.AccountingUnit == t.AccountingUnit);
                    var scoreAverageRate = t.ScoreAverageRate ?? employee.ScoreAverageRate ?? 1;
                    var attendance = t.Attendance ?? employee.Attendance ?? 0;
                    t.GiveFee = Math.Round((t.ShouldGiveFee ?? 0) * scoreAverageRate * attendance + (t.Punishment ?? 0) + (t.AssessLaterOtherFee ?? 0), 2);
                    t.RealGiveFee = Math.Round(t.GiveFee * (t.Adjust ?? 1m) + (t.AdjustLaterOtherFee ?? 0) ?? 0, 2);
                }
            });

            // 临床科室
            var accounts = perforResaccountRepository.GetEntities(t => t.AllotID == allotId && clinicalTypesInt.Contains(t.UnitType.Value)) ?? new List<res_account>();
            var clinicalResult = accounts.Select(t => new DeptResponse
            {
                UnitName = ((UnitType)t.UnitType).ToString(),
                AccountingUnit = t.AccountingUnit,
                Department = t.AccountingUnit,
                PerforFee = t.PerforFee,
                WorkloadFee = t.WorkloadFee,
                AssessBeforeOtherFee = t.AssessBeforeOtherFee,
                PerforTotal = t.PerforTotal,
                ScoringAverage = t.ScoringAverage,
                Extra = t.Extra,
                MedicineExtra = t.MedicineExtra,
                MaterialsExtra = t.MaterialsExtra,
                AssessLaterOtherFee = t.AssessLaterOtherFee,
                AssessLaterPerforTotal = t.AssessLaterPerforTotal,
                AdjustFactor = t.AdjustFactor,
                AdjustLaterOtherFee = t.AdjustLaterOtherFee,
                AssessLaterManagementFee = clinicalComputes?.Where(w => w.AccountingUnit == t.AccountingUnit && w.UnitType == ((UnitType)t.UnitType).ToString())?.Sum(c => c.RealGiveFee),
                RealGiveFee = t.RealGiveFee,
            });

            result.AddRange(clinicalResult);
            // 特殊核算组科室
            var specialunits = _perforResspecialunitRepository.GetEntities(t => t.AllotID == allotId) ?? new List<res_specialunit>();

            var specialResult = specialunits.GroupBy(t => new { t.AccountingUnit }).Select(t => new DeptResponse
            {
                UnitName = UnitType.特殊核算组.ToString(),
                AccountingUnit = t.Key.AccountingUnit,
                Department = t.Key.AccountingUnit,
                PerforFee = t.Max(w => w.ResultsTotalFee),
                WorkloadFee = 0,
                AssessBeforeOtherFee = t.Max(w => w.AssessBeforeOtherFee),
                PerforTotal = t.Max(w => w.PerforTotal),
                ScoringAverage = t.Max(w => w.ScoringAverage),
                Extra = t.Max(w => w.Punishment),
                MedicineExtra = t.Max(w => w.MedicineExtra),
                MaterialsExtra = t.Max(w => w.MaterialsExtra),
                AssessLaterOtherFee = t.Max(w => w.AssessLaterOtherFee),
                AssessLaterPerforTotal = Math.Round((t.Max(w => w.PerforTotal) * t.Max(w => w.ScoringAverage) + t.Max(w => w.MedicineExtra) + t.Max(w => w.MaterialsExtra) + t.Max(w => w.Punishment) + t.Max(w => w.AssessLaterOtherFee)) ?? 0),
                AdjustFactor = t.Max(w => w.Adjust),
                AdjustLaterOtherFee = t.Max(w => w.AdjustLaterOtherFee),
                AssessLaterManagementFee = clinicalComputes?.Where(w => w.AccountingUnit == t.Key.AccountingUnit && w.UnitType == UnitType.特殊核算组.ToString())?.Sum(c => c.RealGiveFee),
                RealGiveFee = t.Max(w => w.RealGiveFee),
            }).Distinct();
            result.AddRange(specialResult);

            // 需要二次分配的行政科室
            var needSecond = perforResaccountRepository.GetEntities(t => t.AllotID == allotId && t.UnitType.Value == (int)UnitType.行政后勤 && t.NeedSecondAllot == "是") ?? new List<res_account>();
            var needSecondResult = needSecond.Select(t => new DeptResponse
            {
                UnitName = ((UnitType)t.UnitType).ToString() == "行政后勤" ? "行政工勤" : ((UnitType)t.UnitType).ToString(),
                AccountingUnit = t.AccountingUnit,
                Department = t.AccountingUnit,
                PerforFee = t.PerforFee,
                WorkloadFee = t.WorkloadFee,
                AssessBeforeOtherFee = t.AssessBeforeOtherFee,
                PerforTotal = t.PerforTotal,
                ScoringAverage = t.ScoringAverage,
                Extra = t.Extra,
                MedicineExtra = t.MedicineExtra,
                MaterialsExtra = t.MaterialsExtra,
                AssessLaterOtherFee = t.AssessLaterOtherFee,
                AssessLaterPerforTotal = t.AssessLaterPerforTotal,
                AdjustFactor = t.AdjustFactor,
                AdjustLaterOtherFee = t.AdjustLaterOtherFee,
                AssessLaterManagementFee = clinicalComputes?.Where(w => w.AccountingUnit == t.AccountingUnit && w.UnitType == ((UnitType)t.UnitType).ToString())?.Sum(c => c.RealGiveFee),
                RealGiveFee = t.RealGiveFee,
            });

            result.AddRange(needSecondResult);

            // 不需要二次分配的行政科室
            var officeTypes = new List<string> { "行政工勤", "行政高层", "行政中层" };
            var computes = _perforRescomputeRepository.GetEntities(t => t.AllotID == allotId && officeTypes.Contains(t.AccountType) && t.NeedSecondAllot == "否") ?? new List<res_compute>();

            var officeResult = computes.GroupBy(t => new { t.AccountingUnit, t.AccountType, t.UnitType }).Select(t => new DeptResponse
            {
                UnitName = t.Key.AccountType == "行政后勤" ? "行政工勤" : t.Key.AccountType,
                AccountingUnit = t.Key.AccountingUnit,
                Department = t.Key.AccountingUnit,
                PerforFee = 0,
                WorkloadFee = 0,
                AssessBeforeOtherFee = 0,
                PerforTotal = t.Sum(w => w.PerforTotal),
                ScoringAverage = 1,
                Extra = 0,
                MedicineExtra = 0,
                MaterialsExtra = 0,
                AssessLaterOtherFee = 0,
                AssessLaterPerforTotal = t.Sum(w => w.GiveFee),
                AdjustFactor = t.FirstOrDefault()?.Adjust ?? 1,
                AdjustLaterOtherFee = t.Sum(w => w.AdjustLaterOtherFee),
                RealGiveFee = t.Sum(w => w.RealGiveFee),
            }); ;
            result.AddRange(officeResult);
            // 医院其他绩效、科主任护士长管理绩效、合并实发
            foreach (var item in result)
            {
                item.AprPerforAmount = otherPerformances?.Where(w => w.AccountingUnit == item.AccountingUnit && w.UnitType == item.UnitName)?.Sum(w => w.Amount) ?? 0;
                item.AssessLaterManagementFee = item.AssessLaterManagementFee ?? 0;
                item.RealGiveFee = (item.RealGiveFee ?? 0) + item.AssessLaterManagementFee + item.AprPerforAmount;
            }

            var enumItems = EnumHelper.GetItems<AccountUnitType>();
            result = result.OrderBy(t => enumItems.FirstOrDefault(e => e.Name == t.UnitName)?.Value)/*.ThenBy(t => t.AccountingUnit)*/.ToList();
            return result;
        }


        /// <summary>
        /// 查看科室绩效
        /// </summary>
        /// <param name="allotId"></param>
        /// <param name="department"></param>
        /// <param name="type"></param>
        /// <returns></returns>
        public DeptDetailResponse GetDepartmentDetail(int allotId, string department, int type)
        {
            if (type == 1)
            {
                var accountList = perforResaccountRepository.GetEntities(t => t.UnitType != (int)UnitType.护理组 && t.AllotID == allotId && t.AccountingUnit == department);
                if (accountList != null)
                    return GetDepartmentDetail(allotId, accountList.First().ID, type);
            }
            else if (type == 2)
            {
                var accountList = perforResaccountRepository.GetEntities(t => t.UnitType == (int)UnitType.护理组 && t.AllotID == allotId && t.AccountingUnit == department);
                if (accountList != null)
                    return GetDepartmentDetail(allotId, accountList.First().ID, type);
            }
            return null;
        }

        /// <summary>
        /// 返回科室详情
        /// </summary>
        /// <param name="allotId"></param>
        /// <param name="accountId"></param>
        /// <param name="type"> 1 医生组 2 护理组</param>
        /// <returns></returns>
        public DeptDetailResponse GetDepartmentDetail(int allotId, int accountId, int type)
        {
            var sheetList = _perforPerSheetRepository.GetEntities(t => t.AllotID == allotId);
            if (type == 1)
            {
                var account = perforResaccountRepository.GetEntity(t => t.UnitType != (int)UnitType.护理组 && t.AllotID == allotId && t.ID == accountId);

                DeptDetailResponse response = new DeptDetailResponse()
                {
                    Pandect = Mapper.Map<PerDataAccountBaisc>(account),
                    Economic = new List<DeptDetail>(),
                    Workload = new List<DeptDetail>()
                };

                var sheetWorkload = sheetList.FirstOrDefault(t => t.SheetType == (int)SheetType.ComputeDoctorWorkload);
                if (sheetWorkload == null)
                    return null;
                var dataWorkloadList = _perforImDataRepository.GetEntities(t => t.SheetID == sheetWorkload.ID && t.IsTotal != 1 && t.AccountingUnit == account.AccountingUnit);
                if (dataWorkloadList != null && dataWorkloadList.Count > 0)
                    dataWorkloadList.ForEach(t => response.Workload.Add(new DeptDetail { ItemName = t.TypeName, ItemValue = t.CellValue ?? 0 }));

                var sheetEconomic = sheetList.FirstOrDefault(t => t.SheetType == (int)SheetType.ComputeEconomic);
                if (sheetEconomic == null)
                    return null;
                var dataEconomicList = _perforImDataRepository.GetEntities(t => t.SheetID == sheetEconomic.ID && t.UnitType == 1 && t.IsTotal != 1 && t.AccountingUnit == account.AccountingUnit);
                if (dataEconomicList != null && dataEconomicList.Count > 0)
                    dataEconomicList.ForEach(t => response.Economic.Add(new DeptDetail { ItemName = t.TypeName, ItemValue = t.CellValue ?? 0 }));

                return response;
            }
            else if (type == 2)
            {
                var nurse = perforResaccountRepository.GetEntity(t => t.UnitType == (int)UnitType.护理组 && t.AllotID == allotId && t.ID == accountId);
                DeptDetailResponse response = new DeptDetailResponse()
                {
                    Pandect = Mapper.Map<PerDataAccountBaisc>(nurse),
                    Economic = new List<DeptDetail>(),
                    Workload = new List<DeptDetail>()
                };

                var sheetWorkload = sheetList.FirstOrDefault(t => t.SheetType == (int)SheetType.ComputeNurseWorkload);
                if (sheetWorkload == null)
                    return null;
                var dataWorkloadList = _perforImDataRepository.GetEntities(t => t.SheetID == sheetWorkload.ID && t.IsTotal != 1 && t.AccountingUnit == nurse.AccountingUnit);
                if (dataWorkloadList != null && dataWorkloadList.Count > 0)
                    dataWorkloadList.ForEach(t => response.Workload.Add(new DeptDetail { ItemName = t.TypeName, ItemValue = t.CellValue ?? 0 }));

                var sheetEconomic = sheetList.FirstOrDefault(t => t.SheetType == (int)SheetType.ComputeEconomic);
                if (sheetEconomic == null)
                    return null;
                var dataEconomicList = _perforImDataRepository.GetEntities(t => t.SheetID == sheetEconomic.ID && t.UnitType == 2 && t.IsTotal != 1 && t.AccountingUnit == nurse.AccountingUnit);
                if (dataEconomicList != null && dataEconomicList.Count > 0)
                    dataEconomicList.ForEach(t => response.Economic.Add(new DeptDetail { ItemName = t.TypeName, ItemValue = t.CellValue ?? 0 }));
                return response;
            }

            return null;
        }

        #region 绩效发放列表

        /// <summary>
        /// 返回绩效发放列表
        /// </summary>
        /// <param name="allotId">绩效ID</param>
        /// <param name="hospitalId"></param>
        /// <param name="isShowManage"> 仅显示管理绩效 isShowManage == 1 </param>
        /// <returns></returns>
        public List<ComputeResponse> AllCompute(int allotId, int hospitalId, int isShowManage)
        {
            // 获取一次次绩效结果
            var list = GetAllotPerformance(allotId, hospitalId, isShowManage);
            // 获取二次绩效结果
            var seconds = GetSecondPerformance(allotId);
            if (seconds != null)
                list?.AddRange(seconds);

            // 补充医院其他绩效
            var result = AddAprAmount(allotId, list);

            // 预留比例
            if (result != null)
            {
                var types = new string[] { UnitType.行政高层.ToString(), UnitType.行政中层.ToString(), UnitType.行政后勤.ToString(), "行政工勤" };
                var empDic = perforPeremployeeRepository.GetEntities(w => w.AllotId == allotId);
                foreach (var item in result)
                {
                    // 二次分配默认 调节系数100%
                    var adjust = item.Source == "二次绩效" ? 1 : (item.Adjust ?? 1);
                    // 计算调节后业绩绩效、管理绩效
                    item.PerforSumFee = Math.Round((item.PerforSumFee * adjust ?? 0), 2, MidpointRounding.AwayFromZero);
                    item.PerforManagementFee = Math.Round((item.PerforManagementFee * adjust ?? 0), 2, MidpointRounding.AwayFromZero);

                    var real = Math.Round((item.PerforSumFee ?? 0) + (item.PerforManagementFee ?? 0) + (item.AdjustLaterOtherFee ?? 0), 2, MidpointRounding.AwayFromZero);
                    // 这里是为了“全院核算绩效发放”金额一致
                    if (item.Source == "一次绩效")
                    {
                        if (isShowManage == 1)
                            real = Math.Round(real, 0);
                        else if (types.Contains(item.UnitType))
                            real = Math.Round(real, 0);
                    }

                    item.OthePerfor = Math.Round((item.OthePerfor ?? 0), 2, MidpointRounding.AwayFromZero);
                    item.NightWorkPerfor = Math.Round((item.NightWorkPerfor ?? 0), 2, MidpointRounding.AwayFromZero);

                    item.ShouldGiveFee = Math.Round(real + (item.OthePerfor ?? 0) + (item.NightWorkPerfor ?? 0), 2, MidpointRounding.AwayFromZero);

                    item.ReservedRatio = empDic?.FirstOrDefault(w => w.PersonnelNumber == item.JobNumber)?.ReservedRatio ?? 0;
                    item.ReservedRatioFee = Math.Round(real * (item.ReservedRatio ?? 0), 2, MidpointRounding.AwayFromZero);
                    item.RealGiveFee = Math.Round(item.ShouldGiveFee - (item.ReservedRatioFee ?? 0) ?? 0, 2, MidpointRounding.AwayFromZero);
                    // 人员信息使用人员字典中数据
                    item.AccountingUnit = empDic?.FirstOrDefault(w => w.PersonnelNumber == item.JobNumber)?.AccountingUnit ?? "";
                    item.UnitType = empDic?.FirstOrDefault(w => w.PersonnelNumber == item.JobNumber)?.UnitType ?? "";
                    item.EmployeeName = empDic?.FirstOrDefault(w => w.PersonnelNumber == item.JobNumber)?.DoctorName ?? "";
                }
            }

            return result?.OrderByDescending(t => t.AccountingUnit).ToList();
        }

        /// <summary>
        /// 获取一次次绩效结果
        /// </summary>
        /// <param name="allotId"></param>
        /// <returns></returns>
        private List<ComputeResponse> GetAllotPerformance(int allotId, int hospitalId, int isShowManage)
        {
            var mTypes = new List<string>
            {
                AccountUnitType.护士长.ToString(), AccountUnitType.科主任.ToString(),
                AccountUnitType.行政中层.ToString(), AccountUnitType.行政高层.ToString(),
                AccountUnitType.行政工勤.ToString()
            };
            //// 获取医院是否开启后勤二次分配
            //var hospital = hospitalRepository.GetEntity(w => w.ID == hospitalId);
            //if (hospital?.IsOpenLogisticsSecondAllot != 1)
            //    mTypes.Add(AccountUnitType.行政工勤.ToString());

            var types1 = new List<string> { AccountUnitType.护士长.ToString(), AccountUnitType.科主任.ToString() };
            var types2 = new List<string> { AccountUnitType.行政中层.ToString(), AccountUnitType.行政高层.ToString() };
            var types3 = new List<string> { AccountUnitType.行政工勤.ToString() };

            //// 业务中层人员信息
            //var empolyeeList = _perforImemployeeclinicRepository.GetEntities(t => t.AllotID == allotId);
            // 一次绩效 获取特定人员绩效结果
            var allot = _perforRescomputeRepository.GetEntities(t => t.AllotID == allotId && mTypes.Contains(t.AccountType) && (string.IsNullOrEmpty(t.NeedSecondAllot) || t.NeedSecondAllot == "否"))?.OrderByDescending(t => t.AccountingUnit);
            //var apramounts = perapramountRepository.GetEntities(t => t.AllotId == allotId);

            return allot?.Select(t =>
            {
                var comp = new ComputeResponse("一次绩效", t.AccountingUnit, t.EmployeeName, t.JobNumber, t.JobTitle);
                comp.UnitType = t.AccountType;
                comp.Adjust = t.Adjust;
                comp.AdjustLaterOtherFee = t.AdjustLaterOtherFee;

                // 行政中层  行政高层 补充  夜班费
                if (types2.Contains(t.AccountType))
                {
                    comp.PerforSumFee = t.GiveFee;
                    comp.PerforManagementFee = 0;
                    comp.NightWorkPerfor = t.NightWorkPerfor;
                }

                // 科主任/护士长
                if (types1.Contains(t.AccountType))
                {
                    // 等同于考核后管理绩效 AssessLaterManagementFee
                    comp.PerforManagementFee = Math.Round(t.ShouldGiveFee * t.ScoreAverageRate * t.Attendance + t.Punishment ?? 0, 2);
                    // 仅显示管理绩效
                    if (isShowManage == 2)
                        comp.PerforSumFee = 0;
                    else
                        comp.PerforSumFee = t.Avg;
                }
                // 行政工勤
                if (types3.Contains(t.AccountType) && t.NeedSecondAllot?.Trim() == "否")
                {
                    comp.PerforSumFee = t.GiveFee;
                    comp.AdjustLaterOtherFee = 0;
                    comp.PerforManagementFee = 0;
                }

                return comp;
            }).ToList();
        }

        /// <summary>
        /// 获取二次绩效结果
        /// </summary>
        /// <param name="allotId"></param>
        /// <returns></returns>
        private List<ComputeResponse> GetSecondPerformance(int allotId)
        {
            var again = _perforAgcomputeRepository.GetEntities(t => t.AllotId == allotId);
            if (again != null && again.Any())
            {
                var disAgains = again.Select(w => new
                {
                    w.AllotId,
                    w.SecondId,
                    w.UnitType,
                    w.Department,
                    w.WorkPost,
                    w.JobNumber,
                    w.PersonName,
                    w.PerforSumFee,
                    w.OthePerfor,
                    w.NightWorkPerfor,
                    w.RealGiveFee
                }).Distinct();
                var group = disAgains
                    .GroupBy(t => new { t.UnitType, t.Department, t.WorkPost, t.JobNumber, t.PersonName })
                    .Select(t =>
                    {
                        var comp = new ComputeResponse("二次绩效", t.Key.Department, t.Key.PersonName, t.Key.JobNumber, t.Key.WorkPost);
                        comp.UnitType = t.Key.UnitType;
                        comp.PerforSumFee = t.Sum(g => g.PerforSumFee);
                        comp.NightWorkPerfor = t.Sum(g => g.NightWorkPerfor);
                        return comp;
                    });
                return group?.ToList();
            }

            return null;
        }

        /// <summary>
        /// 添加额外绩效金额(基础绩效、其他绩效等)
        /// </summary>
        /// <param name="allotId"></param>
        /// <param name="computes"></param>
        public List<ComputeResponse> AddAprAmount(int allotId, List<ComputeResponse> computes)
        {
            if (computes == null || !computes.Any())
                return computes;

            var list = perapramountRepository.GetEntities(t => t.AllotId == allotId && t.Status == 3);
            if (list == null || !list.Any())
                return computes;

            List<string> uses = new List<string>();
            foreach (var item in computes.GroupBy(w => new { w.AccountingUnit, w.JobNumber }))
            {
                // 补充过一次就不在补充了
                var emp = computes.Where(w => w.AccountingUnit == item.Key.AccountingUnit && w.JobNumber == item.Key.JobNumber)
                    .OrderByDescending(w => w.Source).FirstOrDefault();
                var apramount = list.Where(t => t.AccountingUnit == emp.AccountingUnit
                     && !string.IsNullOrEmpty(t.PersonnelNumber) && emp.JobNumber?.Trim() == t.PersonnelNumber?.Trim());
                // 如果医院其他绩效 已经被使用，则不再多次带出，防止单个人多次出现造成金额叠加
                var tag = $"{(emp.AccountingUnit ?? "")}-{(emp.JobNumber ?? "")}";
                if (apramount != null && !uses.Contains(tag))
                {
                    emp.OthePerfor = apramount?.Sum(w => w.Amount) ?? 0;
                    uses.Add(tag);
                }

                //foreach (var emp in computes)
                //{
                //    if (!emp.OthePerfor.HasValue || emp.OthePerfor == 0)
                //    {
                //        var apramount = list.Where(t => t.AccountingUnit == emp.AccountingUnit
                //            && !string.IsNullOrEmpty(t.PersonnelNumber) && emp.JobNumber?.Trim() == t.PersonnelNumber?.Trim());
                //        emp.OthePerfor = apramount?.Sum(w => w.Amount) ?? 0;
                //    }
                //}
            }

            return computes;
        }

        ///// <summary>
        ///// 返回绩效发放列表
        ///// 科主任护士长返回管理绩效
        ///// </summary>
        ///// <param name="allotId">绩效ID</param>
        ///// <returns></returns>
        //public List<ComputeResponse> AllManageCompute(int allotId)
        //{
        //    var list = new List<ComputeResponse>();
        //    var mTypes = new[] { AccountUnitType.护士长.ToString(), AccountUnitType.科主任.ToString(), AccountUnitType.行政中层.ToString(), AccountUnitType.行政高层.ToString() };

        //    var allot = _perforRescomputeRepository.GetEntities(t => t.AllotID == allotId && mTypes.Contains(t.AccountType))?.OrderByDescending(t => t.AccountingUnit);
        //    if (allot != null && allot.Any(t => t.AllotID == allotId))
        //    {
        //        var types = new List<string> { AccountUnitType.护士长.ToString(), AccountUnitType.科主任.ToString() };
        //        list = allot.Select(t => new ComputeResponse
        //        {
        //            Source = "一次绩效",
        //            AccountingUnit = t.AccountingUnit,
        //            EmployeeName = t.EmployeeName,
        //            JobNumber = t.JobNumber,
        //            JobTitle = t.JobTitle,
        //            RealGiveFee = types.Contains(t.AccountType) ? t.ShouldGiveFee : t.RealGiveFee
        //        }).ToList();
        //    }
        //    var again = _perforAgcomputeRepository.GetEntities(t => t.AllotId == allotId);
        //    if (again != null && again.Any())
        //    {
        //        var group = again.GroupBy(t => new { t.Department, t.WorkPost, t.JobNumber, t.PersonName })
        //            .Select(t => new
        //            {
        //                department = t.Key.Department,
        //                jobtitle = t.Key.WorkPost,
        //                jobnumber = t.Key.JobNumber,
        //                name = t.Key.PersonName,
        //                fee = t.Sum(g => g.RealGiveFee)
        //            });
        //        list.AddRange(group.Select(t => new ComputeResponse
        //        {
        //            Source = "二次绩效",
        //            AccountingUnit = t.department,
        //            JobNumber = t.jobnumber,
        //            JobTitle = t.jobtitle,
        //            EmployeeName = t.name,
        //            RealGiveFee = t.fee
        //        }).OrderByDescending(t => t.AccountingUnit));
        //    }
        //    var result = AddAprAmount(allotId, list);
        //    if (result != null)
        //    {
        //        var empDic = perforPeremployeeRepository.GetEntities(w => w.AllotId == allotId);
        //        foreach (var item in result)
        //        {
        //            var temp = item.RealGiveFee ?? 0;
        //            item.ReservedRatio = empDic?.FirstOrDefault(w => w.DoctorName == item.EmployeeName && w.PersonnelNumber == item.JobNumber)?.ReservedRatio ?? 0;
        //            item.ReservedRatioFee = temp * item.ReservedRatio;
        //            item.RealGiveFee = temp - item.ReservedRatioFee;
        //        }
        //    }
        //    return result;
        //}

        #endregion 绩效发放列表

        public res_compute GetComputeSingle(int computeid)
        {
            return _perforRescomputeRepository.GetEntity(t => t.ID == computeid);
        }

        /// <summary>
        /// 修改实发绩效
        /// </summary>
        /// <param name="type"></param>
        /// <param name="id"></param>
        /// <param name="score"></param>
        /// <returns></returns>
        public res_compute UpdateRealfee(ComputerRequest request, int userId, string realName)
        {
            var compute = _perforRescomputeRepository.GetEntity(t => t.ID == request.ComputeId);
            var log = JsonHelper.Deserialize<List<ChangeLog>>(compute.ChangeLog);
            log = log ?? new List<ChangeLog>();
            log.Add(new ChangeLog
            {
                uid = userId,
                user = realName,
                date = DateTime.Now,
                value = compute.RealGiveFee
            });
            compute.RealGiveFee = request.RealGiveFee;
            compute.ChangeLog = JsonHelper.Serialize(log);
            if (!_perforRescomputeRepository.Update(compute))
                throw new PerformanceException("修改失败");

            return compute;
        }

        /// <summary>
        /// 返回绩效平均值
        /// </summary>
        /// <param name="type"></param>
        /// <param name="id"></param>
        /// <param name="score"></param>
        /// <returns></returns>
        public List<res_baiscnorm> GetBaiscnorm(int allotId)
        {
            return perforResbaiscnormRepository.GetEntities(t => t.AllotID == allotId)?.OrderBy(t => t.PositionName).ToList();
        }

        /// <summary>
        /// 返回科室详情
        /// </summary>
        /// <param name="allotId"></param>
        /// <param name="accountId"></param>
        /// <param name="type"></param>
        /// <returns></returns>
        public DeptDataDetails<DetailModuleExtend> DeptDetail(int accountId)
        {
            var account = perforResaccountRepository.GetEntity(t => t.ID == accountId);
            var allot = perforPerallotRepository.GetEntity(t => t.ID == account.AllotID);
            var persheet = _perforPerSheetRepository.GetEntities(t => t.AllotID == account.AllotID);
            var headers = _perforImheaderRepository.GetEntities(t => t.AllotID == account.AllotID);
            var basicData = _perforImDataRepository.GetEntities(t => t.AllotID == account.AllotID && t.AccountingUnit == account.AccountingUnit);

            DeptDataDetails deptDetails = new DeptDataDetails
            {
                ShowFormula = allot.ShowFormula,
                Pandect = Mapper.Map<PerDataAccountBaisc>(account),
                Detail = new List<DetailDtos>()
            };

            if (basicData == null || !basicData.Any()) return MergeDetails(deptDetails);

            var sheetType = new List<int>
            {
                (int)SheetType.Income, (int)SheetType.OtherIncome, (int)SheetType.Expend, (int)SheetType.Workload,
                (int)SheetType.AccountExtra,(int)SheetType.AccountDrugAssess, (int)SheetType.AccountMaterialsAssess, (int)SheetType.AccountScoreAverage,
                (int)SheetType.AccountAdjustLaterOtherFee, (int)SheetType.BudgetRatio, (int)SheetType.AssessBeforeOtherFee,
            };

            int groupbasis = 1; string single = "";
            foreach (var stype in sheetType)
            {
                foreach (var sheet in persheet.Where(t => t.SheetType == stype))
                {
                    var type = TypeConversion(account.UnitType);
                    if (single != "" && sheet.SheetName.Substring(0, 3) != single)
                        groupbasis += 1;
                    single = sheet.SheetName.Substring(0, 3);

                    var sheetName = new Regex("[0-9]*").Replace(sheet.SheetName, "", 5).Replace(".", "").Replace(" ", "");
                    // 只是显示好看而已
                    if (sheetName != "科室考核")
                        sheetName = sheetName.Replace("科室绩效", "").Replace("科室", "");
                    var (sheettype, amount) = ClinicDepartmentDetail(persheet, account, basicData, sheet, type, sheetName);
                    (sheettype, amount) = CommonDepartmentDetail(basicData, sheet, type, sheettype, amount);
                    var items = CommonDetailItems(basicData, headers, sheet, type);

                    if (sheet.SheetType == (int)SheetType.Workload)
                    {
                        items = items.Where(w => w.Factor.HasValue && w.Factor != 0).ToList();
                        if ((sheetName.Contains("医生") && account.UnitType == (int)UnitType.护理组) || (sheetName.Contains("护理") && account.UnitType != (int)UnitType.护理组))
                            continue;

                        var workitems = cofworkitemRepository.GetEntities(t => t.AllotID == account.AllotID);
                        //var allotCmi = cofcmiRepository.GetEntity(t => t.AllotId == account.AllotID && t.UnitType == account.UnitType && t.AccountingUnit == account.AccountingUnit);
                        var medicineFactor = GetFactors(persheet, basicData, type, SheetType.WorkloadMedicineProp);
                        var cmiFactor = GetFactors(persheet, basicData, type, SheetType.WorkloadCMI);
                        var inclineFactor = GetFactors(persheet, basicData, type, SheetType.WorkloadIncline);

                        foreach (var dto in items)
                        {
                            if (workitems != null && workitems.Any(a => a.Type == 1 && a.Item == dto.ItemName) && medicineFactor != null)
                                dto.MediFactor = medicineFactor;
                            if (workitems != null && workitems.Any(a => a.Type == 2 && a.Item == dto.ItemName) && cmiFactor != null)
                                dto.CMIFactor = cmiFactor;
                            if (workitems != null && workitems.Any(a => a.Type == 3 && a.Item == dto.ItemName) && inclineFactor != null)
                                dto.InclineFactor = inclineFactor;
                            dto.ItemValue = dto.ItemValue * (dto.MediFactor ?? 1) * (dto.CMIFactor ?? 1) * (dto.InclineFactor ?? 1);
                        }
                    }

                    if (sheet.SheetType == (int)SheetType.OtherIncome)
                        items = items.Where(t => (t.ItemValue ?? 0) != 0).ToList();

                    if (items != null && items.Count > 0)
                    {
                        var item = new DetailDtos { ItemName = sheetName, IncomeType = sheettype, OriginalType = sheet.SheetType ?? 0, Amount = amount, GroupBasis = groupbasis, Items = items };
                        deptDetails.Detail.Add(item);
                    }
                }
            }

            // 展示额外处理，根据禅道057
            deptDetails.Pandect.ScoringAverage = deptDetails.Detail?.FirstOrDefault(w => w.OriginalType == (int)SheetType.AccountScoreAverage)?.Amount ?? deptDetails.Pandect.ScoringAverage;
            deptDetails.Pandect.Extra = deptDetails.Detail?.FirstOrDefault(w => w.OriginalType == (int)SheetType.AccountExtra)?.Amount ?? deptDetails.Pandect.Extra;
            deptDetails.Pandect.MaterialsExtra = deptDetails.Detail?.FirstOrDefault(w => w.OriginalType == (int)SheetType.AccountMaterialsAssess)?.Amount ?? deptDetails.Pandect.MaterialsExtra;
            deptDetails.Pandect.MedicineExtra = deptDetails.Detail?.FirstOrDefault(w => w.OriginalType == (int)SheetType.AccountDrugAssess)?.Amount ?? deptDetails.Pandect.MedicineExtra;

            return MergeDetails(deptDetails);
            //return deptDetails;
        }

        private decimal? GetFactors(List<per_sheet> persheet, List<im_data> basicData, UnitType type, SheetType sheetType)
        {
            var sheet = persheet.FirstOrDefault(w => w.SheetType == (int)sheetType);
            return basicData.FirstOrDefault(t => t.SheetID == sheet?.ID && t.UnitType == (int)type && t.IsTotal == 1)?.CellValue;
        }

        private (int sheettype, decimal amount) ClinicDepartmentDetail(List<per_sheet> persheet, res_account account, List<im_data> basicData, per_sheet sheet, UnitType type, string sheetName)
        {
            var sheettype = 1;
            var amount = 0m;

            if (sheet.SheetType == (int)SheetType.Income)
            {
                sheettype = 1;
                amount = basicData.Where(t => t.SheetID == sheet.ID && t.UnitType == (int)type && t.IsTotal != 1)?.Sum(t => t.IsFactor == 1 ? t.CellValue * (t.FactorValue ?? 0) : t.CellValue) ?? 0;
            }
            else if (sheet.SheetType == (int)SheetType.Workload)
            {
                sheettype = 3;
                amount = account.WorkloadFee ?? 0m;
            }
            else if (sheet.SheetType == (int)SheetType.OtherIncome)
            {
                sheettype = 1;
                amount = basicData.Where(t => t.SheetID == sheet.ID && t.UnitType == (int)type && t.IsTotal != 1)?.Sum(t => t.IsFactor == 1 ? t.CellValue * (t.FactorValue ?? 0) : t.CellValue) ?? 0;
            }
            else if (sheet.SheetType == (int)SheetType.Expend)
            {
                //科室经济
                var sheetEconomic = persheet.FirstOrDefault(t => t.SheetType == (int)SheetType.ComputeEconomic);
                var dataEconomicList = basicData.Where(t => t.SheetID == sheetEconomic?.ID && t.IsTotal != 1 && t.AccountingUnit == account.AccountingUnit).ToList();
                string typeValue = EnumHelper.GetDescription((UnitType)account.UnitType);
                var economic = dataEconomicList?.Select(t => new
                {
                    ItemName = t.TypeName.Replace($"({typeValue})", ""),
                    ItemValue = t.CellValue ?? 0,
                    t.UnitType
                });
                sheettype = 2;
                amount = economic.FirstOrDefault(t => t.ItemName.Contains(sheetName) && t.UnitType == (int)type)?.ItemValue ?? 0m;
            }
            return (sheettype, amount);
        }

        private (int sheettype, decimal amount) CommonDepartmentDetail(List<im_data> basicData, per_sheet sheet, UnitType type, int sheettype = -1, decimal amount = 0)
        {
            //var sheettype = 1; var amount = 0m;

            //if (pairs.ContainsKey((SheetType)sheet.SheetType))
            //{
            //    sheettype = 5;
            //    amount = pairs[(SheetType)sheet.SheetType] ?? 0;
            //}
            //else if (sheet.SheetType == (int)SheetType.AccountScoreAverage)
            //{
            //    sheettype = 8;
            //    amount = Math.Round(basicData.Where(t => t.SheetID == sheet.ID && t.UnitType == (int)type && t.IsTotal == 1)?.FirstOrDefault()?.CellValue ?? 0, 4);
            //}
            //else if (sheet.SheetType == (int)SheetType.AccountAdjustLaterOtherFee)
            //{
            //    sheettype = 9;
            //    amount = Math.Round(basicData.Where(t => t.SheetID == sheet.ID && t.UnitType == (int)type && t.IsTotal == 1)?.FirstOrDefault()?.CellValue ?? 0, 0);
            //}

            SheetType[] pairs = new SheetType[]
            {
                SheetType.AccountExtra, SheetType.AccountDrugAssess, SheetType.AccountMaterialsAssess, SheetType.AccountScoreAverage, SheetType.AccountAdjustLaterOtherFee,
                SheetType.AssessBeforeOtherFee, SheetType.BudgetRatio,
            };
            if (pairs.Contains((SheetType)sheet.SheetType))
            {
                sheettype = 5;
                amount = basicData?.Where(t => t.SheetID == sheet.ID && t.UnitType == (int)type && t.IsTotal == 1)?.FirstOrDefault()?.CellValue ?? 0;
                if (sheet.SheetType != (int)SheetType.BudgetRatio)
                    amount = GetDecimal(amount, 0);
            }
            return (sheettype, amount);
        }

        private List<DetailModule> CommonDetailItems(List<im_data> basicData, List<im_header> headers, per_sheet sheet, UnitType type)
        {
            Expression<Func<im_data, bool>> exp = (t) => t.SheetID == sheet.ID && t.IsTotal != 1;

            if (sheet.SheetType == (int)SheetType.Workload && new int[] { (int)UnitType.医技组, (int)UnitType.其他医技组 }.Contains((int)type))
                exp = exp.And(t => new int[] { (int)UnitType.医生组, (int)UnitType.医技组, (int)UnitType.其他医技组 }.Contains(t.UnitType.Value));
            else
                exp = exp.And(t => t.UnitType == (int)type);

            var items = basicData.Where(exp.Compile())?.Select(t => new DetailModule
            {
                ItemName = t.TypeName,
                CellValue = t.CellValue,
                Factor = sheet.SheetType == (int)SheetType.Workload ? t.FactorValue : t.FactorValue * 100,
                ItemValue = t.IsFactor == 1 ? (t.CellValue * (t.FactorValue ?? 0)) : t.CellValue,
            }).ToList();

            if (items != null && items.Any())
            {
                items = items.GroupBy(t => t.ItemName).Select(t =>
                {
                    var dto = new DetailModule
                    {
                        ItemName = t.Key,
                        CellValue = t.Sum(group => group.CellValue),
                        Factor = t.FirstOrDefault().Factor,
                        ItemValue = t.Sum(group => group.ItemValue),
                    };

                    return dto;
                }).ToList();
            }
            var headerData = headers?.Where(t => t.SheetID == sheet.ID);
            if (headerData != null && headerData.Any())
            {
                items = items
                    ?.OrderBy(t => (headerData.FirstOrDefault(h => h.CellValue == t.ItemName)?.PointCell) ?? 100)
                    ?.ThenBy(t => t.ItemName).ToList();
            }
            return items;
        }

        private DeptDataDetails<DetailModuleExtend> MergeDetails(DeptDataDetails details)
        {
            if (details == null) return new DeptDataDetails<DetailModuleExtend>();

            var result = new DeptDataDetails<DetailModuleExtend>()
            {
                ShowFormula = details.ShowFormula,
                Pandect = details.Pandect,
                Detail = new List<DetailDtos<DetailModuleExtend>>(),
            };

            if (details.Detail == null || !details.Detail.Any(t => t.IncomeType == 1)) return result;

            foreach (var groupbasis in details.Detail.Select(t => t.GroupBasis).Distinct())
            {
                var items = new List<DetailModuleExtend>();
                var data = details.Detail.Where(t => t.GroupBasis == groupbasis).ToList();
                if (data.Count() > 1)
                {
                    var depts = new List<string>();
                    data.ForEach(t =>
                    {
                        depts.AddRange(t.Items.Select(o => o.ItemName));
                    });
                    var billing = data.FirstOrDefault(t => t.ItemName.Replace("就诊", "开单").IndexOf("开单") > -1);
                    var execute = data.FirstOrDefault(t => t.ItemName.IndexOf("执行") > -1);
                    foreach (var dept in depts.Distinct().OrderBy(t => t))
                    {
                        var item1 = billing?.Items.FirstOrDefault(t => t.ItemName == dept);
                        var item2 = execute?.Items.FirstOrDefault(t => t.ItemName == dept);

                        items.Add(new DetailModuleExtend
                        {
                            ItemName = dept,
                            ItemValue = item1?.ItemValue,
                            ItemValue2 = item2?.ItemValue,
                            CellValue = item1?.CellValue,
                            CellValue2 = item2?.CellValue,
                            Factor = item1?.Factor,
                            Factor2 = item2?.Factor,
                        });
                    }
                }
                else
                {
                    if (data.FirstOrDefault().ItemName.IndexOf("执行") > -1)
                    {
                        items = data.First().Items.Select(t => new DetailModuleExtend
                        {
                            ItemName = t.ItemName,
                            ItemValue2 = t.ItemValue,
                            CellValue2 = t.CellValue,
                            Factor2 = t.Factor,
                        }).ToList();
                    }
                    else
                    {
                        items = data.First().Items.Select(t => new DetailModuleExtend
                        {
                            ItemName = t.ItemName,
                            ItemValue = t.ItemValue,
                            CellValue = t.CellValue,
                            Factor = t.Factor,
                            MediFactor = t.MediFactor,
                            CMIFactor = t.CMIFactor,
                            InclineFactor = t.InclineFactor,
                        }).ToList();
                    }
                }

                result.Detail.Add(new DetailDtos<DetailModuleExtend>
                {
                    ItemName = data.FirstOrDefault(t => t.ItemName.IndexOf("执行") > -1) is null ? data.First().ItemName :
                    data.FirstOrDefault(t => t.ItemName.IndexOf("执行") > -1).ItemName?.Replace("执行", "开单/执行"),
                    IncomeType = data.First()?.IncomeType ?? 0,
                    OriginalType = data.First()?.OriginalType ?? 0,
                    Amount = data.Sum(w => w.Amount),
                    GroupBasis = groupbasis,
                    Items = items
                });
            }

            return result;
        }

        private UnitType TypeConversion(int? unitType)
        {
            UnitType type = (UnitType)unitType.Value;

            var docUnitTypes = new List<UnitType> { UnitType.专家组, UnitType.其他医生组, UnitType.其他医技组 };
            if (docUnitTypes.Contains(type))
                type = UnitType.医生组;
            else if (type == UnitType.其他护理组)
                type = UnitType.护理组;
            return type;
        }

        public DeptDataDetails DeptOfficeDetail(int accountId)
        {
            var account = perforResaccountRepository.GetEntity(t => t.ID == accountId);
            var allot = perforPerallotRepository.GetEntity(t => t.ID == account.AllotID);
            var computes = _perforRescomputeRepository.GetEntities(t => t.AllotID == account.AllotID && t.AccountType == AccountUnitType.行政工勤.ToString() && t.AccountingUnit == account.AccountingUnit);
            var persheet = _perforPerSheetRepository.GetEntities(t => t.AllotID == account.AllotID);
            var headers = _perforImheaderRepository.GetEntities(t => t.AllotID == account.AllotID);
            var basicData = _perforImDataRepository.GetEntities(t => t.AllotID == account.AllotID && t.AccountingUnit == account.AccountingUnit);

            DeptDataDetails deptDetails = new DeptDataDetails
            {
                ShowFormula = allot.ShowFormula,
                Pandect = Mapper.Map<PerDataAccountBaisc>(account),
                Detail = new List<DetailDtos>()
            };

            var sheetType = new List<int>
            {
                (int)SheetType.AccountExtra, (int)SheetType.AccountDrugAssess, (int)SheetType.AccountMaterialsAssess,
                (int)SheetType.AccountScoreAverage, (int)SheetType.AccountAdjustLaterOtherFee
            };

            var detail = new DetailDtos
            {
                ItemName = "后勤人员",
                IncomeType = 9,
                OriginalType = 4,
                Amount = account.PerforTotal ?? 0,
                Items = new List<DetailModule>(),
                GroupBasis = 1,
            };
            if (computes != null)
            {
                foreach (var item in computes)
                {
                    detail.Items.Add(new DetailModule
                    {
                        JobNumber = item.JobNumber,
                        ItemName = item.EmployeeName,
                        ItemValue = Math.Round(item.PerforTotal ?? 0, 2)
                    });
                }
            }

            deptDetails.Detail.Add(detail);

            if (basicData == null || !basicData.Any()) return deptDetails;

            int groupBasis = 0;
            foreach (var stype in sheetType)
            {
                foreach (var sheet in persheet.Where(t => t.SheetType == stype))
                {
                    groupBasis++;
                    var (sheettype, amount) = CommonDepartmentDetail(basicData, sheet, UnitType.行政后勤);
                    var items = CommonDetailItems(basicData, headers, sheet, UnitType.行政后勤);

                    var sheetName = new Regex("[0-9]*").Replace(sheet.SheetName, "", 5).Replace(".", "").Replace(" ", "");
                    // 只是显示好看而已
                    if (sheetName != "科室考核")
                        sheetName = sheetName.Replace("科室绩效", "").Replace("科室", "");

                    if (items != null && items.Count > 0)
                    {
                        var item = new DetailDtos { ItemName = sheetName, IncomeType = sheettype, OriginalType = sheet.SheetType ?? 0, Amount = amount, GroupBasis = groupBasis, Items = items };
                        deptDetails.Detail.Add(item);
                    }
                }
            }
            // 展示额外处理，根据禅道057
            deptDetails.Pandect.ScoringAverage = deptDetails.Detail?.FirstOrDefault(w => w.OriginalType == (int)SheetType.AccountScoreAverage)?.Amount ?? deptDetails.Pandect.ScoringAverage;
            deptDetails.Pandect.Extra = deptDetails.Detail?.FirstOrDefault(w => w.OriginalType == (int)SheetType.AccountExtra)?.Amount ?? deptDetails.Pandect.Extra;
            deptDetails.Pandect.MaterialsExtra = deptDetails.Detail?.FirstOrDefault(w => w.OriginalType == (int)SheetType.AccountMaterialsAssess)?.Amount ?? deptDetails.Pandect.MaterialsExtra;
            deptDetails.Pandect.MedicineExtra = deptDetails.Detail?.FirstOrDefault(w => w.OriginalType == (int)SheetType.AccountDrugAssess)?.Amount ?? deptDetails.Pandect.MedicineExtra;

            return deptDetails;
        }

        public DeptDataDetails SpecialDeptDetail(ag_secondallot second)
        {
            var allot = perforPerallotRepository.GetEntity(t => t.ID == second.AllotId);
            var special = _perforResspecialunitRepository.GetEntities(t => t.AllotID == second.AllotId && t.Department == second.Department);
            if (special == null || !special.Any())
                return new DeptDataDetails();

            DeptDataDetails deptDetails = new DeptDataDetails
            {
                ShowFormula = allot.ShowFormula,
                Pandect = new PerDataAccountBaisc
                {
                    UnitType = second.UnitType,
                    AccountingUnit = second.Department,
                    //Department = second.Department,
                    ScoringAverage = special.FirstOrDefault()?.ScoringAverage ?? 1,
                    //OtherPerfor1 = special.FirstOrDefault()?.OtherPerfor ?? 0,
                    AdjustFactor = special.FirstOrDefault()?.Adjust ?? 1,
                    Avg = special.FirstOrDefault()?.Avg,
                    RealGiveFee = special.FirstOrDefault()?.RealGiveFee,
                    Number = special.FirstOrDefault()?.Number ?? 0,
                    PerforFee = special.FirstOrDefault()?.GiveFee,
                    PerforTotal = special.FirstOrDefault()?.ResultsTotalFee,
                    Income = special.FirstOrDefault()?.ResultsTotalFee,
                    Extra = special.FirstOrDefault()?.Punishment ?? 0,
                    MedicineExtra = special.FirstOrDefault()?.MedicineExtra ?? 0,
                    MaterialsExtra = special.FirstOrDefault()?.MaterialsExtra ?? 0,
                    AssessBeforeOtherFee = special.FirstOrDefault()?.AssessBeforeOtherFee ?? 0,
                    AssessLaterOtherFee = special.FirstOrDefault()?.AssessLaterOtherFee ?? 0,
                    AdjustLaterOtherFee = special.FirstOrDefault()?.AdjustLaterOtherFee ?? 0,
                },
                Detail = new List<DetailDtos>(),
            };
            var detail = new DetailDtos
            {
                ItemName = "特殊核算单元绩效测算表",
                IncomeType = 4,
                OriginalType = 4,
                Amount = special.First().ResultsTotalFee ?? 0,
                Items = new List<DetailModule>(),
                GroupBasis = 1,
            };
            foreach (var item in special)
            {
                detail.Items.Add(new DetailModule
                {
                    ItemName = item.QuantitativeIndicators,
                    CellValue = item.Quantity,
                    Factor = item.QuantitativeIndicatorsValue,
                    ItemValue = Math.Round(item.QuantitativeFee ?? 0, 2)
                });
            }
            deptDetails.Detail.Add(detail);

            var persheet = _perforPerSheetRepository.GetEntities(t => t.AllotID == second.AllotId);
            var headers = _perforImheaderRepository.GetEntities(t => t.AllotID == second.AllotId);
            var basicData = _perforImDataRepository.GetEntities(t => t.AllotID == second.AllotId && t.AccountingUnit == second.Department);

            var sheetType = new List<int>
            {
                (int)SheetType.AccountExtra,(int)SheetType.AccountDrugAssess, (int)SheetType.AccountMaterialsAssess,
                (int)SheetType.AccountScoreAverage, (int)SheetType.AccountAdjustLaterOtherFee,
                (int)SheetType.BudgetRatio, (int)SheetType.AssessBeforeOtherFee,
            };

            int groupBasis = 0;
            foreach (var stype in sheetType)
            {
                foreach (var sheet in persheet.Where(t => t.SheetType == stype))
                {
                    groupBasis++;
                    var (sheettype, amount) = CommonDepartmentDetail(basicData, sheet, UnitType.特殊核算组);
                    var items = CommonDetailItems(basicData, headers, sheet, UnitType.特殊核算组);

                    var sheetName = new Regex("[0-9]*").Replace(sheet.SheetName, "", 5).Replace(".", "").Replace(" ", "");
                    // 只是显示好看而已
                    if (sheetName != "科室考核")
                        sheetName = sheetName.Replace("科室绩效", "").Replace("科室", "");

                    if (items != null && items.Count > 0)
                    {
                        var item = new DetailDtos { ItemName = sheetName, IncomeType = sheettype, OriginalType = sheet.SheetType ?? 0, Amount = amount, GroupBasis = groupBasis, Items = items };
                        deptDetails.Detail.Add(item);
                    }
                }
            }

            // 展示额外处理，根据禅道057
            deptDetails.Pandect.ScoringAverage = deptDetails.Detail?.FirstOrDefault(w => w.OriginalType == (int)SheetType.AccountScoreAverage)?.Amount ?? deptDetails.Pandect.ScoringAverage;
            deptDetails.Pandect.Extra = deptDetails.Detail?.FirstOrDefault(w => w.OriginalType == (int)SheetType.AccountExtra)?.Amount ?? deptDetails.Pandect.Extra;
            deptDetails.Pandect.MaterialsExtra = deptDetails.Detail?.FirstOrDefault(w => w.OriginalType == (int)SheetType.AccountMaterialsAssess)?.Amount ?? deptDetails.Pandect.MaterialsExtra;
            deptDetails.Pandect.MedicineExtra = deptDetails.Detail?.FirstOrDefault(w => w.OriginalType == (int)SheetType.AccountDrugAssess)?.Amount ?? deptDetails.Pandect.MedicineExtra;

            return deptDetails;
        }

        //private List<DetailModule> GetExtraDetail(int allotId, int unitType, string accountingUnit)
        //{
        //    var result = new List<DetailModule>();
        //    var sheetId = _perforPerSheetRepository.GetEntity(t => t.AllotID == allotId && t.SheetType == (int)SheetType.AccountExtra)?.ID;
        //    if (!sheetId.HasValue) return result;

        //    var data = _perforImDataRepository.GetEntities(t => t.AllotID == allotId && t.SheetID == sheetId && t.UnitType == unitType
        //    && t.AccountingUnit == accountingUnit && t.IsTotal != 1);
        //    if (data == null || !data.Any()) return result;

        //    result = data.Select(t => new DetailModule
        //    {
        //        ItemName = t.TypeName,
        //        CellValue = t.CellValue,
        //        ItemValue = t.CellValue,
        //    }).ToList();

        //    return result;
        //}

        public ag_secondallot GetAccountId(int secondId, out int accountId)
        {
            accountId = 0;
            var second = _perforAgsecondallotRepository.GetEntity(t => t.Id == secondId);
            if (second != null)
            {
                var unitType = EnumHelper.GetItems<UnitType>().FirstOrDefault(t => t.Name == second.UnitType);
                var account = perforResaccountRepository.GetEntity(t => t.AllotID == second.AllotId && t.UnitType == unitType.Value && t.AccountingUnit == second.Department);
                if (account == null && second.UnitType != UnitType.特殊核算组.ToString())
                    throw new PerformanceException("科室信息错误");
                accountId = account?.ID ?? 0;
            }
            return second;
        }

        public ag_secondallot GetSecondByAccountId(int accountId)
        {
            var special = _perforResspecialunitRepository.GetEntity(t => t.ID == accountId);
            if (special == null)
                throw new PerformanceException("科室信息错误");
            return new ag_secondallot
            {
                AllotId = special.AllotID,
                Department = special.AccountingUnit,
                UnitType = UnitType.特殊核算组.ToString()
            };
        }

        public DeptDataDetails GetDoctorDetail(int computeId)
        {
            var resCompute = _perforRescomputeRepository.GetEntity(t => t.ID == computeId);
            if (resCompute == null) return new DeptDataDetails();

            //var allot = perforPerallotRepository.GetEntity(t => t.ID == resCompute.AllotID);
            //if (allot == null) return new DeptDataDetails();

            var employee = _perforImemployeeclinicRepository.GetEntity(t => t.AllotID == resCompute.AllotID && t.AccountingUnit == resCompute.AccountingUnit && t.UnitType == resCompute.UnitType && t.PersonnelNumber == resCompute.JobNumber);
            DeptDataDetails doctorDetails = new DeptDataDetails
            {
                ShowFormula = 0,
                Pandect = new PerDataAccountBaisc
                {
                    BasicFactor = employee?.Basics ?? 0,    //基础绩效系数
                    Effic = employee.Efficiency ?? 0,   //效率绩效系数
                    Scale = employee.Scale ?? 0,    //规模绩效系数
                    Management = employee.Management,//管理绩效发放系数
                    AdjustFactor = employee?.Adjust ?? 1,   //调节系数
                    AdjustLaterOtherFee = employee.AdjustLaterOtherFee, //调节后其他绩效

                    AccountingUnit = resCompute.AccountingUnit,
                    EmployeeName = resCompute.EmployeeName,
                    PerforTotal = resCompute.PerforTotal,   //科室考核前绩效
                    Number = resCompute.Number ?? 0,    //核算人数
                    AvgPerfor = (resCompute.Number ?? 0) == 0 ? 0 : resCompute.PerforTotal / resCompute.Number, //人均绩效
                    Attendance = resCompute.Attendance ?? 1, //出勤率
                    Avg = resCompute.Avg,   //实际人均
                    PermanentStaff = resCompute.PermanentStaff ?? 0,    //效率绩效人数
                    EfficPerfor = resCompute.Efficiency ?? 0,   //效率绩效
                    ScalePerfor = resCompute.Scale ?? 0,    //规模绩效
                    Extra = resCompute.Punishment ?? 0,     //医院奖罚
                    OtherManagePerfor = resCompute.OtherManagePerfor ?? 0, //其他管理绩效
                    ShouldGiveFee = resCompute.ShouldGiveFee ?? 0,  //考核前管理绩效
                    ScoringAverage = resCompute.ScoreAverageRate ?? 1,  //考核得分率
                    AssessLaterManagementFee = GetDecimal(resCompute.ShouldGiveFee * resCompute.ScoreAverageRate * resCompute.Attendance + resCompute.Punishment ?? 0), //考核后管理绩效
                    RealGiveFee = resCompute.RealGiveFee    //绩效合计
                },
                Detail = new List<DetailDtos>()
            };
            var isShowManage = IsShowManage(resCompute.AllotID.Value);

            // 开启 显示管理绩效
            if (isShowManage == 2)
                doctorDetails.Pandect.RealGiveFee = doctorDetails.Pandect.AssessLaterManagementFee;

            var sheets = _perforPerSheetRepository.GetEntities(t => t.AllotID == resCompute.AllotID && new int[] { (int)SheetType.PersonExtra, (int)SheetType.PersonAdjustLaterOtherFee }.Contains(t.SheetType.Value));
            if (sheets == null || !sheets.Any()) return doctorDetails;

            var data = _perforImDataRepository.GetEntities(t => t.AllotID == resCompute.AllotID && sheets.Select(s => s.ID).Contains(t.SheetID.Value));
            if (data == null || !data.Any(t => t.JobNumber == (resCompute.JobNumber ?? "") && t.EmployeeName == resCompute.EmployeeName)) return doctorDetails;

            data = data.Where(t => t.JobNumber == (resCompute.JobNumber ?? "") && t.EmployeeName == resCompute.EmployeeName).ToList();
            foreach (var sheet in sheets)
            {
                var sheetData = data.Where(t => t.SheetID == sheet.ID);
                if (sheetData == null || !sheetData.Any()) continue;

                var itemName = Regex.Replace(sheet.SheetName, @"\d", "");
                var detail = new DetailDtos
                {
                    ItemName = itemName.Replace(".", "").Replace(" ", ""),
                    IncomeType = sheet.SheetType == (int)SheetType.PersonExtra ? 5 : 8,
                    OriginalType = sheet.SheetType ?? 0,
                    Amount = sheetData.Where(t => t.IsTotal == 1)?.Sum(t => t.CellValue) ?? 0,
                    Items = sheetData.Where(t => t.IsTotal != 1)?.Select(t => new DetailModule
                    {
                        ItemName = t.TypeName,
                        ItemValue = t.CellValue
                    }).ToList()
                };
                doctorDetails.Detail.Add(detail);
            }
            return doctorDetails;
        }

        public res_baiscnorm EditHospitalAvg(ComputerAvgRequest request)
        {
            if (request.Id == 0)
            {
                var baiscnorm = Mapper.Map<res_baiscnorm>(request);
                if (!perforResbaiscnormRepository.Add(baiscnorm))
                    throw new PerformanceException("保存失败");
                return Mapper.Map<res_baiscnorm>(baiscnorm);
            }
            else
            {
                var baiscnorm = perforResbaiscnormRepository.GetEntity(t => t.ID == request.Id);
                if (baiscnorm == null)
                    throw new PerformanceException($"ID不存在 ：{request.Id}");

                baiscnorm.TotelNumber = request.TotelNumber;
                baiscnorm.TotelValue = request.TotelValue;
                baiscnorm.AvgValue = request.AvgValue;

                //var baiscnorm = Mapper.Map<res_baiscnorm>(request);
                if (!perforResbaiscnormRepository.Update(baiscnorm))
                    throw new PerformanceException("保存失败");
                return Mapper.Map<res_baiscnorm>(baiscnorm);
            }
        }

        public List<Dictionary<string, string>> GetOtherPerStats(List<per_apr_amount> employees)
        {
            var others = new List<Dictionary<string, string>>();
            if (employees == null)
                return others;

            var perForType = employees.Where(c => c.Status == 3).Select(t => t.PerforType).Distinct();
            var doctorNum = employees.Where(c => c.Status == 3).Select(t => t.PersonnelNumber).Distinct().ToList();

            if (!doctorNum.Any())
                return others;

            foreach (var num in doctorNum)
            {
                var dicData = new Dictionary<string, string>();
                var amount = employees.Find(t => t.PersonnelNumber == num);
                if (amount == null)
                    continue;
                dicData.Add("核算单元", amount?.AccountingUnit ?? "");
                dicData.Add("工号", amount?.PersonnelNumber ?? "");
                dicData.Add("人员姓名", amount?.DoctorName ?? "");

                foreach (var type in perForType)
                {
                    var emp = employees.Where(t => t.PerforType == type && t.PersonnelNumber == num)?.ToList();
                    if (!emp.Any())
                        dicData.Add(type, "0");
                    else
                        dicData.Add(type, Math.Round(Convert.ToDecimal(emp?.First()?.Amount), 0).ToString());
                }

                var sum = employees.Where(c => c.PersonnelNumber == num)?.Sum(t => t.Amount);
                dicData.Add("合计", Math.Round(Convert.ToDecimal(sum), 0).ToString());
                others.Add(dicData);
            }

            return others;
        }

        private decimal GetDecimal(decimal? value, decimal _ = 0)
        {
            if (!value.HasValue)
                return _;

            int decimals = Math.Abs(value.Value) > 100 ? 0 : 2;
            return Math.Round(value.Value, decimals, MidpointRounding.AwayFromZero);
        }
    }
}
