using AutoMapper;
using NPOI.SS.Formula.Functions;
using Performance.DtoModels;
using Performance.EntityModels;
using Performance.Infrastructure;
using Performance.Repository;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

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 PerforCofcmiRepository cofcmiRepository;
        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,
            PerforCofcmiRepository cofcmiRepository,
            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.cofcmiRepository = cofcmiRepository;
            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);

            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

                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;
                        var employee = employees.FirstOrDefault(e => e.DoctorName == t.EmployeeName && e.AccountingUnit == t.AccountingUnit && pairs[type].Contains(e.UnitType));
                        var scoreAverageRate = t.ScoreAverageRate ?? employee.ScoreAverageRate ?? 0;
                        var attendance = t.Attendance ?? employee.Attendance ?? 0;
                        t.GiveFee = t.ShouldGiveFee * scoreAverageRate * attendance + t.OtherPerfor;
                        t.RealGiveFee = t.GiveFee * (t.Adjust ?? 1m);
                        t.BaiscNormValue = t.RealGiveFee;
                    }
                });
                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 (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"));
                return data.Distinct().OrderByDescending(t => t.AccountingUnit).ToList();
            }
        }

        /// <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.行政中层, (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> 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.ScoringPerfor = t.PerforFee * (t.ScoringAverage ?? 0);
                });
                result = result.OrderBy(t => t.UnitType).ThenBy(t => t.AccountingUnit).ToList();
            }

            var accountType = new List<AccountUnitType> { AccountUnitType.行政高层, AccountUnitType.行政中层, AccountUnitType.行政工勤 };
            var list = _perforRescomputeRepository.GetEntities(t => t.AllotID == allotId && accountType.Select(a => a.ToString()).Contains(t.AccountType));
            if (list == null || !list.Any()) return result;

            List<DeptResponse> adminPerfor = list.GroupBy(t => new { t.AccountingUnit, t.AccountType })
                .Select(t => new DeptResponse
                {
                    UnitName = t.Key.AccountType,
                    AccountingUnit = t.Key.AccountingUnit,
                    Department = t.Key.AccountingUnit,
                    Number = t.Count(),
                    //Extra = t.FirstOrDefault(group => group.Punishment > 0)?.Punishment, // 医院奖罚
                    //ScoringAverage = t.FirstOrDefault(group => group.ScoreAverageRate > 0)?.ScoreAverageRate, //考核得分率
                    //AdjustFactor = t.FirstOrDefault(group => group.Adjust > 0)?.Adjust, //调节系数
                    //WorkloadFee = t.Sum(group => group.Workload),  //工作量绩效
                    //PerforTotal = t.Sum(group => group.RealGiveFee),  //绩效合计
                    //ScoringPerfor = t.Sum(group => group.RealGiveFee) * (t.FirstOrDefault(group => group.ScoreAverageRate > 0)?.ScoreAverageRate ?? 0),
                    Avg = t.Sum(group => group.RealGiveFee) / t.Count(), //人均绩效
                    OtherPerfor1 = t.Sum(group => group.OtherPerfor),
                    RealGiveFee = t.Sum(group => group.RealGiveFee) + t.Sum(group => group.OtherPerfor),  //实发绩效
                }).ToList();
            var enumItems = EnumHelper.GetItems<AccountUnitType>();
            adminPerfor = adminPerfor.OrderBy(t => enumItems.FirstOrDefault(e => e.Name == t.UnitName).Value).ThenBy(t => t.AccountingUnit).ToList();
            result.AddRange(adminPerfor);

            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 doctor = perforResaccountRepository.GetEntity(t => t.UnitType != (int)UnitType.护理组 && t.AllotID == allotId && t.ID == accountId);

                DeptDetailResponse response = new DeptDetailResponse()
                {
                    Pandect = Mapper.Map<PerDataAccountBaisc>(doctor),
                    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 == doctor.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 == doctor.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;
        }

        /// <summary>
        /// 返回绩效发放列表
        /// </summary>
        /// <param name="allotId">绩效ID</param>
        /// <returns></returns>
        public List<ComputeResponse> AllCompute(int allotId)
        {
            var list = new List<ComputeResponse>();
            var allot = _perforRescomputeRepository.GetEntities(t => t.AllotID == allotId)?.OrderByDescending(t => t.AccountingUnit);
            list = Mapper.Map<List<ComputeResponse>>(allot);
            list?.ForEach(t => t.Source = "一次绩效");
            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));
            }
            return AddAprAmount(allotId, list);
        }

        /// <summary>
        /// 返回绩效发放列表
        /// 科主任护士长返回管理绩效
        /// </summary>
        /// <param name="allotId">绩效ID</param>
        /// <returns></returns>
        public List<ComputeResponse> AllManageCompute(int allotId)
        {
            var list = new List<ComputeResponse>();
            var allot = _perforRescomputeRepository.GetEntities(t => t.AllotID == allotId)?.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));
            }
            return AddAprAmount(allotId, list);
        }

        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 doctor = perforResaccountRepository.GetEntity(t => t.ID == accountId);

            var workitems = cofworkitemRepository.GetEntities(t => t.AllotID == doctor.AllotID);
            var allotCmi = cofcmiRepository.GetEntity(t => t.AllotId == doctor.AllotID && t.UnitType == doctor.UnitType && t.AccountingUnit == doctor.AccountingUnit);

            var allot = perforPerallotRepository.GetEntity(t => t.ID == doctor.AllotID);
            DeptDataDetails deptDetails = new DeptDataDetails
            {
                ShowFormula = allot.ShowFormula,
                Pandect = Mapper.Map<PerDataAccountBaisc>(doctor),
                Detail = new List<DetailDtos>()
            };

            var persheet = _perforPerSheetRepository.GetEntities(t => t.AllotID == doctor.AllotID);
            var headers = _perforImheaderRepository.GetEntities(t => t.AllotID == doctor.AllotID);

            //科室经济
            var sheetEconomic = persheet.FirstOrDefault(t => t.SheetType == (int)SheetType.ComputeEconomic);
            var basicData = _perforImDataRepository.GetEntities(t => t.AllotID == doctor.AllotID && t.AccountingUnit == doctor.AccountingUnit);
            var dataEconomicList = basicData.Where(t => t.SheetID == sheetEconomic?.ID && t.IsTotal != 1 && t.AccountingUnit == doctor.AccountingUnit).ToList();
            string typeValue = EnumHelper.GetDescription((UnitType)doctor.UnitType);
            var economic = dataEconomicList?.Select(t => new
            {
                ItemName = t.TypeName.Replace($"({typeValue})", ""),
                ItemValue = t.CellValue ?? 0,
                t.UnitType
            });

            Regex reg = new Regex("[0-9]*");

            int type = doctor.UnitType.Value;

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

            int groupbasis = 1;
            string single = "";
            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
            };
            foreach (var stype in sheetType)
            {
                if (type == 3 && stype == (int)SheetType.Workload) type = 1;
                foreach (var sheet in persheet.Where(t => t.SheetType == stype))
                {
                    if (single != "" && sheet.SheetName.Substring(0, 3) != single)
                        groupbasis += 1;
                    single = sheet.SheetName.Substring(0, 3);

                    var sheetName = reg.Replace(sheet.SheetName, "", 5).Replace(".", "").Replace(" ", "");
                    var sheetData = basicData.Where(t => t.SheetID == sheet.ID && t.UnitType == type).ToList();
                    if (sheetData == null || !sheetData.Any()) continue;

                    var headerData = headers?.Where(t => t.SheetID == sheet.ID);

                    var sheettype = 1; //特殊核算科室 4
                    var amount = 0m;
                    if (sheet.SheetType == (int)SheetType.Expend)
                    {
                        sheettype = 2;
                        amount = economic.FirstOrDefault(t => t.ItemName.Contains(sheetName) && t.UnitType == type)?.ItemValue ?? 0m;
                    }
                    else if (sheet.SheetType == (int)SheetType.Workload)
                    {
                        sheettype = 3;
                        amount = doctor.WorkloadFee ?? 0m;
                    }
                    else if (sheet.SheetType == (int)SheetType.AccountExtra)
                    {
                        sheettype = 5;
                        amount = sheetData.Sum(t => t.CellValue ?? 0m);
                    }
                    else if (sheet.SheetType == (int)SheetType.AccountDrugAssess)
                    {
                        sheettype = 6;
                        amount = sheetData.Sum(t => t.CellValue ?? 0m);
                    }
                    else if (sheet.SheetType == (int)SheetType.AccountMaterialsAssess)
                    {
                        sheettype = 7;
                        amount = sheetData.Sum(t => t.CellValue ?? 0m);
                    }

                    var item = new DetailDtos
                    {
                        ItemName = sheetName,
                        IncomeType = sheettype,
                        Amount = amount,
                        GroupBasis = groupbasis,
                    };

                    var items = sheetData?.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),
                            };

                            if (sheet.SheetType == (int)SheetType.Workload)
                            {
                                if (workitems != null && workitems.Any(a => a.Type == 1 && a.Item == t.Key))
                                    dto.MediFactor = doctor.MedicineFactor;
                                if (workitems != null && workitems.Any(a => a.Type == 2 && a.Item == t.Key) && allotCmi != null)
                                    dto.CMIFactor = allotCmi.Value;
                                dto.ItemValue = dto.ItemValue * (dto.MediFactor ?? 1) * (dto.CMIFactor ?? 1);
                            }

                            return dto;
                        }).ToList();

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

                    }

                    if (headerData != null && headerData.Any())
                    {
                        items = items
                            ?.OrderBy(t => (headerData.FirstOrDefault(h => h.CellValue == t.ItemName)?.PointCell) ?? 100)
                            ?.ThenBy(t => t.ItemName).ToList();
                    }

                    item.Items = items;
                    deptDetails.Detail.Add(item);
                }
            }

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

        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,
                        }).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,
                    Amount = data.First().Amount,
                    GroupBasis = groupbasis,
                    Items = items
                });
            }

            return result;
        }

        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.First().ScoringAverage.Value,
                    OtherPerfor1 = special.First().OtherPerfor.Value,
                    AdjustFactor = special.First().Adjust.Value,
                    Avg = special.First().Avg,
                    RealGiveFee = special.First().RealGiveFee,
                    Number = special.First().Number.Value,
                    PerforFee = special.First().GiveFee,
                    PerforTotal = special.First().ResultsTotalFee,
                    Income = special.First().ResultsTotalFee,
                    //Extra = special.First().Punishment.Value,
                },
                Detail = new List<DetailDtos>(),
            };
            var detail = new DetailDtos
            {
                ItemName = "特殊核算单元绩效测算表",
                IncomeType = 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.Quantity * item.QuantitativeIndicatorsValue ?? 0, 2)
                });
            }
            deptDetails.Detail.Add(detail);
            return deptDetails;
        }


        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.Department == second.Department);
                if (account == null && second.UnitType != UnitType.特殊核算组.ToString())
                    throw new PerformanceException("科室信息错误");
                accountId = account?.ID ?? 0;
            }
            return second;
        }

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

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

            var source = new string[] { "一次绩效", "二次绩效" };
            foreach (var item in list.Where(t => t.Amount.HasValue))
            {
                var flag = false;
                foreach (var s in source)
                {
                    if (flag) continue;
                    var emp = computes.FirstOrDefault(t => t.Source == s && t.JobNumber == item.PersonnelNumber && t.EmployeeName == item.DoctorName);
                    if (emp != null)
                    {
                        emp.RealGiveFee += item.Amount;
                        flag = true;
                        continue;
                    }
                    emp = computes.FirstOrDefault(t => t.Source == s && t.JobNumber == item.PersonnelNumber);
                    if (emp != null)
                    {
                        emp.RealGiveFee += item.Amount;
                        flag = true;
                        continue;
                    }
                    emp = computes.FirstOrDefault(t => t.Source == s && t.EmployeeName == item.DoctorName);
                    if (emp != null)
                    {
                        emp.RealGiveFee += item.Amount;
                        flag = true;
                        continue;
                    }
                }
            }
            return computes;
        }
    }
}
