package com.jeequan.jeepay.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.DesensitizedUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.entity.AccountOperate;
import com.jeequan.jeepay.core.model.ApiRes;
import com.jeequan.jeepay.db.entity.*;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.service.mapper.PayOrderMapper;
import com.jeequan.jeepay.service.mapper.RefundOrderMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.MutablePair;
import org.apache.commons.lang3.tuple.MutableTriple;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 退款订单表 服务实现类
 * </p>
 *
 * @author [mybatis plus generator]
 * @since 2021-04-27
 */
@Service
@Slf4j
public class RefundOrderService extends ServiceImpl<RefundOrderMapper, RefundOrder> {

    @Autowired private PayOrderMapper payOrderMapper;
    @Autowired private OrderProfitSettRecordService orderProfitSettRecordService;
    @Autowired private MchAppService mchAppService;
    @Autowired private PayInterfaceDefineService payInterfaceDefineService;
    @Autowired private IsvInfoService isvInfoService;
    @Autowired private RefundOrderService refundOrderService;
    @Autowired private AgentInfoService agentInfoService;
    @Autowired private AccountInfoService accountInfoService;
    @Autowired private MchInfoService mchInfoService;
    @Autowired private AccountInfoService accountService;

    /** 查询商户订单 **/
    public RefundOrder queryMchOrder(String mchNo, String mchRefundNo, String refundOrderId){

        if(StringUtils.isNotEmpty(refundOrderId)){
            return getOne(RefundOrder.gw().eq(RefundOrder::getMchNo, mchNo).eq(RefundOrder::getRefundOrderId, refundOrderId));
        }else if(StringUtils.isNotEmpty(mchRefundNo)){
            return getOne(RefundOrder.gw().eq(RefundOrder::getMchNo, mchNo).eq(RefundOrder::getMchRefundNo, mchRefundNo));
        }else{
            return null;
        }
    }


    /** 更新退款单状态  【退款单生成】 --》 【退款中】 **/
    public boolean updateInit2Ing(String refundOrderId, String channelOrderNo){

        RefundOrder updateRecord = new RefundOrder();
        updateRecord.setState(RefundOrder.STATE_ING);
        updateRecord.setChannelOrderNo(channelOrderNo);

        //更新订单表状态也为退款中
        RefundOrder refundOrder = refundOrderService.getById(refundOrderId);
        PayOrder payOrder = payOrderMapper.selectById(refundOrder.getPayOrderId());
        if (payOrder != null){
            payOrder.setState(PayOrder.STATE_REFUNDING);
            payOrderMapper.updateById(payOrder);

        }
        //扣除账户余额
        if(RefundOrder.REFUND_ACCOUNT_PLAT.equals(refundOrder.getExtParam())){
            AccountInfo account = accountInfoService.getAccountInfo(refundOrder.getMchNo(), AccountInfo.Type.REFUND.getType());
            AccountOperate operate = new AccountOperate(account.getAccountNo(),refundOrder.getRefundAmount(),AccountFundInfo.ChangeType.REFUND.getValue(), AccountFundInfo.ChangeMethod.YBH_REFUND.getValue(), refundOrder.getRefundOrderId(),"一般户退款");
            operate.setState(AccountFundInfo.SUCCESS);
            operate.setIsUpdateAccount(true);
            accountInfoService.upAccount(operate);
        }
        return update(updateRecord, new LambdaUpdateWrapper<RefundOrder>()
                .eq(RefundOrder::getRefundOrderId, refundOrderId).eq(RefundOrder::getState, RefundOrder.STATE_INIT));
    }

    /** 更新退款单状态  【退款中】 --》 【退款成功】 **/
    @Transactional
    public boolean updateIng2Success(String refundOrderId, String channelOrderNo){

        RefundOrder updateRecord = new RefundOrder();
        updateRecord.setState(RefundOrder.STATE_SUCCESS);
        updateRecord.setChannelOrderNo(channelOrderNo);
        updateRecord.setSuccessTime(new Date());

        //1. 更新退款订单表数据
        if(! update(updateRecord, new LambdaUpdateWrapper<RefundOrder>()
                .eq(RefundOrder::getRefundOrderId, refundOrderId).eq(RefundOrder::getState, RefundOrder.STATE_ING))
        ){
            return false;
        }

        //2. 更新订单表数据（更新退款次数,退款状态,如全额退款更新支付状态为已退款）
        RefundOrder refundOrder = getOne(RefundOrder.gw().select(RefundOrder::getPayOrderId, RefundOrder::getRefundAmount,RefundOrder::getIfCode,RefundOrder::getMchNo).eq(RefundOrder::getRefundOrderId, refundOrderId));
        int updateCount = payOrderMapper.updateRefundAmountAndCount(refundOrder.getPayOrderId(), refundOrder.getRefundAmount());
        if(updateCount <= 0){
            throw new BizException("更新订单数据异常");
        }
        // 3. 退款退佣  MutableTriple<手续费快照, 商户实际手续费, 本次退还手续费>
        MutableTriple<String, Long, Long> calFeeAndSnapshot = orderProfitSettRecordService.insertProfitByRefundOrder(refundOrderId);
        if(calFeeAndSnapshot != null){

            // 更新到订单
            PayOrder updateRateRecord = new PayOrder().setPayOrderId(refundOrder.getPayOrderId()).setMchFeeAmount(calFeeAndSnapshot.middle).setMchFeeRate(calFeeAndSnapshot.left);
            payOrderMapper.updateById(updateRateRecord);

            // 更新到退款订单
            RefundOrder refundOrder2 = new RefundOrder().setRefundOrderId(refundOrderId).setRefundFeeAmount(calFeeAndSnapshot.right);
            this.updateById(refundOrder2);

            if(CS.IF_CODE.ZFTPAY.equals(refundOrder.getIfCode())){
                //直付通退款 追加手续费
                try {
                    AccountInfo account = accountService.getAccountInfo(refundOrder.getMchNo(), AccountInfo.Type.SERVICE_CHARGE.getType());
                    if(account != null){
                        AccountOperate operate = new AccountOperate(account.getAccountNo(),refundOrder.getRefundAmount(),AccountFundInfo.ChangeType.REFUND.getValue(),AccountFundInfo.ChangeMethod.ZFT.getValue(),refundOrderId,"直付通退款返还手续费");
                        operate.setIsUpdateAccount(true);
                        operate.setFinalAmt(calFeeAndSnapshot.right == BigDecimal.ZERO.longValue() ? calFeeAndSnapshot.middle : calFeeAndSnapshot.right);
                        accountService.upAccount(operate);
                    }
                }catch (Exception e){
                    log.error("直付通退款返还手续费异常,订单号:{}，异常信息:{}",refundOrderId,e.getMessage());
                }
            }
        }

        return true;
    }


    /** 更新退款单状态  【退款中】 --》 【退款失败】 **/
    @Transactional
    public boolean updateIng2Fail(String refundOrderId, String channelOrderNo, String channelErrCode, String channelErrMsg){

        RefundOrder updateRecord = new RefundOrder();
        updateRecord.setState(RefundOrder.STATE_FAIL);
        updateRecord.setErrCode(channelErrCode);
        updateRecord.setErrMsg(channelErrMsg);
        updateRecord.setChannelOrderNo(channelOrderNo);

        return update(updateRecord, new LambdaUpdateWrapper<RefundOrder>()
                .eq(RefundOrder::getRefundOrderId, refundOrderId).eq(RefundOrder::getState, RefundOrder.STATE_ING));
    }


    /** 更新退款单状态  【退款中】 --》 【退款成功/退款失败】 **/
    @Transactional
    public boolean updateIng2SuccessOrFail(String refundOrderId, Byte updateState, String channelOrderNo, String channelErrCode, String channelErrMsg){

        if(updateState == RefundOrder.STATE_ING){
            return true;
        }else if(updateState == RefundOrder.STATE_SUCCESS){
            return updateIng2Success(refundOrderId, channelOrderNo);
        }else if(updateState == RefundOrder.STATE_FAIL){
            return updateIng2Fail(refundOrderId, channelOrderNo, channelErrCode, channelErrMsg);
        }
        return false;
    }


    /** 更新退款单为 关闭状态 **/
    public Integer updateOrderExpired(){

        RefundOrder refundOrder = new RefundOrder();
        refundOrder.setState(RefundOrder.STATE_CLOSED);

        return baseMapper.update(refundOrder,
                RefundOrder.gw()
                        .in(RefundOrder::getState, Arrays.asList(RefundOrder.STATE_INIT, RefundOrder.STATE_ING))
                        .le(RefundOrder::getExpiredTime, new Date())
        );
    }

    /** 更新退款单状态  【退款关闭】 --》 【退款中】 **/
    public boolean updateClose2Ing(String refundOrderId) {
        RefundOrder refundOrder = new RefundOrder();
        refundOrder.setState(RefundOrder.STATE_CLOSED);

        return update(refundOrder, new LambdaUpdateWrapper<RefundOrder>()
                        .eq(RefundOrder::getRefundOrderId, refundOrderId)
                        .in(RefundOrder::getState, Arrays.asList(RefundOrder.STATE_INIT, RefundOrder.STATE_ING))
                        .le(RefundOrder::getExpiredTime, new Date())
        );
    }


    public IPage<RefundOrder> pageList(IPage iPage, LambdaQueryWrapper<RefundOrder> wrapper, RefundOrder refundOrder, JSONObject paramJSON) {
        wrapper.eq(StringUtils.isNotEmpty(refundOrder.getRefundOrderId()), RefundOrder::getRefundOrderId, refundOrder.getRefundOrderId());
        wrapper.eq(StringUtils.isNotEmpty(refundOrder.getPayOrderId()), RefundOrder::getPayOrderId, refundOrder.getPayOrderId());
        wrapper.eq(StringUtils.isNotEmpty(refundOrder.getChannelPayOrderNo()), RefundOrder::getChannelPayOrderNo, refundOrder.getChannelPayOrderNo());
        wrapper.eq(StringUtils.isNotEmpty(refundOrder.getMchNo()), RefundOrder::getMchNo, refundOrder.getMchNo());
        //wrapper.eq(StringUtils.isNotEmpty(refundOrder.getIsvNo()), RefundOrder::getIsvNo, refundOrder.getIsvNo());
        wrapper.eq(refundOrder.getMchType() != null, RefundOrder::getMchType, refundOrder.getMchType());
        wrapper.eq(StringUtils.isNotEmpty(refundOrder.getMchRefundNo()), RefundOrder::getMchRefundNo, refundOrder.getMchRefundNo());
        wrapper.eq(refundOrder.getState() != null, RefundOrder::getState, refundOrder.getState());
        wrapper.eq(refundOrder.getRefundType() != null, RefundOrder::getRefundType, refundOrder.getRefundType());
        wrapper.eq(StringUtils.isNotEmpty(refundOrder.getAgentNo()), RefundOrder::getAgentNo, refundOrder.getAgentNo());
        wrapper.eq(StringUtils.isNotEmpty(refundOrder.getTopAgentNo()), RefundOrder::getTopAgentNo, refundOrder.getTopAgentNo());
        wrapper.like(StringUtils.isNotEmpty(refundOrder.getStoreName()), RefundOrder::getStoreName, refundOrder.getStoreName());
        //wrapper.eq(StringUtils.isNotEmpty(refundOrder.getIfCode()), RefundOrder::getIfCode, refundOrder.getIfCode());
        wrapper.eq(StringUtils.isNotEmpty(refundOrder.getExtParam()),RefundOrder::getExtParam,refundOrder.getExtParam());
        //支付通道改为模糊检索
        if (StringUtils.isNotEmpty(refundOrder.getIfCode())){
            List<PayInterfaceDefine> interfaceDefineList = payInterfaceDefineService.list(PayInterfaceDefine.gw().like(PayInterfaceDefine::getIfName, refundOrder.getIfCode()));
            List<String> collect = interfaceDefineList.stream().map(PayInterfaceDefine::getIfCode).collect(Collectors.toList());
            if (CollUtil.isNotEmpty(collect)){
                wrapper.in(RefundOrder::getIfCode,collect);
            }else {
                wrapper.eq(RefundOrder::getIfCode,refundOrder.getIfCode());
            }
        }
        //渠道号渠道名称检索二合一
        if (StringUtils.isNotEmpty(refundOrder.getIsvNo())){
            List<IsvInfoEntity> isvInfoEntityList = isvInfoService.list(IsvInfoEntity.gw()
                    .like(IsvInfoEntity::getIsvName, refundOrder.getIsvNo()).or()
                    .like(IsvInfoEntity::getIsvShortName, refundOrder.getIsvNo()));
            List<String> collect = isvInfoEntityList.stream().map(IsvInfoEntity::getIsvNo).collect(Collectors.toList());
            if (CollUtil.isNotEmpty(collect)){
                wrapper.in(RefundOrder::getIsvNo,collect);
            }else {
                wrapper.eq(RefundOrder::getIsvNo,refundOrder.getIsvNo());
            }
        }
        //服务商号，名称检索二合一
        if (StringUtils.isNotEmpty(refundOrder.getAgentName())){
            List<AgentInfo> agentInfos = agentInfoService.list(AgentInfo.gw().like(AgentInfo::getAgentName, refundOrder.getAgentName()));
            List<String> collect = agentInfos.stream().map(AgentInfo::getAgentNo).collect(Collectors.toList());
            if (CollUtil.isNotEmpty(collect)){
                wrapper.in(RefundOrder::getAgentNo,collect);
            }else {
                wrapper.eq(RefundOrder::getAgentNo,refundOrder.getAgentName());
            }
        }
        //用户名称、用户号、用户手机号三合一
        if (StringUtils.isNotEmpty(refundOrder.getMchUserName())){
            List<MchInfo> mchInfoList = mchInfoService.list(MchInfo.gw().eq(MchInfo::getContactTel, refundOrder.getMchUserName())
                    .or().like(MchInfo::getMchName, refundOrder.getMchUserName()));
            List<String> collect = mchInfoList.stream().map(MchInfo::getMchNo).collect(Collectors.toList());
            if (CollUtil.isNotEmpty(collect)){
                wrapper.in(RefundOrder::getMchNo,collect);
            }else {
                wrapper.eq(RefundOrder::getMchNo,refundOrder.getMchUserName());
            }
        }
        //应用名称和id检索二合一
        if (StringUtils.isNotEmpty(refundOrder.getAppId())){
            //传入值作为应用名称进行匹配如果匹配不上则为应用id
            List<MchAppEntity> mchAppEntityList = mchAppService.list(MchAppEntity.gw().like(MchAppEntity::getAppName, refundOrder.getAppId()));
            List<String> collect = mchAppEntityList.stream().map(MchAppEntity::getAppId).collect(Collectors.toList());
            if (CollUtil.isNotEmpty(collect)){
                wrapper.in(RefundOrder::getAppId,collect);
            }else {
                wrapper.eq(RefundOrder::getAppId,refundOrder.getAppId());
            }
        }
        if (paramJSON.get("storeInfo") != null) {
            wrapper.and(i->{
                i.eq(RefundOrder::getStoreId,paramJSON.get("storeInfo")).or().like(RefundOrder::getStoreName,paramJSON.get("storeInfo"));
            });
        }
        if(paramJSON.get("mchInfo") != null){
            wrapper.and(wr -> {
                wr.eq(RefundOrder::getMchExtNo, paramJSON.getString("mchInfo"))
                        .or().like(RefundOrder::getMchName, paramJSON.getString("mchInfo"));
            });
        }
        // 时间范围条件
        Date[] dateRange = refundOrder.buildQueryDateRange();
        if (dateRange[0] != null) {
            wrapper.ge(RefundOrder::getCreatedAt, dateRange[0]);
        }
        if (dateRange[1] != null) {
            wrapper.le(RefundOrder::getCreatedAt, dateRange[1]);
        }
        // 三合一订单
        if (paramJSON != null && StringUtils.isNotEmpty(paramJSON.getString("unionOrderId"))) {
            wrapper.and(wr -> {
                wr.eq(RefundOrder::getPayOrderId, paramJSON.getString("unionOrderId"))
                        .or().eq(RefundOrder::getRefundOrderId, paramJSON.getString("unionOrderId"))
                        .or().eq(RefundOrder::getChannelPayOrderNo, paramJSON.getString("unionOrderId"))
                        .or().eq(RefundOrder::getMchRefundNo, paramJSON.getString("unionOrderId"));
            });
        }
        wrapper.orderByDesc(RefundOrder::getCreatedAt);
        IPage<RefundOrder> page = page(iPage, wrapper);
        Map<String, String> ifCodeMap = new HashMap<>();
        List<PayInterfaceDefine> list = payInterfaceDefineService.list();
        if(!list.isEmpty()){
            for (PayInterfaceDefine define:list) {
                ifCodeMap.put(define.getIfCode(), define.getIfName());
            }
        }
        for (RefundOrder order:page.getRecords()) {
            if(StringUtils.isNotBlank(order.getIfCode())){
                order.setIfName(ifCodeMap.get(order.getIfCode()));
            }
            //返回应用名称
            if (StringUtils.isNotEmpty(order.getAppId())){
                MchAppEntity mchAppEntity = mchAppService.getById(order.getAppId());
                if (mchAppEntity != null){
                    order.setAppName(mchAppEntity.getAppName());
                }
            }
            //返回渠道名称
            if (StringUtils.isNotEmpty(order.getIsvNo())){
                IsvInfoEntity infoEntity = isvInfoService.getById(order.getIsvNo());
                if (infoEntity != null){
                    order.setIsvName(infoEntity.getIsvName());
                    order.setIsvShortName(infoEntity.getIsvShortName());
                }
            }
            //返回服务商信息
            if (StringUtils.isNotEmpty(order.getAgentNo())){
                AgentInfo agentInfo = agentInfoService.getById(order.getAgentNo());
                if (agentInfo != null){
                    order.setAgentName(agentInfo.getAgentName());
                    order.setAgentContactTel(DesensitizedUtil.mobilePhone(agentInfo.getContactTel()));
                }
            }
            //返回用户信息
            if (StringUtils.isNotEmpty(order.getMchNo())){
                MchInfo byId = mchInfoService.getById(order.getMchNo());
                if (byId != null){
                    order.setMchUserName(byId.getMchName());
                    order.setMchUserPhone(DesensitizedUtil.mobilePhone(byId.getContactTel()));
                }
            }
        }
        return page;
    }

    public ApiRes getCount(List<RefundOrder> list){
        HashMap<String, Object> resutMap = new HashMap<>();
        if (CollUtil.isNotEmpty(list)){
            //总退款笔数
            resutMap.put("allCount",list.size());
            //总退款金额
            BigDecimal refundAmount= BigDecimal.ZERO;
            for (RefundOrder refundOrder : list) {
                refundAmount=refundAmount.add(BigDecimal.valueOf(refundOrder.getRefundAmount()));
            }
            resutMap.put("allCountAmount",refundAmount);
            //退款成功笔数
            List<RefundOrder> succesCollect = list.stream().filter(order -> order.getState() == 2).collect(Collectors.toList());
            resutMap.put("succesCount",CollUtil.isEmpty(succesCollect)?0:succesCollect.size());
            //退款成功金额
            BigDecimal succesAmount= BigDecimal.ZERO;
            if (CollUtil.isNotEmpty(succesCollect)){
                for (RefundOrder refundOrder : succesCollect) {
                    succesAmount=succesAmount.add(BigDecimal.valueOf(refundOrder.getRefundAmount()));
                }
                resutMap.put("succesAmount",succesAmount);
            }else {
                resutMap.put("succesAmount",0);
            }
            //手续费退款笔数
            List<RefundOrder> feeCollect = list.stream().filter(order -> order.getRefundFeeAmount() != 0).collect(Collectors.toList());
            resutMap.put("feeCount",CollUtil.isEmpty(feeCollect)?0:feeCollect.size());
            //手续费退款金额
            if (CollUtil.isNotEmpty(feeCollect)){
                BigDecimal feeAmount= BigDecimal.ZERO;
                for (RefundOrder refundOrder : feeCollect) {
                    feeAmount=feeAmount.add(BigDecimal.valueOf(refundOrder.getRefundFeeAmount()));
                }
                resutMap.put("feeAmount",feeAmount);
            }else {
                resutMap.put("feeAmount",0);
            }
        }else {
            resutMap.put("allCount",0);
            resutMap.put("allCountAmount",0);
            resutMap.put("succesCount",0);
            resutMap.put("succesAmount",0);
            resutMap.put("feeCount",0);
            resutMap.put("feeAmount",0);
        }
        return ApiRes.ok(resutMap);
    }
}
