package com.jeequan.jeepay.pay.task;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Pair;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.entity.MchInfo;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.core.interfaces.IConfigContextQueryService;
import com.jeequan.jeepay.core.interfaces.paychannel.IChannelAccountService;
import com.jeequan.jeepay.core.model.cashout.CashoutParams;
import com.jeequan.jeepay.core.model.cashout.CashoutRetMsg;
import com.jeequan.jeepay.core.model.context.MchAppConfigContext;
import com.jeequan.jeepay.core.utils.JeepayKit;
import com.jeequan.jeepay.core.utils.SeqKit;
import com.jeequan.jeepay.core.utils.SpringBeansUtil;
import com.jeequan.jeepay.db.entity.ChannelAccountCashoutRecord;
import com.jeequan.jeepay.db.entity.PayInterfaceConfig;
import com.jeequan.jeepay.db.entity.PayInterfaceDefine;
import com.jeequan.jeepay.pay.service.MchChannelCashoutService;
import com.jeequan.jeepay.service.impl.ChannelAccountCashoutRecordService;
import com.jeequan.jeepay.service.impl.PayInterfaceConfigService;
import com.jeequan.jeepay.service.impl.PayInterfaceDefineService;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.stream.Collectors;

/**
* 商户渠道自动提现 定时任务
*
* @author zx
*
* @date 2022/2/14 10:47
*/
@Slf4j
@Component
public class MchChannelCashoutTask {

    private static final int QUERY_PAGE_SIZE = 50; // 每次执行数量

    @Autowired private PayInterfaceDefineService payInterfaceDefineService;
    @Autowired private PayInterfaceConfigService payInterfaceConfigService;
    @Autowired private ChannelAccountCashoutRecordService cashoutRecordService;
    @Autowired private IConfigContextQueryService configContextQueryService;
    @Autowired private MchChannelCashoutService mchChannelCashoutService;

    @XxlJob("mchAutoCashoutTaskHandler")
    public void start() {

        String logPrefix = "【处理三方账户自动提现任务】";
        log.info("开始{}", logPrefix);

        // 查询条件：启用状态 && 支持提现 && 开启提现
        List<PayInterfaceDefine> ifDefines = payInterfaceDefineService.list(PayInterfaceDefine.gw()
                .eq(PayInterfaceDefine::getState, CS.YES)
                .eq(PayInterfaceDefine::getIsSupportCashout, CS.YES)
                .eq(PayInterfaceDefine::getIsOpenCashout, CS.YES)
        );
        if (CollUtil.isEmpty(ifDefines)) {
            log.info("{}，无可提现接口", logPrefix);
            return;
        }
        List<String> ifCodeList = ifDefines.stream().map(PayInterfaceDefine::getIfCode).collect(Collectors.toList());

        // 查询条件：启用状态 && 支持提现的支付接口
        LambdaQueryWrapper<PayInterfaceConfig> lambdaQueryWrapper = PayInterfaceConfig.gw()
                .eq(PayInterfaceConfig::getState, CS.YES)
                .eq(PayInterfaceConfig::getInfoType, CS.SYS_ROLE_TYPE.MCH_APP)
                .in(PayInterfaceConfig::getIfCode, ifCodeList);

        int currentPageIndex = 1; //当前页码
        while(true){

            try {
                IPage<PayInterfaceConfig> page = payInterfaceConfigService.page(new Page(currentPageIndex, QUERY_PAGE_SIZE), lambdaQueryWrapper);
                if(page == null || page.getRecords().isEmpty()){ //本次查询无结果, 不再继续查询;
                    break;
                }
                currentPageIndex++;

                for(PayInterfaceConfig interfaceConfig: page.getRecords()){
                    log.info("\n开始处理支付接口：{}, 应用appId：{}，提现任务", interfaceConfig.getIfCode(), interfaceConfig.getInfoId());

                    try {
                        // 查询结算接口是否存在
                        IChannelAccountService channelAccountService = SpringBeansUtil.getBean(JeepayKit.getIfCodeOrigin(interfaceConfig.getIfCode()) + "ChannelAccountService", IChannelAccountService.class);
                        // 提现接口实现不存在

                        MchAppConfigContext mchAppConfigContext = configContextQueryService.queryMchInfoAndAppInfo(interfaceConfig.getInfoId());

                        cashoutSaveRecord(channelAccountService, interfaceConfig, mchAppConfigContext);

                        log.info("\n完成处理支付接口：{}, 应用appId：{}，提现任务", interfaceConfig.getIfCode(), interfaceConfig.getInfoId());
                    }catch (BizException e) {
                        log.error("\n定时提现任务异常，支付接口：{},，应用appId：{}，异常信息：{}", interfaceConfig.getIfCode(), interfaceConfig.getInfoId(), e.getMessage()); // 内存异常，打印错误，继续执行
                    }
                }

                //已经到达页码最大量，无需再次查询
                if(page.getPages() < currentPageIndex){
                    break;
                }
            } catch (Exception e) {
                log.error("error", e); // 外层异常，直接退出
                break;
            }

        }
        log.info("完成{}", logPrefix);
    }

    private void cashoutSaveRecord(IChannelAccountService channelAccountService, PayInterfaceConfig mchAppIfConfig, MchAppConfigContext mchAppConfigContext) {

        String ifCode = mchAppIfConfig.getIfCode();
        MchInfo mchInfo = mchAppConfigContext.getMchInfo();

        // 校验提现配置
        CashoutParams cashoutParams = mchChannelCashoutService.checkCashoutJudge(ifCode, mchAppConfigContext.getMchApplyment().getIsvNo(), mchAppConfigContext.getAppId(), ChannelAccountCashoutRecord.CASHOUT_FROM_TASK);

        // 查询余额
        Pair<String, Long> pair = channelAccountService.queryBalanceAmount(mchAppConfigContext, ifCode);
        if (pair.getValue() <= 0) {
            log.info("查询余额为0，不再发起提现，ifCode={}，mchNo={}，appId={}", ifCode, mchInfo.getMchNo(), mchAppConfigContext.getAppId());
            return;
        }

        // 校验提现金额
        Long cashoutAmount = mchChannelCashoutService.checkCashoutAmount(pair.getValue(), cashoutParams, mchAppConfigContext.getAppId());

        // 提现记录入库
        ChannelAccountCashoutRecord cashoutRecord = cashoutRecordService.initRecord(SeqKit.genCashoutRecordId(), cashoutAmount, pair.getValue(), mchAppConfigContext.getMchNo(), mchAppConfigContext.getMchInfo().getMchName(),
                mchAppConfigContext.getAppId(), mchAppConfigContext.getMchApplyment().getIsvNo(), ifCode, pair.getKey(), null, null, null);

        // 提现
        CashoutRetMsg cashoutRetMsg = channelAccountService.cashout(cashoutRecord, mchAppConfigContext, ifCode);

        mchChannelCashoutService.processChannelMsg(cashoutRetMsg, cashoutRecord.getRid());
    }

}
