using IRaCIS.Core.Infrastructure.ExpressionExtend;
using IRaCIS.Application.Interfaces;
using IRaCIS.Application.Contracts;
using IRaCIS.Application.Contracts.Pay;
using IRaCIS.Core.Domain.Share;
using System.Linq.Expressions;
using IRaCIS.Core.Infra.EFCore;
using IRaCIS.Core.Domain.Models;
using IRaCIS.Core.Infrastructure.Extention;
using Microsoft.AspNetCore.Mvc;
using Panda.DynamicWebApi.Attributes;

namespace IRaCIS.Application.Services
{
    [ ApiExplorerSettings(GroupName = "Financial")]
    public class FinancialService : BaseService, IPaymentService
    {
        private readonly IRepository<Payment> _paymentRepository;
        private readonly IRepository<ReviewerPayInformation> _doctorPayInfoRepository;
        private readonly IRepository<TrialPaymentPrice> _TrialPaymentPriceRepository;
        private readonly IRepository<Trial> _trialRepository;
        private readonly IRepository<Doctor> _doctorRepository;
        private readonly IRepository<RankPrice> _rankPriceRepository;
        private readonly IRepository<PaymentDetail> _paymentDetailRepository;
        private readonly IRepository<CRO> _croRepository;
        private readonly IRepository<Workload> _workloadRepository;
        private readonly IRepository<TrialRevenuesPrice> _trialRevenuePriceRepository;
        private readonly IRepository<PaymentAdjustment> _payAdjustmentRepository;

        private readonly IRepository<Enroll> _enrollRepository;

        private readonly IRepository<Workload> _doctorWorkloadRepository;

        public FinancialService(IRepository<Payment> costStatisticsRepository,
            IRepository<ReviewerPayInformation> doctorPayInfoRepository,
            IRepository<Trial> trialRepository,
            IRepository<Doctor> doctorRepository,
            IRepository<RankPrice> rankPriceRepository,
            IRepository<PaymentDetail> costStatisticsDetailRepository,
            IRepository<CRO> croCompanyRepository,
            IRepository<Workload> workloadRepository,
                IRepository<Enroll> intoGroupRepository,
                  IRepository<TrialPaymentPrice> trialPaymentPriceRepository,
            IRepository<TrialRevenuesPrice> trialCostRepository,
            IRepository<PaymentAdjustment> costAdjustmentRepository, 
            IRepository<Workload> doctoWorkloadRepository
        )
        {
            _TrialPaymentPriceRepository = trialPaymentPriceRepository;
            _paymentRepository = costStatisticsRepository;
            _doctorPayInfoRepository = doctorPayInfoRepository;
            _trialRepository = trialRepository;
            _doctorRepository = doctorRepository;
            _rankPriceRepository = rankPriceRepository;
            _paymentDetailRepository = costStatisticsDetailRepository;
            _croRepository = croCompanyRepository;
            _enrollRepository = intoGroupRepository;
            _workloadRepository = workloadRepository;
            _trialRevenuePriceRepository = trialCostRepository;
            _payAdjustmentRepository = costAdjustmentRepository;
            
            _doctorWorkloadRepository = doctoWorkloadRepository;
        }

        /// <summary>
        /// Financials /MonthlyPayment 列表查询接口
        /// </summary>
         [NonDynamicMethod]
        public async Task<PageOutput<PaymentModel>> GetMonthlyPaymentList(MonthlyPaymentQueryDTO queryParam)
        {
            //var year = queryParam.StatisticsDate.Year;
            //var month = queryParam.StatisticsDate.Month;
            //var searchBeginDateTime = queryParam.StatisticsDate;
            //Expression<Func<Workload, bool>> workloadLambda = t => t.DataFrom == (int)WorkLoadFromStatus.FinalConfirm;
            //workloadLambda = workloadLambda.And(t =>
            //    t.WorkTime >= queryParam.StatisticsDate && t.WorkTime <= queryParam.StatisticsDate);
            //var rate = _exchangeRateRepository.FindSingleOrDefault(u => u.YearMonth == yearMonth);
            //var exchangeRate = rate == null ? 0 : rate.Rate;

            var yearMonth = queryParam.StatisticsDate.ToString("yyyy-MM");

            Expression<Func<Doctor, bool>> doctorLambda = x => true;
            if (!string.IsNullOrWhiteSpace(queryParam.KeyWord))
            {
                var reviewer = queryParam.KeyWord.Trim();
                doctorLambda = doctorLambda.And(u => u.ChineseName.Contains(reviewer)
                                                     || u.FirstName.Contains(reviewer)
                                                     || u.LastName.Contains(reviewer)
                                                     || u.ReviewerCode.Contains(reviewer));
            }

            if (queryParam.Nation != null)
            {
                doctorLambda = doctorLambda.And(u => u.Nation == queryParam.Nation);
            }

            var costStatisticsQueryable =

                                           from monthlyPayment in _paymentRepository.Where(t => t.YearMonth == yearMonth)
                                           join payInfo in _doctorPayInfoRepository.AsQueryable() on monthlyPayment.DoctorId equals payInfo.DoctorId
                                               into cc
                                           from payInfo in cc.DefaultIfEmpty()
                                           join doctor in _doctorRepository.Where(doctorLambda) on monthlyPayment.DoctorId equals doctor.Id
                                           join rankPrice in _rankPriceRepository.AsQueryable() on payInfo.RankId equals rankPrice.Id into dd
                                           from rankPriceItem in dd.DefaultIfEmpty()
                                           select new PaymentModel()
                                           {
                                               Id = monthlyPayment.Id,
                                               DoctorId = monthlyPayment.DoctorId,
                                               YearMonth = monthlyPayment.YearMonth,
                                               PaymentUSD = monthlyPayment.PaymentUSD,
                                               CalculateTime = monthlyPayment.CalculateTime,
                                               CalculateUser = monthlyPayment.CalculateUser,
                                               IsLock = monthlyPayment.IsLock,
                                               ExchangeRate = monthlyPayment.ExchangeRate,
                                               PaymentCNY = monthlyPayment.PaymentCNY,
                                               AdjustPaymentCNY = monthlyPayment.AdjustmentCNY,
                                               AdjustPaymentUSD = monthlyPayment.AdjustmentUSD,

                                               TotalPaymentCNY = monthlyPayment.AdjustmentCNY + monthlyPayment.PaymentCNY,
                                               TotalPaymentUSD = monthlyPayment.AdjustmentUSD + monthlyPayment.PaymentUSD,


                                               Code = doctor.ReviewerCode,
                                               FirstName = doctor.FirstName,
                                               LastName = doctor.LastName,
                                               ChineseName = doctor.ChineseName,
                                               Phone = doctor.Phone,
                                               DoctorNameInBank = payInfo.DoctorNameInBank,
                                               RankName = rankPriceItem.RankName,
                                               IDCard = payInfo.IDCard,
                                               BankCardNumber = payInfo.BankCardNumber,
                                               BankName = payInfo.BankName
                                           };

            var propName = string.IsNullOrWhiteSpace(queryParam.SortField) ? "Code" : queryParam.SortField;
            costStatisticsQueryable = queryParam.Asc ? costStatisticsQueryable.OrderBy(propName).ThenBy(u => u.Code)
                : costStatisticsQueryable.OrderByDescending(propName).ThenBy(u => u.Code);
            var count = costStatisticsQueryable.Count();
            costStatisticsQueryable = costStatisticsQueryable.Skip((queryParam.PageIndex - 1) * queryParam.PageSize).Take(queryParam.PageSize);
            var costStatisticsList = await costStatisticsQueryable.ToListAsync();


            #region 增加调整费用总计字段之前
            //var doctorIds = costStatisticsList.Select(t => t.DoctorId).ToList();

            //var adjList = _payAdjustmentRepository.GetAll()
            //    .Where(t => t.YearMonth == yearMonth && doctorIds.Contains(t.ReviewerId))
            //    .GroupBy(t => t.ReviewerId).Select(g => new
            //    {
            //        ReviewerId = g.Key,
            //        AdjustPaymentCNY = g.Sum(t => t.AdjustPaymentCNY),
            //        AdjustPaymentUSD = g.Sum(t => t.AdjustPaymentUSD)
            //    }).ToList();

            //costStatisticsList.ForEach(t =>
            //{
            //    var tempAdj = adjList.FirstOrDefault(u => u.ReviewerId == t.DoctorId);
            //    if (tempAdj != null)
            //    {
            //        t.AdjustPaymentUSD = tempAdj.AdjustPaymentUSD;
            //        t.AdjustPaymentCNY = tempAdj.AdjustPaymentCNY;

            //    }
            //});


            #endregion

            return new PageOutput<PaymentModel>(queryParam.PageIndex, queryParam.PageSize, count, costStatisticsList);
        }

        /// <summary>
        /// Financials /MonthlyPaymentDetail 详情查询接口
        /// </summary>
        [HttpPost("{paymentId:guid}/{doctorId:guid}/{yearMonth:datetime}")]
        public async Task<PayDetailDTO> GetMonthlyPaymentDetailList(Guid paymentId, Guid reviewerId, DateTime yearMonth)
        {
            var returnModel = new PayDetailDTO();
            var yearMonthStr = yearMonth.ToString("yyyy-MM");

            List<PaymentDetailDTO> detailList = new List<PaymentDetailDTO>();
            //有详细表的数据   先查出来
            if (paymentId != Guid.Empty)
            {

                //from enroll in _enrollRepository.Where(t => t.TrialId == challengeQuery.TrialId)
                //join dociorc in _doctorRepository.Where() on enroll.DoctorId equals dociorc.Id
                //join price in _TrialPaymentPriceRepository.Where() on enroll.TrialId equals price.TrialId


                //select new EnrollViewModel()
                //{
                //    ChineseName = dociorc.ChineseName,
                //    AdjustmentMultiple = enroll.AdjustmentMultiple,
                //    FirstName = dociorc.FirstName,
                //    LastName = dociorc.LastName,
                //    DoctorId = dociorc.Id,
                //    TrialId = challengeQuery.TrialId

                //};
                //detailList = _paymentDetailRepository.AsQueryable()
                //   .Where(t => t.PaymentId == paymentId)
                //   .OrderBy(t => t.ShowCodeOrder).ThenBy(t => t.ShowTypeOrder).ProjectTo<PaymentDetailDTO>(_mapper.ConfigurationProvider).ToList();


                detailList = await (from pay in _paymentDetailRepository.Where(t => t.PaymentId == paymentId)
                              join enroll in _enrollRepository.Where() on new { pay.DoctorId, pay.TrialId } equals new { enroll.DoctorId, enroll.TrialId }
                              join price in _TrialPaymentPriceRepository.Where() on pay.TrialId equals price.TrialId
                              orderby pay.ShowCodeOrder
                              orderby pay.ShowTypeOrder
                              select new PaymentDetailDTO()
                              {
                                  Id=pay.Id,
                                  ShowCodeOrder = pay.ShowCodeOrder,
                                  ShowTypeOrder = pay.ShowTypeOrder,
                                  PaymentUSD = pay.PaymentUSD,
                                  BasePrice = pay.BasePrice,
                                  PersonalAdditional = pay.PersonalAdditional,
                                  TrialAdditional = pay.TrialAdditional,
                                  TrialCode = pay.TrialCode,
                                  PaymentCNY = pay.PaymentCNY,
                                  DoctorId = pay.DoctorId,
                                  ExchangeRate = pay.ExchangeRate,
                                  IsNewTrial = price.IsNewTrial,
                                  NewPersonalAdditional= enroll.AdjustmentMultiple,

                              }).ToListAsync();

            }
            //费用调整
            //_payAdjustmentRepository.Where(t => t.YearMonth == yearMonthStr && t.ReviewerId == reviewerId)
            var adjList =
                await (from costAdjustment in _payAdjustmentRepository.Where(t => t.YearMonth == yearMonthStr&& t.ReviewerId == paymentId)
                 join enroll in _enrollRepository.Where() on new { costAdjustment.ReviewerId, costAdjustment.TrialId } equals new { ReviewerId= enroll.DoctorId, enroll.TrialId }
                 join price in _TrialPaymentPriceRepository.Where() on costAdjustment.TrialId equals price.TrialId


                 select new PaymentDetailDTO()
                 {
                     Id=costAdjustment.Id,
                     TrialCode = "Adjustment",
                     PaymentCNY = costAdjustment.AdjustmentCNY,
                     PaymentUSD = costAdjustment.AdjustmentUSD,
                     DoctorId = costAdjustment.ReviewerId,
                     ExchangeRate = costAdjustment.ExchangeRate,
                     AdjustmentView = new AdjustmentDTO()
                     {
                         AdjustPaymentUSD = costAdjustment.AdjustmentUSD,
                         AdjustPaymentCNY = costAdjustment.AdjustmentCNY,
                         Note = costAdjustment.Note
                     },
                     IsNewTrial = price.IsNewTrial,
                     NewPersonalAdditional = enroll.AdjustmentMultiple,

                 }).ToListAsync();

             


            detailList.AddRange(adjList);

            detailList.ForEach(x =>
            {
                x.PersonalAdditional = x.IsNewTrial == true && x.NewPersonalAdditional != null ? 0 : x.PersonalAdditional;
                x.TrialAdditional = x.IsNewTrial == true && x.NewPersonalAdditional != null ? 0 : x.TrialAdditional;
                x.BasePrice = x.IsNewTrial == true && x.NewPersonalAdditional != null ? x.NewPersonalAdditional.Value : x.BasePrice;

            });

            returnModel.DetailList = detailList;

      

            var doctorId = returnModel.DetailList.FirstOrDefault()?.DoctorId;
            var query = from doctor in _doctorRepository.AsQueryable()
                    .Where(t => t.Id == doctorId)
                        join payInfo in _doctorPayInfoRepository.AsQueryable() on doctor.Id equals payInfo.DoctorId
                        join rank in _rankPriceRepository.AsQueryable() on payInfo.RankId equals rank.Id
                        select new DoctorPayInfo()
                        {
                            Code = doctor.ReviewerCode,
                            ChineseName = doctor.ChineseName,
                            FirstName = doctor.FirstName,
                            LastName = doctor.LastName,
                            Phone = doctor.Phone,
                            DoctorId = doctor.Id,
                            PayTitle = rank.RankName,
                            YearMonth = yearMonthStr
                        };

            returnModel.DoctorInfo =(await query.FirstOrDefaultAsync()).IfNullThrowException();

            return returnModel;
        }

        /// <summary>
        /// NEW  导出Excel压缩包 数据获取
        /// </summary>
        [HttpPost]
        public async Task<List<PayDetailDTO>> GetReviewersMonthlyPaymentDetail(List<MonthlyPaymentDetailQuery> manyReviewers)
        {
            List<PayDetailDTO> result = new List<PayDetailDTO>();
            foreach (var t in manyReviewers)
            {
                 result.Add(await GetMonthlyPaymentDetailList(t.PaymentId, t.ReviewerId, t.YearMonth));
            }


            return result;

        }


        /// <summary>
        /// Financials / Payment History 列表查询接口(已经支付锁定的数据,包含调整的)[New]
        /// </summary>
        [HttpPost]
        public async Task<PageOutput<MonthlyPaymentDTO>> GetPaymentHistoryList(PaymentQueryDTO queryParam)
        {
            Expression<Func<Doctor, bool>> doctorLambda = x => true;
            if (!string.IsNullOrWhiteSpace(queryParam.Reviewer))
            {
                var reviewer = queryParam.Reviewer.Trim();
                doctorLambda = doctorLambda.And(u => u.ChineseName.Contains(reviewer)
                                                     || u.FirstName.Contains(reviewer)
                                                     || u.LastName.Contains(reviewer)
                                                     || u.ReviewerCode.Contains(reviewer));
            }
            if (queryParam.Nation != null)
            {
                doctorLambda = doctorLambda.And(u => u.Nation == queryParam.Nation);
            }

            Expression<Func<Payment, bool>> paymentLambda = x => x.IsLock && x.YearMonthDate >= queryParam.BeginMonth && x.YearMonthDate <= queryParam.EndMonth;

            #region 在 payment表加 调整总计前

            //var paymentQueryable = _paymentRepository.Find(paymentLambda)
            //    .Select(
            //        t => new
            //        {
            //            ReviewerId = t.DoctorId,
            //            t.YearMonth,
            //            t.PaymentUSD,
            //            t.PaymentCNY,
            //            t.AdjustPaymentCNY, 
            //            t.AdjustPaymentUSD
            //        });

            //Expression<Func<PaymentAdjustment, bool>> payAdjustmentLambda = x => x.IsLock && x.AdjustedYearMonth >= param.BeginMonth && x.AdjustedYearMonth <= param.EndMonth;

            //var adjQueryable = _payAdjustmentRepository.GetAll()
            //      .Where(payAdjustmentLambda)
            //      .GroupBy(t => new { t.ReviewerId, t.YearMonth }).Select(g => new
            //      {
            //          g.Key.ReviewerId,
            //          g.Key.YearMonth,
            //          PaymentUSD = 0,
            //          PaymentCNY = 0,
            //          AdjustPaymentCNY = g.Sum(t => t.AdjustPaymentCNY),
            //          AdjustPaymentUSD = g.Sum(t => t.AdjustPaymentUSD)
            //      });

            //var query = from pay in (from paymentCost in paymentQueryable
            //                         join adjCost in adjQueryable on new { paymentCost.YearMonth, paymentCost.ReviewerId } equals new { adjCost.YearMonth, adjCost.ReviewerId } into a
            //                         from adjCost in a.DefaultIfEmpty()
            //                         select new
            //                         {
            //                             paymentCost.ReviewerId,
            //                             paymentCost.PaymentUSD,
            //                             paymentCost.PaymentCNY,
            //                             AdjustmentCNY = adjCost == null ? 0 : adjCost.AdjustPaymentCNY,
            //                             AdjustmentUSD = adjCost == null ? 0 : adjCost.AdjustPaymentUSD
            //                         }
            //                     ).Union(
            //                         from adjCost in adjQueryable
            //                         join paymentCost in paymentQueryable on new { adjCost.YearMonth, adjCost.ReviewerId } equals new { paymentCost.YearMonth, paymentCost.ReviewerId } into a
            //                         from paymentCost in a.DefaultIfEmpty()
            //                         select new
            //                         {
            //                             ReviewerId = adjCost.ReviewerId,
            //                             PaymentUSD = paymentCost == null ? 0 : paymentCost.PaymentUSD,
            //                             PaymentCNY = paymentCost == null ? 0 : paymentCost.PaymentCNY,
            //                             AdjustmentCNY = adjCost.AdjustPaymentCNY,
            //                             AdjustmentUSD = adjCost.AdjustPaymentUSD
            //                         }
            //                     )

            #endregion

            var query = from monthlyPay in _paymentRepository.Where(paymentLambda)
                               .GroupBy(t => t.DoctorId).Select(g => new
                               {
                                   ReviewerId = g.Key,
                                   PaymentUSD = g.Sum(u => u.PaymentUSD),
                                   PaymentCNY = g.Sum(u => u.PaymentCNY),
                                   AdjustmentCNY = g.Sum(u => u.AdjustmentCNY),
                                   AdjustmentUSD = g.Sum(u => u.AdjustmentCNY)
                               })
                        join doctor in _doctorRepository.Where(doctorLambda) on monthlyPay.ReviewerId equals doctor.Id
                        select new MonthlyPaymentDTO
                        {
                            ReviewerId = doctor.Id,
                            ChineseName = doctor.ChineseName,
                            FirstName = doctor.FirstName,
                            LastName = doctor.LastName,
                            ReviewerCode = doctor.ReviewerCode,
                            PaymentUSD = monthlyPay.PaymentUSD,
                            PaymentCNY = monthlyPay.PaymentCNY,
                            AdjustmentCNY = monthlyPay.AdjustmentCNY,
                            AdjustmentUSD = monthlyPay.AdjustmentUSD,
                            TotalCNY = monthlyPay.AdjustmentCNY + monthlyPay.PaymentCNY,
                            TotalUSD = monthlyPay.AdjustmentUSD + monthlyPay.PaymentUSD
                        };
            var propName = queryParam.SortField == string.Empty ? "ReviewerCode" : queryParam.SortField;
            query = queryParam.Asc ? query.OrderBy(propName).ThenBy(u => u.ReviewerCode) : query.OrderByDescending(propName).ThenBy(u => u.ReviewerCode);
            if (propName == "FirstName" || propName == "LastName")
            {
                query = queryParam.Asc ? query.OrderBy(t => t.LastName).ThenBy(t => t.FirstName)
                    : query.OrderByDescending(t => t.LastName).ThenBy(t => t.FirstName);
            }
            var count = await query.CountAsync();
            query = query.Skip((queryParam.PageIndex - 1) * queryParam.PageSize).Take(queryParam.PageSize);
            var list = await query.ToListAsync();
            return new PageOutput<MonthlyPaymentDTO>(queryParam.PageIndex, queryParam.PageSize, count, list);

        }

        /// <summary>
        /// Financials / Payment History 详情接口[New]
        /// </summary>
        [HttpPost]
        public async Task<List<VolumeStatisticsDTO>> GetPaymentHistoryDetailList(VolumeQueryDTO param)
        {
            var beginDate = new DateTime(param.BeginMonth.Year, param.BeginMonth.Month, 1);
            var endDate = new DateTime(param.EndMonth.Year, param.EndMonth.Month, 1);

            Expression<Func<Payment, bool>> monthlyPayLambda = x => x.IsLock && x.DoctorId == param.ReviewerId && x.YearMonthDate >= beginDate && x.YearMonthDate <= endDate;

            var query =
                from monthlyPayment in _paymentRepository.Where(monthlyPayLambda)

                select new VolumeStatisticsDTO
                {
                    StatisticsId = monthlyPayment.Id,
                    Month = monthlyPayment.YearMonth,
                    ExchangeRate = monthlyPayment.ExchangeRate,
                    PaymentUSD = monthlyPayment.PaymentUSD,
                    PaymentCNY = monthlyPayment.PaymentCNY,
                    AdjustmentCNY = monthlyPayment.AdjustmentCNY,
                    AdjustmentUSD = monthlyPayment.AdjustmentUSD,
                    VolumeReward = 0
                };

            var payDetailList = await query.OrderBy(t => t.Month).ToListAsync();

            List<Guid> statisticsIdList = payDetailList.Select(t => t.StatisticsId).ToList();

            var monthlyPayDetailList = await _paymentDetailRepository.Where(u =>
                statisticsIdList.Contains(u.PaymentId)).Select(t => new
                {
                    PaymentId = t.PaymentId,
                    t.PaymentUSD,
                    t.TrialCode,
                    t.PaymentCNY,
                    t.YearMonth
                }).ToListAsync();

            payDetailList.ForEach(t =>
                {
                    t.VolumeReward = monthlyPayDetailList
                        .Where(u => u.PaymentId == t.StatisticsId && u.TrialCode == "Volume Reward")
                        .Sum(k => k.PaymentUSD);

                    t.TrialPaymentList = monthlyPayDetailList
                        .Where(u => u.PaymentId == t.StatisticsId && u.TrialCode != "Volume Reward" && u.YearMonth == t.Month)
                        .GroupBy(u => u.TrialCode).Select(g => new TrialPaymentDTO
                        {
                            TrialPayment = g.Sum(k => k.PaymentUSD),
                            TrialCode = g.Key
                        }).ToList();
                });


            #region 改表之前

            //var tempVolume = _costStatisticsDetailRepository.Find(u =>
            //    statisticsIdList.Contains(u.PaymentId)).ToList();

            //foreach (var item in payDetailList)
            //{
            //    var temp = tempVolume.Where(u => u.PaymentId == item.StatisticsId && u.TrialCode == "Volume Reward");
            //    var Volume = 0.0;
            //    foreach (var t in temp)
            //    {
            //        Volume += (t.BasePrice * t.Count);
            //    }
            //    item.VolumeReward = Volume;

            //    var trialCodes = tempVolume.Where(u => u.PaymentId == item.StatisticsId
            //                                           && u.TrialCode != "Volume Reward").GroupBy(u => u.TrialCode).Select(u => u.Key).Distinct();

            //    foreach (var trial in trialCodes)
            //    {
            //        var trialFee = 0.0;
            //        var aa = tempVolume.Where(u => u.PaymentId == item.StatisticsId && u.TrialCode == trial
            //        ).ToList();

            //        foreach (var a in aa)
            //        {
            //            trialFee += (a.Count * (a.BasePrice + a.PersonalAdditional + a.TrialAdditional));
            //        }
            //        item.TrialFeeList.Add(new TrialFeeViewModel
            //        {
            //            TrialCode = trial,
            //            TrialFee = trialFee
            //        });
            //    }

            //}

            #endregion

            return payDetailList;
        }

        /// <summary>
        /// Revenues列表接口,收入统计[New]  0是Detail   1是按照项目   2是按照人  3按照月份
        /// </summary>
        [HttpPost]
        public async Task<PageOutput<RevenuesDTO>> GetRevenuesStatistics(StatisticsQueryDTO queryParam)
        {
            var bDate = new DateTime(queryParam.BeginDate.Year, queryParam.BeginDate.Month, 1);
            var eDate = new DateTime(queryParam.EndDate.Year, queryParam.EndDate.Month, 1);
            Expression<Func<Workload, bool>> workloadLambda = x => x.DataFrom == (int)WorkLoadFromStatus.FinalConfirm;
            workloadLambda = workloadLambda.And(x => x.WorkTime >= bDate && x.WorkTime <= eDate);

            Expression<Func<Trial, bool>> trialLambda = x => true;
            if (Guid.Empty != queryParam.CroId && queryParam.CroId != null)
            {
                trialLambda = trialLambda.And(u => u.CROId == queryParam.CroId);
            }
            if (!string.IsNullOrWhiteSpace(queryParam.TrialCode))
            {
                var trialCode = queryParam.TrialCode.Trim();
                trialLambda = trialLambda.And(u => u.TrialCode.Contains(trialCode));
            }

            if (queryParam.AttendedReviewerType != null)
            {
                trialLambda = trialLambda.And(u => u.AttendedReviewerType == queryParam.AttendedReviewerType);
            }

            Expression<Func<Doctor, bool>> doctorLambda = x => true;

            if (!string.IsNullOrWhiteSpace(queryParam.Reviewer))
            {
                var reviewer = queryParam.Reviewer.Trim();
                doctorLambda = doctorLambda.And(u => u.ChineseName.Contains(reviewer)
                                                     || u.FirstName.Contains(reviewer)
                                                     || u.LastName.Contains(reviewer)
                                                      || u.ReviewerCode.Contains(reviewer));
            }
            if (queryParam.Nation != null)
            {
                doctorLambda = doctorLambda.And(u => u.Nation == queryParam.Nation);
            }

            List<RevenuesDTO> incomeList = new List<RevenuesDTO>();
            IQueryable<RevenuesDTO>? query=null ;
            var propName = string.Empty;
            var count = 0;

            #region  按照详细维度 ReviewId  TrialId

            if (queryParam.StatType == 0)
            {
                query = from workLoad in _workloadRepository.Where(workloadLambda)
                        join doctor in _doctorRepository.Where(doctorLambda)
                            on workLoad.DoctorId equals doctor.Id
                        join trial in _trialRepository.Where(trialLambda)
                            on workLoad.TrialId equals trial.Id
                        join cro in _croRepository.AsQueryable() on trial.CROId equals cro.Id into ttt
                        from croItem in ttt.DefaultIfEmpty()
                        join trialCost in _trialRevenuePriceRepository.AsQueryable() on workLoad.TrialId equals trialCost.TrialId into c
                        from trialCost in c.DefaultIfEmpty()
                        select new RevenuesDTO
                        {

                            TrialId = workLoad.TrialId,
                            Cro = croItem.CROName,
                            ReviewerCode = doctor.ReviewerCode,
                            ChineseName = doctor.ChineseName,
                            FirstName = doctor.FirstName,
                            LastName = doctor.LastName,

                            Indication = trial.Indication,
                            TrialCode = trial.TrialCode,
                            Expedited = trial.Expedited,
                            CroId = trial.CROId,

                            Downtime = workLoad.Downtime * trialCost.Downtime,
                            Training = workLoad.Training * trialCost.Training,
                            Timepoint = workLoad.Timepoint * trialCost.Timepoint,
                            TimepointIn24H = workLoad.TimepointIn24H * trialCost.TimepointIn24H,
                            TimepointIn48H = workLoad.TimepointIn48H * trialCost.TimepointIn48H,
                            Global = workLoad.Global * trialCost.Global,
                            Adjudication = workLoad.Adjudication * trialCost.Adjudication,
                            AdjudicationIn24H =
                               workLoad.AdjudicationIn24H * trialCost.AdjudicationIn24H,
                            AdjudicationIn48H = workLoad.AdjudicationIn48H * trialCost.AdjudicationIn48H,

                            YearMonth = workLoad.YearMonth,

                            Total = (workLoad.Downtime * trialCost.Downtime +
                                     workLoad.Training * trialCost.Training +
                                     workLoad.Timepoint * trialCost.Timepoint +
                                     workLoad.TimepointIn24H * trialCost.TimepointIn24H +
                                     workLoad.TimepointIn48H * trialCost.TimepointIn48H +
                                     workLoad.Global * trialCost.Global +
                                     workLoad.Adjudication * trialCost.Adjudication +
                                     workLoad.AdjudicationIn24H * trialCost.AdjudicationIn24H +
                                     workLoad.AdjudicationIn48H * trialCost.AdjudicationIn48H +
                                     workLoad.RefresherTraining * trialCost.RefresherTraining
                                     )

                        };

                //处理排序字段
                propName = queryParam.SortField == "" ? "ReviewerCode" : queryParam.SortField;

            }
            //按照项目维度
            if (queryParam.StatType == 1)
            {

                var workloadQuery = from workLoad in _workloadRepository.Where(workloadLambda)

                                    group workLoad by workLoad.TrialId
                    into gWorkLoad
                                    select new
                                    {
                                        TrialId = gWorkLoad.Key,
                                        Downtime = gWorkLoad.Sum(t => t.Downtime),
                                        Training = gWorkLoad.Sum(t => t.Training),
                                        Timepoint = gWorkLoad.Sum(t => t.Timepoint),
                                        TimepointIn24H = gWorkLoad.Sum(t => t.TimepointIn24H),
                                        TimepointIn48H = gWorkLoad.Sum(t => t.TimepointIn48H),
                                        Global = gWorkLoad.Sum(t => t.Global),
                                        Adjudication = gWorkLoad.Sum(t => t.Adjudication),
                                        AdjudicationIn24H = gWorkLoad.Sum(t => t.AdjudicationIn24H),
                                        AdjudicationIn48H = gWorkLoad.Sum(t => t.AdjudicationIn48H),
                                        RefresherTraining = gWorkLoad.Sum(t => t.RefresherTraining),
                                    };

                query = from workLoad in workloadQuery
                        join trialCost in _trialRevenuePriceRepository.AsQueryable() on workLoad.TrialId equals trialCost.TrialId
                            into c
                        from trialCost in c.DefaultIfEmpty()
                        join trial in _trialRepository.Where(trialLambda) on workLoad.TrialId equals trial.Id
                        join cro in _croRepository.AsQueryable() on trial.CROId equals cro.Id into ttt
                        from croItem in ttt.DefaultIfEmpty()
                        select new RevenuesDTO
                        {

                            TrialId = trial.Id,
                            Indication = trial.Indication,
                            TrialCode = trial.TrialCode,
                            Expedited = trial.Expedited,
                            CroId = trial.CROId,
                            Cro = croItem.CROName,
                            Training = workLoad.Training * trialCost.Training,
                            Timepoint = workLoad.Timepoint * trialCost.Timepoint,
                            TimepointIn24H = workLoad.TimepointIn24H * trialCost.TimepointIn24H,
                            TimepointIn48H = workLoad.TimepointIn48H * trialCost.TimepointIn48H,
                            Adjudication = workLoad.Adjudication * trialCost.Adjudication,
                            AdjudicationIn24H = workLoad.AdjudicationIn24H * trialCost.AdjudicationIn24H,
                            AdjudicationIn48H = workLoad.AdjudicationIn48H * trialCost.AdjudicationIn48H,
                            Global = workLoad.Global * trialCost.Global,
                            Downtime = workLoad.Downtime * trialCost.Downtime,

                            Total = (workLoad.Downtime * trialCost.Downtime +
                                     workLoad.Training * trialCost.Training +
                                     workLoad.Timepoint * trialCost.Timepoint +
                                     workLoad.TimepointIn24H * trialCost.TimepointIn24H +
                                     workLoad.TimepointIn48H * trialCost.TimepointIn48H +
                                     workLoad.Global * trialCost.Global +
                                     workLoad.Adjudication * trialCost.Adjudication +
                                     workLoad.AdjudicationIn24H * trialCost.AdjudicationIn24H +
                                     workLoad.AdjudicationIn48H * trialCost.AdjudicationIn48H +
                                     workLoad.RefresherTraining * trialCost.RefresherTraining
                                )
                        };

                //处理排序字段
                propName = queryParam.SortField == "" ? "TrialCode" : queryParam.SortField;

            }

            //按照人的维度
            if (queryParam.StatType == 2)
            {
                var workloadQuery = from workLoad in _workloadRepository.Where(workloadLambda)
                                    join doctor in _doctorRepository.Where(doctorLambda)
                                                        on workLoad.DoctorId equals doctor.Id
                                    join trial in _trialRepository.Where(trialLambda) on workLoad.TrialId equals trial.Id
                                    join trialCost in _trialRevenuePriceRepository.AsQueryable() on workLoad.TrialId equals trialCost.TrialId into c
                                    from trialCost in c.DefaultIfEmpty()

                                    select new
                                    {
                                        DoctorId = workLoad.DoctorId,
                                        Downtime = workLoad.Downtime * trialCost.Downtime,
                                        Training = workLoad.Training * trialCost.Training,
                                        Timepoint = workLoad.Timepoint * trialCost.Timepoint,
                                        TimepointIn24H = workLoad.TimepointIn24H * trialCost.TimepointIn24H,
                                        TimepointIn48H = workLoad.TimepointIn48H * trialCost.TimepointIn48H,
                                        Global = workLoad.Global * trialCost.Global,
                                        Adjudication = workLoad.Adjudication * trialCost.Adjudication,
                                        AdjudicationIn24H =
                                             workLoad.AdjudicationIn24H * trialCost.AdjudicationIn24H,
                                        AdjudicationIn48H = workLoad.AdjudicationIn48H * trialCost.AdjudicationIn48H,
                                        RefresherTraining = workLoad.RefresherTraining * trialCost.RefresherTraining,
                                        ReviewerCode = doctor.ReviewerCode,
                                        ChineseName = doctor.ChineseName,
                                        FirstName = doctor.FirstName,
                                        LastName = doctor.LastName,

                                    };


                query = workloadQuery.GroupBy(t => new { t.DoctorId, t.ReviewerCode, t.ChineseName, t.FirstName, t.LastName }).Select(gWorkLoad => new RevenuesDTO
                {
                    ReviewerCode = gWorkLoad.Key.ReviewerCode,
                    ChineseName = gWorkLoad.Key.ChineseName,
                    FirstName = gWorkLoad.Key.FirstName,
                    LastName = gWorkLoad.Key.LastName,

                    Downtime = gWorkLoad.Sum(t => t.Downtime),
                    Training = gWorkLoad.Sum(t => t.Training),
                    Timepoint = gWorkLoad.Sum(t => t.Timepoint),
                    TimepointIn24H = gWorkLoad.Sum(t => t.TimepointIn24H),
                    TimepointIn48H = gWorkLoad.Sum(t => t.TimepointIn48H),
                    Global = gWorkLoad.Sum(t => t.Global),
                    Adjudication = gWorkLoad.Sum(t => t.Adjudication),
                    AdjudicationIn24H = gWorkLoad.Sum(t => t.AdjudicationIn24H),
                    AdjudicationIn48H = gWorkLoad.Sum(t => t.AdjudicationIn48H),

                    Total = gWorkLoad.Sum(t => t.Downtime) +
                            gWorkLoad.Sum(t => t.Training) +
                            gWorkLoad.Sum(t => t.Timepoint) +
                            gWorkLoad.Sum(t => t.TimepointIn24H) +
                            gWorkLoad.Sum(t => t.TimepointIn48H) +
                            gWorkLoad.Sum(t => t.Global) +
                            gWorkLoad.Sum(t => t.Adjudication) +
                            gWorkLoad.Sum(t => t.AdjudicationIn24H) +
                            gWorkLoad.Sum(t => t.AdjudicationIn48H) +
                            gWorkLoad.Sum(t => t.RefresherTraining)

                });

                propName = queryParam.SortField == string.Empty ? "ReviewerCode" : queryParam.SortField;


            }

            //按照月份维度
            if (queryParam.StatType == 3)
            {
                var workloadQuery = from workLoad in _workloadRepository.Where(workloadLambda)
                                    join trial in _trialRepository.Where(trialLambda)
                                        on workLoad.TrialId equals trial.Id
                                    join doctor in _doctorRepository.Where(doctorLambda)
                                        on workLoad.DoctorId equals doctor.Id
                                    join trialCost in _trialRevenuePriceRepository.AsQueryable() on workLoad.TrialId equals trialCost.TrialId into c
                                    from trialCost in c.DefaultIfEmpty()

                                    select new
                                    {
                                        workLoad.YearMonth,
                                        Downtime = workLoad.Downtime * trialCost.Downtime,
                                        Training = workLoad.Training * trialCost.Training,
                                        Timepoint = workLoad.Timepoint * trialCost.Timepoint,
                                        TimepointIn24H = workLoad.TimepointIn24H * trialCost.TimepointIn24H,
                                        TimepointIn48H = workLoad.TimepointIn48H * trialCost.TimepointIn48H,
                                        Global = workLoad.Global * trialCost.Global,
                                        Adjudication = workLoad.Adjudication * trialCost.Adjudication,
                                        AdjudicationIn24H =
                                            workLoad.AdjudicationIn24H * trialCost.AdjudicationIn24H,
                                        AdjudicationIn48H = workLoad.AdjudicationIn48H * trialCost.AdjudicationIn48H,
                                        RefresherTraining = workLoad.RefresherTraining * trialCost.RefresherTraining,

                                    };

                query = workloadQuery.GroupBy(t => t.YearMonth).Select(gWorkLoad => new RevenuesDTO
                {

                    YearMonth = gWorkLoad.Key,
                    Downtime = gWorkLoad.Sum(t => t.Downtime),
                    Training = gWorkLoad.Sum(t => t.Training),
                    Timepoint = gWorkLoad.Sum(t => t.Timepoint),
                    TimepointIn24H = gWorkLoad.Sum(t => t.TimepointIn24H),
                    TimepointIn48H = gWorkLoad.Sum(t => t.TimepointIn48H),
                    Global = gWorkLoad.Sum(t => t.Global),
                    Adjudication = gWorkLoad.Sum(t => t.Adjudication),
                    AdjudicationIn24H = gWorkLoad.Sum(t => t.AdjudicationIn24H),
                    AdjudicationIn48H = gWorkLoad.Sum(t => t.AdjudicationIn48H),
                    Total = gWorkLoad.Sum(t => t.Downtime) +
                            gWorkLoad.Sum(t => t.Training) +
                            gWorkLoad.Sum(t => t.Timepoint) +
                            gWorkLoad.Sum(t => t.TimepointIn24H) +
                            gWorkLoad.Sum(t => t.TimepointIn48H) +
                            gWorkLoad.Sum(t => t.Global) +
                            gWorkLoad.Sum(t => t.Adjudication) +
                            gWorkLoad.Sum(t => t.AdjudicationIn24H) +
                            gWorkLoad.Sum(t => t.AdjudicationIn48H) +
                             gWorkLoad.Sum(t => t.RefresherTraining)

                });
                propName = queryParam.SortField == string.Empty ? "YearMonth" : queryParam.SortField;
            }


            #endregion
            //if (propName == "FirstName" || propName == "LastName")
            //{
            //    query = param.Asc
            //        ? query.OrderBy(t => t.LastName).ThenBy(t => t.FirstName)
            //        : query.OrderByDescending(t => t.LastName).ThenBy(t => t.FirstName);
            //}

            //非详细 只用单字段排序
            if (queryParam.StatType != 0)
            {
                query = queryParam.Asc ? query.OrderBy(propName) : query.OrderByDescending(propName);
            }
            //详情  多字段排序
            if (queryParam.StatType == 0)
            {
                query = queryParam.Asc ? query.OrderBy(propName).ThenBy(t => t.TrialId).ThenBy(t => t.YearMonth).ThenBy(t => t.ReviewerCode) :
                        query.OrderByDescending(propName).ThenBy(t => t.TrialId).ThenBy(t => t.YearMonth).ThenBy(t => t.ReviewerCode)
                    ;
            }


            count = query!.Count();
            query = query!.Skip((queryParam.PageIndex - 1) * queryParam.PageSize).Take(queryParam.PageSize);

            incomeList = await query.ToListAsync();

            #region 处理缺失项目价格       按照医生 或者月份维度

            if (queryParam.StatType == 2 || queryParam.StatType == 3)
            {
                var hasIncomePriceTrialIds = await _trialRevenuePriceRepository.Select(t => t.TrialId).ToListAsync();

                workloadLambda = workloadLambda.And(t => !hasIncomePriceTrialIds.Contains(t.TrialId));
                var doctorMissingTrialCodesQuery = (from workLoad in _workloadRepository.Where(workloadLambda)
                                                    join trial in _trialRepository.AsQueryable() on workLoad.TrialId equals trial.Id
                                                    select new
                                                    {
                                                        DoctorId = workLoad.DoctorId,
                                                        Month = workLoad.YearMonth,
                                                        TrialCode = trial.TrialCode
                                                    }).Distinct();

                var doctorMissingTrialCodes = ((await doctorMissingTrialCodesQuery.ToListAsync()).GroupBy(t => t.DoctorId).Select(g => new
                {
                    DoctorId = g.Key,
                    TrialCodes = g.Select(u => u.TrialCode).Distinct().ToList()
                })).ToList();

                var monthMissingTrialCode = ((await doctorMissingTrialCodesQuery.ToListAsync()).GroupBy(t => t.Month).Select(g => new
                {
                    Month = g.Key,
                    TrialCodes = g.Select(u => u.TrialCode).Distinct().ToList()
                })).ToList();

                incomeList.ForEach(income =>
                {
                    var doctor = doctorMissingTrialCodes.FirstOrDefault(t => t.DoctorId == income.Id);
                    var month = monthMissingTrialCode.FirstOrDefault(t => t.Month == income.YearMonth);

                    if (queryParam.StatType == 2)
                    {
                        income.MissingTrialCodes = doctor == null ? new List<string>() : doctor.TrialCodes;
                    }
                    else
                    {
                        income.MissingTrialCodes = month == null ? new List<string>() : month.TrialCodes;
                    }
                });
            }

            if (queryParam.StatType == 0 || queryParam.StatType == 1)
            {
                incomeList.ForEach(income =>
                {
                    List<string> temp = new List<string>();



                    if (Math.Abs(income.Total) < 0.001m)
                    {
                        temp.Add(income.TrialCode);
                        income.MissingTrialCodes = temp;
                    }

                });
            }
            #endregion

            return new PageOutput<RevenuesDTO>(queryParam.PageIndex, queryParam.PageSize, count, incomeList);

        }

        /// <summary>
        /// 收入支出分析接口,按照项目维度分析统计
        /// </summary>
        [HttpPost]
        public async Task<List<TrialAnalysisDTO>> GetTrialAnalysisList(TrialAnalysisQueryDTO param)
        {
            var bDate = new DateTime(param.BeginDate.Year, param.BeginDate.Month, 1);
            var eDate = new DateTime(param.EndDate.Year, param.EndDate.Month, 1);

            Expression<Func<Workload, bool>> workloadLambda = x => x.DataFrom == (int)WorkLoadFromStatus.FinalConfirm;

            Expression<Func<Trial, bool>> trialLambda = x => true;
            if (Guid.Empty != param.CroId && param.CroId != null)
            {
                trialLambda = trialLambda.And(u => u.CROId == param.CroId);
            }
            if (!string.IsNullOrWhiteSpace(param.TrialCode))
            {
                var trialCode = param.TrialCode.Trim();
                trialLambda = trialLambda.And(u => u.TrialCode.Contains(trialCode));
            }
            if (param.AttendedReviewerType != null)
            {
                trialLambda = trialLambda.And(u => u.AttendedReviewerType == param.AttendedReviewerType);
            }

            var lockedPaymentIdAndYearMonth = _paymentRepository.Where(t => t.IsLock && t.YearMonthDate >= bDate && t.YearMonthDate <= eDate).Select(t => new { PaymentId = t.Id, t.YearMonth, t.DoctorId });

            var costStatisticsIds = await lockedPaymentIdAndYearMonth.Select(t => t.PaymentId).ToListAsync();

            var lockedDoctorIdAndYearMonthQueryable = lockedPaymentIdAndYearMonth.Select(t => new { t.YearMonth, t.DoctorId });


            ////工作量过滤查询 锁定得月份
            //workloadLambda = workloadLambda.And(x => lockedDoctorIdAndYearMonthQueryable.Contains());

            var trialPayQuery = from costStatisticsDetail in _paymentDetailRepository.AsQueryable()
                    .Where(t => costStatisticsIds.Contains(t.PaymentId) && t.TrialCode != "Volume Reward")
                                group costStatisticsDetail by costStatisticsDetail.TrialId
                into g
                                select new
                                {
                                    TrialId = g.Key,
                                    PaymentUSD = g.Sum(t => t.PaymentUSD)
                                };


            var workloadQuery = from workLoad in _workloadRepository.Where(workloadLambda)
                                join lockedDoctorAndMonth in lockedDoctorIdAndYearMonthQueryable on new { workLoad.DoctorId, YearMonth = workLoad.YearMonth } equals new { lockedDoctorAndMonth.DoctorId, lockedDoctorAndMonth.YearMonth }
                                group workLoad by workLoad.TrialId

                into gWorkLoad
                                select new
                                {
                                    TrialId = gWorkLoad.Key,
                                    Downtime = gWorkLoad.Sum(t => t.Downtime),
                                    Training = gWorkLoad.Sum(t => t.Training),
                                    Timepoint = gWorkLoad.Sum(t => t.Timepoint),
                                    TimepointIn24H = gWorkLoad.Sum(t => t.TimepointIn24H),
                                    TimepointIn48H = gWorkLoad.Sum(t => t.TimepointIn48H),
                                    Global = gWorkLoad.Sum(t => t.Global),
                                    Adjudication = gWorkLoad.Sum(t => t.Adjudication),
                                    AdjudicationIn24H = gWorkLoad.Sum(t => t.AdjudicationIn24H),
                                    AdjudicationIn48H = gWorkLoad.Sum(t => t.AdjudicationIn48H)

                                };

            var workloadIncomeQuery = from workLoad in workloadQuery
                                      join trialCost in _trialRevenuePriceRepository.AsQueryable() on workLoad.TrialId equals trialCost.TrialId
                                          into c
                                      from trialCost in c.DefaultIfEmpty()
                                      join trial in _trialRepository.Where(trialLambda) on workLoad.TrialId equals trial.Id into t
                                      from trial in t.DefaultIfEmpty()
                                      join cro in _croRepository.AsQueryable() on trial.CROId equals cro.Id into ttt
                                      from croItem in ttt.DefaultIfEmpty()
                                      select new TrialAnalysisDTO
                                      {
                                          TrialId = trial.Id,
                                          Indication = trial.Indication,
                                          TrialCode = trial.TrialCode,
                                          Expedited = trial.Expedited,
                                          Cro = croItem == null ? "" : croItem.CROName,

                                          Type = "Trial",

                                          RevenusUSD = (workLoad.Downtime * trialCost.Downtime) +
                                                       (workLoad.Training * trialCost.Training) +
                                                       (workLoad.Timepoint * trialCost.Timepoint)
                                                       + (workLoad.TimepointIn24H * trialCost.TimepointIn24H)
                                                       + (workLoad.TimepointIn48H * trialCost.TimepointIn48H)
                                                       + (workLoad.Adjudication * trialCost.Adjudication)
                                                       + (workLoad.AdjudicationIn24H * trialCost.AdjudicationIn24H)
                                                       + (workLoad.AdjudicationIn48H * trialCost.AdjudicationIn48H)
                                                       + (workLoad.Global * trialCost.Global),

                                      };


            var trialPayList = await trialPayQuery.OrderBy(t => t.PaymentUSD).ToListAsync();
            var workloadIncomeList = await workloadIncomeQuery.ToListAsync();
            var returnList = workloadIncomeList;
            returnList.ForEach(t =>
            {
                var pay = trialPayList.FirstOrDefault(u => u.TrialId == t.TrialId);
                t.PaymentUSD = pay == null ? 0 : pay.PaymentUSD;
            });

            if ((Guid.Empty == param.CroId || null == param.CroId) && string.IsNullOrWhiteSpace(param.TrialCode))
            {
                var volumeReward = _paymentDetailRepository.AsQueryable()
                    .Where(t => costStatisticsIds.Contains(t.PaymentId) && t.TrialCode == "Volume Reward")
                    .Sum(t => (decimal?)t.PaymentUSD) ?? 0;

                var adjustment = _payAdjustmentRepository.AsQueryable()
                    .Where(t => t.YearMonthDate >= param.BeginDate
                                && t.YearMonthDate <= param.EndDate && t.IsLock)
                    .Sum(u => (decimal?)u.AdjustmentUSD) ?? 0;

                returnList.Add(new TrialAnalysisDTO()
                {
                    Type = "Volume Reward",
                    RevenusUSD = 0,
                    PaymentUSD = volumeReward
                });
                returnList.Add(new TrialAnalysisDTO()
                {
                    Type = "Adjustment",
                    RevenusUSD = 0,
                    PaymentUSD = adjustment
                });
            }
            return returnList;
        }

        /// <summary>
        /// 收入支出分析接口,按照医生维度分析统计
        /// </summary>
        [HttpPost]
        public async Task<List<ReviewerAnalysisDTO>> GetReviewerAnalysisList(AnalysisQueryDTO param)
        {
            var beginDate = new DateTime(param.BeginDate.Year, param.BeginDate.Month, 1);
            var endDate = new DateTime(param.EndDate.Year, param.EndDate.Month, 1);

            Expression<Func<Workload, bool>> workloadLambda = x => x.DataFrom == (int)WorkLoadFromStatus.FinalConfirm;

            Expression<Func<Doctor, bool>> doctorLambda = x => true;
            if (!string.IsNullOrWhiteSpace(param.Reviewer))
            {
                var reviewer = param.Reviewer.Trim();
                doctorLambda = doctorLambda.And(u => u.ChineseName.Contains(reviewer)
                                                     || u.FirstName.Contains(reviewer)
                                                     || u.LastName.Contains(reviewer)
                                                     || u.ReviewerCode.Contains(reviewer));
            }
            if (param.Nation != null)
            {
                doctorLambda = doctorLambda.And(u => u.Nation == param.Nation);
            }

            var lockedPaymentIdAndYearMonth = _paymentRepository.Where(t => t.IsLock && t.YearMonthDate >= param.BeginDate && t.YearMonthDate <= param.EndDate).Select(t => new { PaymentId = t.Id, t.YearMonth, t.DoctorId });

            var lockedDoctorIdAndYearMonthQueryable = lockedPaymentIdAndYearMonth.Select(t => new { t.YearMonth, t.DoctorId });



            Expression<Func<Payment, bool>> monthlyPayLambda = x => x.IsLock && x.YearMonthDate >= beginDate && x.YearMonthDate <= endDate;
            var payQuery =
                from monthlyPayment in _paymentRepository.Where(monthlyPayLambda)
                               .GroupBy(t => t.DoctorId).Select(g => new
                               {
                                   ReviewerId = g.Key,
                                   PaymentUSD = g.Sum(u => u.PaymentUSD),
                                   PaymentCNY = g.Sum(u => u.PaymentCNY),
                                   AdjustmentCNY = g.Sum(u => u.AdjustmentCNY),
                                   AdjustmentUSD = g.Sum(u => u.AdjustmentUSD)
                               })
                join doctor in _doctorRepository.Where(doctorLambda) on monthlyPayment.ReviewerId equals doctor.Id
                select new MonthlyPaymentDTO
                {
                    ReviewerId = doctor.Id,
                    ChineseName = doctor.ChineseName,
                    FirstName = doctor.FirstName,
                    LastName = doctor.LastName,
                    ReviewerCode = doctor.ReviewerCode,
                    PaymentUSD = monthlyPayment.PaymentUSD,
                    PaymentCNY = monthlyPayment.PaymentCNY,
                    AdjustmentCNY = monthlyPayment.AdjustmentCNY,
                    AdjustmentUSD = monthlyPayment.AdjustmentUSD,
                    TotalUSD = monthlyPayment.AdjustmentUSD + monthlyPayment.PaymentUSD,
                    TotalCNY = monthlyPayment.AdjustmentCNY + monthlyPayment.PaymentCNY,
                };

            //获取工作量收入  workloadLambda 已经加入过滤  payment锁定月份

            ////工作量过滤查询 锁定得月份

            var workloadIncomeQuery = from workLoad in _workloadRepository.Where(workloadLambda)
                                      join doctor in _doctorRepository.Where(doctorLambda)
                                          on workLoad.DoctorId equals doctor.Id
                                      join lockedDoctorAndMonth in lockedDoctorIdAndYearMonthQueryable on new { workLoad.DoctorId, workLoad.YearMonth } equals new { lockedDoctorAndMonth.DoctorId, lockedDoctorAndMonth.YearMonth }
                                      join trialCost in _trialRevenuePriceRepository.AsQueryable() on workLoad.TrialId equals trialCost.TrialId into c
                                      from trialCost in c.DefaultIfEmpty()

                                      select new
                                      {
                                          DoctorId = workLoad.DoctorId,
                                          Downtime = workLoad.Downtime * trialCost.Downtime,
                                          Training = workLoad.Training * trialCost.Training,
                                          Timepoint = workLoad.Timepoint * trialCost.Timepoint,
                                          TimepointIn24H = workLoad.TimepointIn24H * trialCost.TimepointIn24H,
                                          TimepointIn48H = workLoad.TimepointIn48H * trialCost.TimepointIn48H,
                                          Global = workLoad.Global * trialCost.Global,
                                          Adjudication = workLoad.Adjudication * trialCost.Adjudication,
                                          AdjudicationIn24H = workLoad.AdjudicationIn24H * trialCost.AdjudicationIn24H,
                                          AdjudicationIn48H = workLoad.AdjudicationIn48H * trialCost.AdjudicationIn48H


                                      };

            //工作量收入按照人分组统计
            var workloadIncomeList = await workloadIncomeQuery.GroupBy(t => t.DoctorId).Select(gWorkLoad => new
            {

                DoctorId = gWorkLoad.Key,
                //TrialId = Guid.Empty,
                Downtime = gWorkLoad.Sum(t => t.Downtime),
                Training = gWorkLoad.Sum(t => t.Training),
                Timepoint = gWorkLoad.Sum(t => t.Timepoint),
                TimepointIn24H = gWorkLoad.Sum(t => t.TimepointIn24H),
                TimepointIn48H = gWorkLoad.Sum(t => t.TimepointIn48H),
                Global = gWorkLoad.Sum(t => t.Global),
                Adjudication = gWorkLoad.Sum(t => t.Adjudication),
                AdjudicationIn24H = gWorkLoad.Sum(t => t.AdjudicationIn24H),
                AdjudicationIn48H = gWorkLoad.Sum(t => t.AdjudicationIn48H),
            }).ToListAsync();
            var workloadPayList = payQuery.ToList();
            //var workloadIncomeList = workloadIncomeQuery.ToList();

            var returnList = new List<ReviewerAnalysisDTO>();

            #region 处理找到缺失的项目

            //有项目价格的trial Id 集合
            var hasIncomePriceTrialIds = await _trialRevenuePriceRepository.Select(t => t.TrialId).ToListAsync();

            workloadLambda = workloadLambda.And(t => !hasIncomePriceTrialIds.Contains(t.TrialId));
            var doctorMissingTrialCodesQuery = (from workLoad in _workloadRepository.Where(workloadLambda)
                                                join trial in _trialRepository.AsQueryable() on workLoad.TrialId equals trial.Id
                                                select new
                                                {
                                                    DoctorId = workLoad.DoctorId,
                                                    TrialCode = trial.TrialCode
                                                }).Distinct();

            var doctorMissingTrialCodes = ((await doctorMissingTrialCodesQuery.ToListAsync()).GroupBy(t => t.DoctorId).Select(g => new
            {
                DoctorId = g.Key,
                TrialCodes = g.Select(u => u.TrialCode).ToList()
            })).ToList();


            #endregion

            workloadPayList.ForEach(pay =>
            {
                var doctor = workloadIncomeList.FirstOrDefault(t => t.DoctorId == pay.ReviewerId);

                var doctorMissingCode = doctorMissingTrialCodes.FirstOrDefault(t => t.DoctorId == pay.ReviewerId);

                returnList.Add(new ReviewerAnalysisDTO()
                {
                    ReviewerId = pay.ReviewerId,
                    ChineseName = pay.ChineseName,
                    FirstName = pay.FirstName,
                    LastName = pay.LastName,
                    ReviewerCode = pay.ReviewerCode,
                    PaymentUSD = pay.PaymentUSD + pay.AdjustmentUSD,

                    //付费表的医生数量肯定事全的  工作量的不一定全 (只有调整)
                    RevenusUSD = doctor != null
                        ? doctor.Adjudication + doctor.AdjudicationIn24H + doctor.AdjudicationIn48H + doctor.Global +
                          doctor.Downtime + doctor.Training +
                          doctor.Timepoint + doctor.TimepointIn24H + doctor.TimepointIn48H
                        : 0,
                    MissingTrialCodes = doctorMissingCode != null ? doctorMissingCode.TrialCodes : new List<string>()
                });
            });
            return returnList.OrderBy(t => t.ReviewerCode).ToList();
        }

        /// <summary>
        /// 获取劳务费用列表
        /// </summary>
        [HttpPost]
        public async Task<List<LaborPayment>> GetLaborPaymentList(List<Guid> paymentIds)
        {
            var query = from payment in _paymentRepository.Where(t => paymentIds.Contains(t.Id))
                        join reviewer in _doctorRepository.AsQueryable() on payment.DoctorId equals reviewer.Id
                        join payInfo in _doctorPayInfoRepository.AsQueryable() on payment.DoctorId equals payInfo.DoctorId
                        select new LaborPayment()
                        {

                            ChineseName = reviewer.ChineseName,
                            FirstName = reviewer.FirstName,
                            LastName = reviewer.LastName,
                            ResidentId = payInfo.IDCard,
                            PaymentCNY = payment.PaymentCNY + payment.AdjustmentCNY,
                            YearMonth = payment.YearMonth,
                            Phone = reviewer.Phone,
                            AccountNumber = payInfo.BankCardNumber,
                            Bank = payInfo.BankName

                            //TaxCNY = payment.TaxCNY,
                            //ActuallyPaidCNY = payment.ActuallyPaidCNY,
                            //BankTransferCNY = payment.BankTransferCNY,
                        };
            var result = await query.ToListAsync();

            result.ForEach(t =>
            {
                t.TaxCNY =GetTax2(t.PaymentCNY);

                t.ActuallyPaidCNY = t.PaymentCNY - t.TaxCNY;
                t.BankTransferCNY = t.PaymentCNY - t.TaxCNY;
            });

            return result;

        }

        /// <summary>
        /// 锁定医生费用,锁定后,无法变更该医生对应月份的费用和工作量[New]
        /// </summary>
        [HttpPost]
        public async Task<IResponseOutput> LockMonthlyPayment(LockPaymentDTO param)
        {
            var reviewerIds = param.ReviewerIdList;
            var yearMonth = param.Month.ToString("yyyy-MM");
            var isLock = param.IsLock;


            var paymentLockSuccess = await _paymentRepository.UpdateFromQueryAsync(u => reviewerIds.Contains(u.DoctorId) && u.YearMonth == yearMonth, t => new Payment
            {
                IsLock = isLock
            });

            var adjustmentLockSuccess = await _payAdjustmentRepository.UpdateFromQueryAsync(
                t => t.YearMonth == yearMonth && reviewerIds.Contains(t.ReviewerId), u =>
                    new PaymentAdjustment()
                    {
                        IsLock = true
                    });
           await  _doctorWorkloadRepository.UpdateFromQueryAsync(u => reviewerIds.Contains(u.DoctorId) && u.YearMonth == yearMonth,
                t => new Workload { IsLock = true });

            return ResponseOutput.Result(paymentLockSuccess || adjustmentLockSuccess);
        }

        [NonDynamicMethod]
        private static decimal GetTax2(decimal paymentCNY)
        {
            if (paymentCNY >= 0 && paymentCNY <= 800)
            {
                return 0;
            }

            var calculateTaxPart = paymentCNY <= 4000 ? paymentCNY - 800 : paymentCNY * (1 - 0.2m);


            if (calculateTaxPart <= 20000)
            {
                return calculateTaxPart * 0.2m;
            }

            else if (calculateTaxPart > 20000 && calculateTaxPart <= 50000)
            {
                return calculateTaxPart * 0.3m - 2000;
            }

            else
            {
                return calculateTaxPart * 0.4m - 7000;
            }


        }
    }
}