package com.jeequan.jeepay.thirdparty.channel;

import cn.hutool.core.date.DateField;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.entity.AccountOperate;
import com.jeequan.jeepay.core.entity.TransferOrder;
import com.jeequan.jeepay.core.entity.TransferWallet;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.core.interfaces.paychannel.ITransferService;
import com.jeequan.jeepay.core.model.rqrs.transfer.TransferOrderRQ;
import com.jeequan.jeepay.core.model.tranfer.TransferBasicInfo;
import com.jeequan.jeepay.core.utils.AmountUtil;
import com.jeequan.jeepay.db.entity.AccountFundInfo;
import com.jeequan.jeepay.db.entity.AccountInfo;
import com.jeequan.jeepay.db.entity.TransferSubjectEntity;
import com.jeequan.jeepay.db.entity.TransferWalletEntity;
import com.jeequan.jeepay.service.impl.*;
import org.apache.commons.lang3.tuple.MutablePair;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.Date;

/**
 * 支付接口抽象类
 *
 * @author terrfly
 *
 * @since 2021/6/8 17:18
 */
public abstract class AbstractTransferService implements ITransferService {

    @Autowired protected TransferOrderService transferOrderService;

    @Autowired protected TransferWalletService transferWalletService;

    @Autowired protected TransferSubjectService transferSubjectService;

    @Autowired protected SysConfigService sysConfigService;

    @Autowired protected AccountInfoService accountInfoService;

    protected String getPaySiteUrl() {
        return sysConfigService.getDBApplicationConfig().getPaySiteUrl();
    }

    protected String getNotifyUrl(){
        return getPaySiteUrl() + "/api/transfer/notify/" + getIfCode();
    }

    protected String getNotifyUrl(String payOrderId){
        return getPaySiteUrl() + "/api/transfer/notify/" + getIfCode() + "/" + payOrderId;
    }

    @Override
    public MutablePair<String, Long> queryBalanceAmount(TransferWallet transferWallet) {;
        return MutablePair.of(null, null);
    }

    @Override
    public String preCheck(TransferOrderRQ bizRQ, TransferOrder transferOrder) {
        commonCheck(bizRQ, transferOrder);

        return "";
    }

    @Override
    public void commonCheck(TransferOrderRQ bizRQ, TransferOrder transferOrder) {
        checkAmountLimit(bizRQ, transferOrder);
        checkRateAccountFee(bizRQ, transferOrder);
    }

    /**
     * 交易限额的校验
     */
    protected final void checkAmountLimit(TransferOrderRQ bizRQ, TransferOrder transferOrder) {
        String transferSubjectIdFq = transferOrder.getTransferSubjectIdFq();
        TransferWalletEntity transferWallet = transferWalletService.getByApplyId(transferSubjectIdFq, null);

        Long monthLimit;
        Long dayLimit;

        String transferTypeName;
        switch (transferOrder.getEntryType()) {
            case TransferOrder.ENTRY_BANK_CARD:
                if (transferOrder.getAccountType().equals(TransferBasicInfo.ACCOUNT_TYPE_COR)) {
                    transferTypeName = "对公账户";
                    // 对公
                    if (transferOrder.getAmount() > transferWallet.getBankCardCorOnceMax()) {
                        throw new BizException("转账单笔超限额[" + AmountUtil.convertCent2Dollar(transferWallet.getBankCardCorOnceMax()) + "]");
                    }
                } else {
                    transferTypeName = "个人银行卡";
                    // 对私
                    if (transferOrder.getAmount() > transferWallet.getBankCardPriOnceMax()) {
                        throw new BizException("转账个人银行卡单笔超限额[" + AmountUtil.convertCent2Dollar(transferWallet.getBankCardPriOnceMax()) + "]");
                    }
                }

                monthLimit = transferWallet.getBankCardMonthMax();
                dayLimit = transferWallet.getBankCardDayMax();
                break;
            case TransferOrder.ENTRY_WX_CASH:
                if (transferOrder.getAccountType().equals(TransferBasicInfo.ACCOUNT_TYPE_COR)) {
                    transferTypeName = "企业微信";
                    // 企业微信
                    if (transferOrder.getAmount() > transferWallet.getWxCorOnceMax()) {
                        throw new BizException("转账企业微信单笔超限额[" + AmountUtil.convertCent2Dollar(transferWallet.getWxCorOnceMax()) + "]");
                    }
                } else {
                    transferTypeName = "个人微信";
                    // 对私
                    if (transferOrder.getAmount() > transferWallet.getWxPriOnceMax()) {
                        throw new BizException("转账个人微信单笔超限额[" + AmountUtil.convertCent2Dollar(transferWallet.getWxPriOnceMax()) + "]");
                    }
                }

                monthLimit = transferWallet.getWxMonthMax();
                dayLimit = transferWallet.getWxDayMax();
                break;
            case TransferOrder.ENTRY_ALIPAY_CASH:
                if (transferOrder.getAccountType().equals(TransferBasicInfo.ACCOUNT_TYPE_COR)) {
                    transferTypeName = "企业支付宝";
                    // 对公
                    if (transferOrder.getAmount() > transferWallet.getZfbCorOnceMax()) {
                        throw new BizException("转账企业支付宝单笔超限额[" + AmountUtil.convertCent2Dollar(transferWallet.getZfbCorOnceMax()) + "]");
                    }
                } else {
                    transferTypeName = "个人支付宝";
                    // 对私
                    if (transferOrder.getAmount() > transferWallet.getZfbPriOnceMax()) {
                        throw new BizException("转账个人支付宝单笔超限额[" + AmountUtil.convertCent2Dollar(transferWallet.getZfbPriOnceMax()) + "]");
                    }
                }

                monthLimit = transferWallet.getZfbMonthMax();
                dayLimit = transferWallet.getZfbDayMax();
                break;
            default:
                throw new BizException("未知的打款方式");
        }

        Date current = new Date();
        Long accumulatedMonth = transferOrderService.accumulated(DateField.MONTH, current,
                TransferOrder.TRANSFER_TYPE_OUT, transferOrder.getEntryType(), transferSubjectIdFq,
                TransferOrder.STATE_INIT, TransferOrder.STATE_ING, TransferOrder.STATE_SUCCESS);

        if (accumulatedMonth + transferOrder.getAmount() > monthLimit) {;
            throw new BizException("操作失败，转账" + transferTypeName + "已达到月限额[" + monthLimit + "]");
        }

        Long accumulatedDay = transferOrderService.accumulated(DateField.DAY_OF_YEAR, current,
                TransferOrder.TRANSFER_TYPE_OUT, transferOrder.getEntryType(), transferSubjectIdFq,
                TransferOrder.STATE_INIT, TransferOrder.STATE_ING, TransferOrder.STATE_SUCCESS);

        if (accumulatedDay + transferOrder.getAmount() > dayLimit) {
            throw new BizException("操作失败，转账" + transferTypeName + "已达到日限额[" + dayLimit + "]");
        }
    }

    /**
     * 手续费校验
     */
    protected final void checkRateAccountFee(TransferOrderRQ bizRQ, TransferOrder transferOrder) {
        // 手续费外扣，需要校验余额
        if (transferOrder.getFeeCostType().equals(TransferOrder.COST_TYPE_ACCOUNT)) {
            // 校验余额，
            TransferSubjectEntity transferSubject = transferSubjectService.getById(transferOrder.getTransferSubjectIdFq());
            String infoId;
            if (transferSubject.getInfoType().equals(CS.SYS_ROLE_TYPE.MCH)) {
                infoId = transferSubject.getMchNo();
            } else {
                infoId = transferSubject.getAgentNo();
            }

            AccountInfo accountInfo = accountInfoService.getAccountInfo(infoId, AccountInfo.Type.SERVICE_CHARGE.getType());
            if (accountInfo.getBalacne() < transferOrder.getMchOrderFeeAmount()) {
                throw new BizException("当前手续费余额不足");
            }

            // 预扣手续费
            AccountOperate accountOperate = new AccountOperate(accountInfo.getAccountNo(), transferOrder.getAmount(),
                    AccountFundInfo.ChangeType.TRANSFER.getValue(), AccountFundInfo.ChangeMethod.DF.getValue(),
                    transferOrder.getTransferId(), "代付手续费");
            accountOperate.setFinalAmt(transferOrder.getMchOrderFeeAmount());
            accountOperate.setIsUpdateAccount(true);
            accountInfoService.upAccount(accountOperate);
        }
    }
}
