package com.cku.oa.finance.service;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import com.cku.core.ZAErrorCode;
import com.cku.core.ZAException;
import com.cku.oa.finance.dao.PaymentOrderRefundDao;
import com.cku.oa.finance.dao.SaPaymentDetailTotalDao;
import com.cku.oa.finance.entity.PaymentOrder;
import com.cku.oa.finance.entity.PaymentOrderDetail;
import com.cku.oa.finance.entity.PaymentOrderRefund;
import com.cku.oa.finance.entity.PaymentRecord;
import com.cku.oa.finance.entity.SaPaymentDetailTotal;
import com.cku.oa.statistics.service.SplitOrderService;
import com.cku.oa.sys.code.SysCodeUtil;
import com.cku.oa.sys.service.user.MemberService;
import com.thinkgem.jeesite.common.persistence.Page;
import com.thinkgem.jeesite.common.service.CrudService;
import com.thinkgem.jeesite.common.utils.StringUtils;
import com.thinkgem.jeesite.modules.sys.utils.UserUtils;

import io.netty.util.internal.StringUtil;

/**
 * 退费记录Service
 * 
 * @author Sunny
 * @version 2021-06-17
 */
@Service
@Transactional(readOnly = true)
public class PaymentOrderRefundService extends CrudService<PaymentOrderRefundDao, PaymentOrderRefund> {

	@Autowired
	private PaymentOrderService paymentOrderService;
	@Autowired
	private PaymentRecordService paymentRecordService;
	@Autowired
	private MemberService memberService;
	@Autowired
	private SplitOrderService splitOrderService;
	@Autowired
	private SaPaymentDetailTotalDao saPaymentDetailTotalDao;

	public PaymentOrderRefund get(String id) {
		return super.get(id);
	}

	public List<PaymentOrderRefund> findList(PaymentOrderRefund paymentOrderRefund) {
		return super.findList(paymentOrderRefund);
	}

	public Page<PaymentOrderRefund> findPage(Page<PaymentOrderRefund> page, PaymentOrderRefund paymentOrderRefund) {
		return super.findPage(page, paymentOrderRefund);
	}

	@Transactional(readOnly = false)
	public void update(PaymentOrderRefund paymentOrderRefund) {
		PaymentOrderRefund entity = this.get(paymentOrderRefund.getId());
		if (Objects.isNull(entity)) {
			throw new ZAException(ZAErrorCode.ZA_ERC_UNKNOWN, "修改记录不存在，请刷新后重试");
		}
		if (!"0".equals(entity.getProcessState())) {
			throw new ZAException(ZAErrorCode.ZA_ERC_UNKNOWN, "已处理的记录不允许修改");
		}
		if (paymentOrderRefund.getPartRefundFlag()) {
			if (new BigDecimal(paymentOrderRefund.getTotalPrice())
					.compareTo(new BigDecimal(paymentOrderRefund.getPartRefundPrice())) < 0) {
				throw new ZAException(ZAErrorCode.ZA_ERROR, "实际退费金额不能大于原订单金额");
			} else if (BigDecimal.ZERO.compareTo(new BigDecimal(paymentOrderRefund.getPartRefundPrice())) >= 0) {
				throw new ZAException(ZAErrorCode.ZA_ERROR, "实际退费金额不能小于0");
			}
		}
		entity.setChargingItemId(paymentOrderRefund.getChargingItemId());
		entity.setChargingItemName(paymentOrderRefund.getChargingItemName());
		entity.setPartRefundFlag(paymentOrderRefund.getPartRefundFlag());
		entity.setPartRefundPrice(paymentOrderRefund.getPartRefundPrice());
		entity.setRefundRemark(paymentOrderRefund.getRefundRemark());
		entity.preUpdate();
		super.save(entity);
	}

	@Transactional(readOnly = false)
	public void saveBatch(List<PaymentOrderRefund> paymentOrderRefunds) {
		paymentOrderRefunds.forEach(refund -> {
			// 1、保存时业务校验
			if (StringUtil.isNullOrEmpty(refund.getOrderCode())) {
				throw new ZAException(ZAErrorCode.ZA_ERC_UNKNOWN, "订单号不能为空");
			}
			PaymentOrder order = paymentOrderService.getByOrderCode(refund.getOrderCode());
			if (Objects.isNull(order) || StringUtils.isBlank(order.getId())) {
				throw new ZAException(ZAErrorCode.ZA_ERC_UNKNOWN, "订单号不能为空");
			}
			if (Objects.isNull(refund.getChargingItemId()) || StringUtils.isBlank(refund.getChargingItemId())) {
				throw new ZAException(ZAErrorCode.ZA_ERC_UNKNOWN, "订单：" + order.getOrderCode() + "退费项目不能为空");
			}
			List<PaymentOrderDetail> orderDetailList = paymentOrderService
					.findOrderDetailByOrderCode(order.getOrderCode());
			checkRefund(order, orderDetailList);
			BigDecimal totalPrice = new BigDecimal(order.getTotalPrice());
			BigDecimal adjustedTotalPrice = new BigDecimal(order.getTotalPrice());
			if (refund.getPartRefundFlag() && refund.getPartRefundPrice() != null) {
				adjustedTotalPrice = new BigDecimal(refund.getPartRefundPrice());
			}
			if (totalPrice.compareTo(adjustedTotalPrice) < 0) {
				throw new ZAException(ZAErrorCode.ZA_ERROR, "订单：" + order.getOrderCode() + "实际退费金额不能大于原订单金额");
			} else if (BigDecimal.ZERO.compareTo(adjustedTotalPrice) >= 0) {
				throw new ZAException(ZAErrorCode.ZA_ERROR, "订单：" + order.getOrderCode() + "实际退费金额不能小于0");
			}
			refund.preInsert();
			refund.setReviewState("0");
			refund.setProcessState("0");
		});

		int row = this.dao.insertBatch(paymentOrderRefunds);
		if (row != paymentOrderRefunds.size()) {
			throw new ZAException(ZAErrorCode.ZA_ERROR, "保存失败！");
		}
	}

	/**
	 * 退款申请
	 *
	 * @author yuanshuai
	 * @date 2021/5/21 15:51
	 */
	@Transactional(readOnly = false)
	public void applyRefund(List<String> refundOrderIds) {
		List<PaymentOrderRefund> refundList = this.dao.findByIds(refundOrderIds);
		if (CollectionUtils.isEmpty(refundList)) {
			throw new ZAException(ZAErrorCode.ZA_ERC_UNKNOWN, "退款单记录不存在，请刷新后重试！");
		}

		if (refundList.stream().filter(refund -> !"0".equals(refund.getProcessState())).count() > 0) {
			throw new ZAException(ZAErrorCode.ZA_ERC_UNKNOWN, "存在已退款的单据记录，请刷新后重试！");
		}
		refundList.forEach(refund -> {
			PaymentOrder order = paymentOrderService.getByOrderCode(refund.getOrderCode());
			if (Objects.isNull(order) || StringUtils.isBlank(order.getId())) {
				throw new ZAException(ZAErrorCode.ZA_ERC_UNKNOWN, "订单" + refund.getOrderCode() + "单据不存在，请确认后重试！");
			}
			List<PaymentOrderDetail> orderDetailList = paymentOrderService
					.findOrderDetailByOrderCode(order.getOrderCode());
			checkRefund(order, orderDetailList);
			// 处理对冲订单 按补扣费用退费处理
			BigDecimal totalPrice = new BigDecimal(order.getTotalPrice());
			BigDecimal adjustedTotalPrice = new BigDecimal(order.getTotalPrice());
			if (refund.getPartRefundFlag() && refund.getPartRefundPrice() != null) {
				adjustedTotalPrice = new BigDecimal(refund.getPartRefundPrice());
			}
			if (totalPrice.compareTo(adjustedTotalPrice) < 0) {
				throw new ZAException(ZAErrorCode.ZA_ERROR, "订单：" + order.getOrderCode() + "实际退费金额不能大于原订单金额");
			} else if (BigDecimal.ZERO.compareTo(adjustedTotalPrice) >= 0) {
				throw new ZAException(ZAErrorCode.ZA_ERROR, "订单：" + order.getOrderCode() + "实际退费金额不能小于0");
			}
			// 保存流水
			PaymentRecord record = new PaymentRecord();
			String runningNumber = SysCodeUtil.getPayRunningNumber();
			record.setRunningNumber(runningNumber);
			record.setMemberCode(order.getMemberCode());
			record.setChargingItemId(refund.getChargingItemId());
			record.setChargingItemNum(1);
			record.setCreateDate(new Date());
			record.setPaymentTime(new Date());
			record.setPaymentState("2");
			// 默认余额支付
			record.setPaymentWay("25");
			record.setPrice(BigDecimal.ZERO.subtract(adjustedTotalPrice).toString());
			record.setPaymentAmount(BigDecimal.ZERO.subtract(adjustedTotalPrice).toString());
			record.setPaymentWay("cku.org");
			record.setPaymentRemarks(refund.getRefundRemark());
			record.setRemarks(refund.getRefundRemark());
			paymentRecordService.save(record);
			// 修改余额
			memberService.memberRecharge(order.getMemberCode(), adjustedTotalPrice.toString(), record.getPaymentTime(),
					record.getRunningNumber());
			// 拆分项 不处理业务表，赛事不处理30手续费
			splitOrderService.initSplit(record.getRunningNumber());
			List<SaPaymentDetailTotal> saPaymentDetailTotalList = saPaymentDetailTotalDao
					.getByRunningNumber(runningNumber);
			saPaymentDetailTotalList.forEach(total -> {
				total.setOldRunningNumber(order.getOrderCode());
				total.setOrderStates("2");
				total.preUpdate();
				saPaymentDetailTotalDao.update(total);
			});

			PaymentOrderRefund entity = new PaymentOrderRefund();
			entity.setId(refund.getId());
			entity.setRefundOrderCode(runningNumber);
			entity.setProcessState("1");
			entity.setProcessPerson(UserUtils.getUser().getId());
			entity.setProcessTime(new Date());
			entity.preUpdate();
			this.dao.updateProcess(entity);
		});

	}

	@Transactional(readOnly = false)
	public void delete(PaymentOrderRefund paymentOrderRefund) {
		super.delete(paymentOrderRefund);
	}

	/**
	 * 校验是否存在相同订单的提交记录
	 * 
	 * @param orderCodes
	 */
	public void checkRefundRecord(List<String> orderCodes) {
		List<PaymentOrderRefund> entityList = this.dao.findByOrderCodes(orderCodes);
		if (!CollectionUtils.isEmpty(entityList)) {
			throw new ZAException(ZAErrorCode.ZA_ERC_UNKNOWN, "已存在订单："
					+ entityList.stream().map(PaymentOrderRefund::getOrderCode).collect(Collectors.joining(","))
					+ "的申请记录，请勿重复申请！");
		}
	}

	/**
	 * 校验是否可以退款
	 *
	 * @author yuanshuai
	 * @date 2021/5/21 15:40
	 */
	public void checkRefund(PaymentOrder order, List<PaymentOrderDetail> orderDetailList) {
		if (!"2".equals(order.getPaymentState())) {
			throw new ZAException(ZAErrorCode.ZA_ERC_UNKNOWN, "订单：" + order.getOrderCode() + "未付款的订单不能申请退款");
		}
		if (!"0".equals(order.getDelFlag())) {
			throw new ZAException(ZAErrorCode.ZA_ERC_UNKNOWN, "订单：" + order.getOrderCode() + "该订单已删除，无法申请退款");
		}
		if (orderDetailList.stream().anyMatch(i -> !StringUtil.isNullOrEmpty(i.getBusinessRefundState()))) {
			throw new ZAException(ZAErrorCode.ZA_ERC_UNKNOWN, "订单：" + order.getOrderCode() + "该订单已申请退款,请勿重新申请");
		}
		if (BigDecimal.ZERO.compareTo(new BigDecimal(order.getTotalPrice())) == 0) {
			throw new ZAException(ZAErrorCode.ZA_ERC_UNKNOWN, "订单：" + order.getOrderCode() + "0元订单无需退款,请勿重新申请");
		}
	}

	public boolean validOrderIsRefundingOrRefunded(String orderCode) {
		if (StringUtils.isEmpty(orderCode)) {
			return Boolean.FALSE;
		}
		List<PaymentOrderDetail> orderDetailList = paymentOrderService.findOrderDetailByOrderCode(orderCode);
		if (!CollectionUtils.isEmpty(orderDetailList)
				&& orderDetailList.stream().anyMatch(i -> StringUtils.isNotEmpty(i.getBusinessRefundState())
						&& ("1".equals(i.getBusinessRefundState()) || "3".equals(i.getBusinessRefundState())))) {
			return Boolean.TRUE;
		}
		return Boolean.FALSE;
	}

}