using AutoMapper;
using IRaCIS.Application.Interfaces;
using IRaCIS.Application.Contracts.Pay;
using IRaCIS.Core.Domain.Share;
using Microsoft.AspNetCore.Mvc;
using Panda.DynamicWebApi.Attributes;

namespace IRaCIS.Application.Services
{
    [ApiExplorerSettings(GroupName = "Financial")]
    public class PaymentAdjustmentService : BaseService, IPaymentAdjustmentService
    {
        private readonly IRepository<PaymentAdjustment> _payAdjustmentRepository;
        private readonly IRepository<Doctor> _doctorRepository;
        private readonly IRepository<ExchangeRate> _exchangeRateRepository;
        private readonly IRepository<Payment> _paymentRepository;


        public PaymentAdjustmentService(IRepository<PaymentAdjustment> costAdjustmentRepository, IRepository<Doctor> doctorRepository,
            IRepository<ExchangeRate> exchangeRateRepository, IRepository<Payment> paymentRepository, IMapper mapper)
        {
            _payAdjustmentRepository = costAdjustmentRepository;
            _doctorRepository = doctorRepository;
            _exchangeRateRepository = exchangeRateRepository;
            _paymentRepository = paymentRepository;

        }

        /// <summary>
        /// 添加或更新费用调整[AUTH]
        /// </summary>

        [HttpPost]
        public async Task<IResponseOutput> AddOrUpdatePaymentAdjustment(PaymentAdjustmentCommand addOrUpdateModel)
        {

            var yearMonthDate = new DateTime(addOrUpdateModel.YearMonth.Year, addOrUpdateModel.YearMonth.Month, 1);
            var yearMonth = addOrUpdateModel.YearMonth.ToString("yyyy-MM");

            var payment = await _paymentRepository.FirstOrDefaultAsync(u => u.DoctorId == addOrUpdateModel.ReviewerId
            && u.YearMonth == yearMonth);

            //判断付费表中是否有记录
            if (payment == null)
            {
                //没有 添加仅有的调整费用记录
                payment = new Payment
                {
                    DoctorId = addOrUpdateModel.ReviewerId,
                    YearMonth = yearMonth,
                    YearMonthDate = yearMonthDate,
                    PaymentCNY = 0,
                    PaymentUSD = 0,
                    AdjustmentCNY = 0,
                    AdjustmentUSD = 0
                };
                await _paymentRepository.AddAsync(payment);
                await _paymentRepository.SaveChangesAsync();
            }
            else
            {
                if (payment.IsLock)
                {
                    return ResponseOutput.NotOk("Doctor payment has confirmed lock");
                }
            }

            var exchangeRate = await _exchangeRateRepository.FirstOrDefaultAsync(t => t.YearMonth == yearMonth);
            if (addOrUpdateModel.Id == Guid.Empty || addOrUpdateModel.Id == null)
            {
                var costAdjustment = _mapper.Map<PaymentAdjustment>(addOrUpdateModel);

                //视图模型和领域模型没对应 重新赋值  
                costAdjustment.ExchangeRate = exchangeRate?.Rate ?? 0;
                costAdjustment.AdjustmentCNY = addOrUpdateModel.AdjustPaymentUSD * (exchangeRate?.Rate ?? 0);
                costAdjustment.AdjustmentUSD = addOrUpdateModel.AdjustPaymentUSD;

                await _payAdjustmentRepository.AddAsync(costAdjustment);

                //添加的时候，每个月调整汇总费用 需要加上本次调整的费用
                payment.AdjustmentCNY += costAdjustment.AdjustmentCNY;
                payment.AdjustmentUSD += costAdjustment.AdjustmentUSD;

                //await _paymentRepository.UpdateAsync(payment);

                await _paymentRepository.UpdateAsync(payment, u => new Payment()
                {
                    AdjustmentCNY = payment.AdjustmentCNY + costAdjustment.AdjustmentCNY,
                    AdjustmentUSD = payment.AdjustmentUSD + costAdjustment.AdjustmentUSD
                });

                await _payAdjustmentRepository.SaveChangesAsync();


                return ResponseOutput.Ok(costAdjustment.Id.ToString());

            }
            else
            {



                // 更新的时候，先查出来，更新前的调整费用数据

                var paymentAdjust = await _payAdjustmentRepository.FirstOrDefaultAsync(t => t.Id == addOrUpdateModel.Id);


                _mapper.Map(addOrUpdateModel, paymentAdjust);

                paymentAdjust.ExchangeRate = exchangeRate?.Rate ?? 0;
                paymentAdjust.AdjustmentUSD = addOrUpdateModel.AdjustPaymentUSD;
                paymentAdjust.AdjustmentCNY = addOrUpdateModel.AdjustPaymentUSD * (exchangeRate?.Rate ?? 0);

                //await _payAdjustmentRepository.UpdateAsync(paymentAdjust);

                var success = await _payAdjustmentRepository.SaveChangesAsync();

                if (success)
                {

                    var adjustmentList = await _payAdjustmentRepository.Where(u => u.ReviewerId == addOrUpdateModel.ReviewerId && u.YearMonth == yearMonth).ToListAsync();


                    await _paymentRepository.UpdateAsync(payment, u => new Payment()
                    {
                        AdjustmentCNY = adjustmentList.Sum(t => t.AdjustmentCNY),
                        AdjustmentUSD = adjustmentList.Sum(t => t.AdjustmentUSD)
                    });

                    //payment.AdjustmentCNY = adjustmentList.Sum(t => t.AdjustmentCNY);
                    //payment.AdjustmentUSD = adjustmentList.Sum(t => t.AdjustmentUSD);

                    //await _paymentRepository.UpdateAsync(payment);

                    await _paymentRepository.SaveChangesAsync();
                }

                //查询得到历史汇总



                return ResponseOutput.Ok(success);

                #region 逻辑存在错误  问题待查

                //// 更新的时候，先查出来，更新前的调整费用数据
                //var paymentAdjust = _payAdjustmentRepository.FindSingleOrDefault(t => t.Id == addOrUpdateModel.Id);

                ////减去数据库本条记录的值
                //payment.AdjustmentCNY = -paymentAdjust.AdjustmentCNY;
                //payment.AdjustmentUSD = -paymentAdjust.AdjustmentUSD;

                //_mapper.Map(addOrUpdateModel, paymentAdjust);

                //paymentAdjust.ExchangeRate = exchangeRate?.Rate ?? 0;
                //paymentAdjust.AdjustmentUSD = addOrUpdateModel.AdjustPaymentUSD;
                //paymentAdjust.AdjustmentCNY = addOrUpdateModel.AdjustPaymentUSD * (exchangeRate?.Rate ?? 0);

                //_payAdjustmentRepository.Update(paymentAdjust);

                ////查询得到历史汇总
                //var adjustment = _payAdjustmentRepository.Find(u => u.ReviewerId == addOrUpdateModel.ReviewerId && u.YearMonth == yearMonth)
                //    .GroupBy(u => new { u.ReviewerId, u.YearMonth }).Select(g => new
                //    {
                //        AdjustCNY = g.Sum(t => t.AdjustmentCNY),
                //        AdjustUSD = g.Sum(t => t.AdjustmentUSD)
                //    }).FirstOrDefault();

                ////最终的值 等于历史汇总 减去更新前的加上当前更新的值
                //payment.AdjustmentCNY += (adjustment.AdjustCNY + paymentAdjust.AdjustmentCNY);
                //payment.AdjustmentUSD += (adjustment.AdjustUSD + paymentAdjust.AdjustmentUSD);

                //_paymentRepository.Update(payment);

                //var success = _payAdjustmentRepository.SaveChanges();
                //return ResponseOutput.Result(success, success ? string.Empty : StaticData.UpdateFailed);

                #endregion



            }
        }
        /// <summary>
        /// 删除费用调整记录
        /// </summary>

        [HttpDelete("{id:guid}")]
        public async Task<IResponseOutput> DeletePaymentAdjustment(Guid id)
        {
            var adjustPayment = await _payAdjustmentRepository.FirstOrDefaultAsync(u => u.Id == id);


            await _payAdjustmentRepository.DeleteAsync(new PaymentAdjustment() { Id = id });

            var success = await _payAdjustmentRepository.SaveChangesAsync();

            if (success)
            {

                var adjustmentList = await _payAdjustmentRepository.Where(u =>
                     u.ReviewerId == adjustPayment.ReviewerId && u.YearMonth == adjustPayment.YearMonth).ToListAsync();


                var monthPay = await _paymentRepository.FirstOrDefaultAsync(t =>
                    t.DoctorId == adjustPayment.ReviewerId && t.YearMonth == adjustPayment.YearMonth);



                await _paymentRepository.UpdateAsync(monthPay, u => new Payment()
                {
                    AdjustmentCNY = adjustmentList.Sum(t => t.AdjustmentCNY),
                    AdjustmentUSD = adjustmentList.Sum(t => t.AdjustmentUSD)
                });


                //monthPay.AdjustmentCNY = adjustmentList.Sum(t => t.AdjustmentCNY);
                //monthPay.AdjustmentUSD = adjustmentList.Sum(t => t.AdjustmentUSD);
                //await _paymentRepository.UpdateAsync(monthPay);

                await _paymentRepository.SaveChangesAsync();
            }



            return ResponseOutput.Result(success);
        }

        /// <summary>
        /// 获取费用调整列表
        /// </summary>
        [HttpPost]
        public async Task<PageOutput<PaymentAdjustmentDetailDTO>> GetPaymentAdjustmentList(PaymentAdjustmentQueryDTO queryParam)
        {

            var beginYearMonth = queryParam.BeginMonth.AddDays(1 - queryParam.BeginMonth.Day);
            var endYearMonth = queryParam.EndMonth.AddDays(1 - queryParam.EndMonth.Day).AddMonths(1).AddDays(-1);

            var costAdjustmentQueryable = from costAdjustment in _payAdjustmentRepository
                    .Where(t => t.YearMonthDate >= beginYearMonth && t.YearMonthDate <= endYearMonth)
                                          join doctor in _doctorRepository.AsQueryable().
                                          WhereIf(!string.IsNullOrWhiteSpace(queryParam.Reviewer),
                                          u => u.ChineseName.Contains(queryParam.Reviewer) ||
                                          (u.LastName + u.FirstName).Contains(queryParam.Reviewer) ||
                                          u.ReviewerCode.Contains(queryParam.Reviewer))
                                              on costAdjustment.ReviewerId equals doctor.Id

                                          select new PaymentAdjustmentDetailDTO()
                                          {
                                              AdjustPaymentCNY = costAdjustment.AdjustmentCNY,
                                              AdjustPaymentUSD = costAdjustment.AdjustmentUSD,
                                              IsLock = costAdjustment.IsLock,
                                              Id = costAdjustment.Id,
                                              YearMonth = costAdjustment.YearMonth,
                                              YearMonthDate = costAdjustment.YearMonthDate,
                                              Note = costAdjustment.Note,
                                              ReviewerId = costAdjustment.ReviewerId,
                                              ReviewerCode = doctor.ReviewerCode,
                                              FirstName = doctor.FirstName,
                                              LastName = doctor.LastName,
                                              ChineseName = doctor.ChineseName
                                          };

            return await costAdjustmentQueryable.ToPagedListAsync(queryParam.PageIndex, queryParam.PageSize, string.IsNullOrWhiteSpace(queryParam.SortField) ? "YearMonthDate" : queryParam.SortField, queryParam.Asc);


        }

        public async Task<List<DoctorSelectDTO>> GetReviewerSelectList()
        {
            return await _doctorRepository.Where(t => t.CooperateStatus == ContractorStatusEnum.Cooperation && t.ResumeStatus == ResumeStatusEnum.Pass).ProjectTo<DoctorSelectDTO>(_mapper.ConfigurationProvider).ToListAsync();
        }

        [NonDynamicMethod]
        public async Task CalculateCNY(string yearMonth, decimal rate)
        {

            //如果是double 不会保留两位小数
            await _payAdjustmentRepository.BatchUpdateNoTrackingAsync(u => u.YearMonth == yearMonth &&
            !u.IsLock, t => new PaymentAdjustment
            {
                AdjustmentCNY = t.AdjustmentUSD * rate,
                ExchangeRate = rate,
                UpdateTime = DateTime.Now
            });

            var adjustList = await _payAdjustmentRepository.Where(u => u.YearMonth == yearMonth &&
                                                           !u.IsLock).ToListAsync();



            var needUpdatePayment = adjustList.GroupBy(t => t.ReviewerId).Select(g => new
            {
                ReviewerId = g.Key,
                AdjustCNY = g.Sum(t => t.AdjustmentCNY),
                AdjustUSD = g.Sum(t => t.AdjustmentUSD)
            });

            foreach (var reviewer in needUpdatePayment)
            {
                await _paymentRepository.BatchUpdateNoTrackingAsync(u => u.YearMonth == yearMonth &&
                                                !u.IsLock && u.DoctorId == reviewer.ReviewerId, t => new Payment()
                                                {
                                                    AdjustmentUSD = reviewer.AdjustUSD,
                                                    AdjustmentCNY = reviewer.AdjustCNY

                                                });
            }


        }
    }
}