package cn.freemud.management.service.handle;

import cn.freemud.base.util.DateUtil;
import cn.freemud.management.adapter.OrderCancelReqAdapter;
import cn.freemud.management.adapter.PaymentSdkAdapter;
import cn.freemud.management.entities.dto.request.pay.AgentPayRefundReq;
import cn.freemud.management.entities.dto.response.pay.AgentPayRefundResp;
import cn.freemud.management.entities.dto.response.pay.PayRefundResponse;
import cn.freemud.management.thirdparty.MulitiPaymentClient;
import cn.freemud.management.util.RedisUtil;
import cn.freemud.redis.RedisCache;
import com.freemud.application.sdk.api.ordercenter.enums.CashTypeEnum;
import com.freemud.application.sdk.api.ordercenter.enums.PayChannelType;
import com.freemud.application.sdk.api.ordercenter.enums.PayMethodEnum;
import com.freemud.application.sdk.api.ordercenter.response.orderInfo.OrderPayItemResp;
import com.freemud.sdk.api.assortment.order.enums.PayRefundStatus;
import com.freemud.sdk.api.assortment.order.request.order.MultiOrderRefundRequest;
import com.freemud.sdk.api.assortment.order.response.order.MultiOrderRefundResponse;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

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

@Component
public class MultiRefundService {

    @Autowired
    private PaymentSdkAdapter paymentSdkAdapter;
    @Autowired
    private MulitiPaymentClient mulitiPaymentClient;
    @Autowired
    private RedisCache redisCache;


    /**
     * 多种支付方式支付退款
     */
    public PayRefundResponse multiRefund(String partnerId, String storeCode, String orderCode, BigDecimal refundAmount,
                                         List<OrderPayItemResp> orderPayItem, Integer orderClient){
        //是否多种支付方式支付退款
        if(!getMultiRefund(orderPayItem,orderClient)){
            return null;
        }
        return multiRefund(partnerId, storeCode, orderCode, refundAmount);
    }



    /**
     * 订单支付明细表新saas都会存数据，ka,pass商户需要兼容
     * 是否多种支付方式支付退款 有储值卡支付，调混合支付退款接口 单宝其他支付方式支付退款（汇来米，收钱吧，现金，其他）
     * @param orderPayItems
     * @return
     */
    private Boolean getMultiRefund(List<OrderPayItemResp> orderPayItems,Integer orderClient){
        boolean isMultiRefund = false;
        if(CollectionUtils.isEmpty(orderPayItems)){
            return isMultiRefund;
        }
        //订单宝支付走混合支付接口，退款走混合支付退款
        List<Integer> orderClients = Arrays.asList(38);
        if(orderClients.contains(orderClient)){
            return true;
        }
        List<Integer> multiPayChannelType = Arrays.asList(3,8,10,50,51,52);
        for(OrderPayItemResp orderPayItemResp : orderPayItems){
            //有储值卡支付，调混合支付退款
            if(multiPayChannelType.contains(orderPayItemResp.getPayChannelType())){
                isMultiRefund = true;
            }
        }
        return isMultiRefund;
    }


    /**
     * 多种支付方式支付退款（包括储值卡退款，微信和储值卡，订单宝其他支付方式支付退款（汇来米，收钱吧，现金，其他））
     */
    private PayRefundResponse multiRefund(String partnerId, String storeCode, String orderCode, BigDecimal refundAmount) {
        PayRefundStatus refundStatus = PayRefundStatus.SUCCESS;
        MultiOrderRefundRequest req = paymentSdkAdapter.getMultiOrderPayRefundRequest(partnerId, storeCode, orderCode, refundAmount);
        MultiOrderRefundResponse resp = mulitiPaymentClient.paymentApplicationRefund(req, partnerId);
        String message = "";
        if (Objects.isNull(resp) || resp.getCode() != 200) {
            refundStatus = PayRefundStatus.FAIL;
        } else {
            MultiOrderRefundResponse.RefundPlatform data = resp.getData();
            if (Objects.isNull(data) || CollectionUtils.isEmpty(data.refundPlatformResponseList)) {
                refundStatus = PayRefundStatus.FAIL;
            } else {
                List<MultiOrderRefundResponse.RefundPlatformResponse> refundPlatformResponseList = data.refundPlatformResponseList;
                redisCache.save(RedisUtil.getPaymentTransIdSequenceKey(refundPlatformResponseList.get(0).getTransId()), orderCode, 1L, TimeUnit.DAYS);

                long refundError = refundPlatformResponseList.stream()
                        .filter(s -> s.getResultCode().compareTo(MultiOrderRefundResponse.RefundPlatformResponse.REFUNDED_RESULTCODE) != 0
                                && s.getResultCode().compareTo(MultiOrderRefundResponse.RefundPlatformResponse.REFUND_SUCCESS) != 0)
                        .count();
                if (refundError > 0L) {
                    refundStatus = PayRefundStatus.FAIL;
                }
                // 退款中
                long refunded = refundPlatformResponseList.stream()
                        .filter(s -> s.getResultCode().compareTo(MultiOrderRefundResponse.RefundPlatformResponse.REFUNDED_RESULTCODE) == 0)
                        .count();
                if (refunded > 0L) {
                    refundStatus = PayRefundStatus.RUNNING;
                }
                for (MultiOrderRefundResponse.RefundPlatformResponse refundPlatformResponse : refundPlatformResponseList) {
                    if (refundPlatformResponse.getResultCode().compareTo(MultiOrderRefundResponse.RefundPlatformResponse.REFUND_SUCCESS) != 0) {
                        message = refundPlatformResponse.getResultMsg() + ";" + message;
                    }
                }
            }
        }

        PayRefundResponse payRefundResponse = handlePayRefundResponse(refundStatus, req.getRefundTradeNo());
        if (PayRefundStatus.SUCCESS.equals(refundStatus)) {
            payRefundResponse.setPayRefundItemList(OrderCancelReqAdapter.convertMultiRefundItem(resp.getData().getRefundPlatformResponseList()));
        }
        if (StringUtils.isNotEmpty(message)) {
            payRefundResponse.setMessage(message);
        }
        return payRefundResponse;
    }


    /**
     * 代付退款
     */
    public PayRefundResponse agentPayRefund(String partnerId, String storeCode, String orderCode, BigDecimal refundAmount, String fmTradeNo) {
        PayRefundStatus refundStatus = PayRefundStatus.SUCCESS;
        String fmRefundNo = "";
        List<PayRefundResponse.PayRefundItem> refundItems = new ArrayList<>();
        try {
            AgentPayRefundReq req = paymentSdkAdapter.getAgentPayRefundReq(partnerId, storeCode, orderCode, refundAmount, fmTradeNo);
            AgentPayRefundResp resp = mulitiPaymentClient.agentPayRefund(req);
            if (!resp.isOk()) {
                refundStatus = PayRefundStatus.FAIL;
            }
            AgentPayRefundResp.DataDTO data = resp.getData();
            if (Objects.nonNull(data)) {
                refundStatus = this.getFinalRefundStatus(data.getResultCode());
                fmRefundNo = data.getFmRefundNo();
                PayRefundResponse.PayRefundItem refundItem = new PayRefundResponse.PayRefundItem();
                refundItem.setPayChannelType(Integer.valueOf(PayChannelType.getByEbcode(data.getEbcode()).getIndex()));
                refundItem.setPayChannelName(PayChannelType.getByEbcode(data.getEbcode()).getName());
                refundItem.setAmount(data.getRefundAmount());
                refundItem.setRefundTradeNo(data.getRefundEndTransTradeNo());
                refundItem.setRefundTime(DateUtil.convert2Date(data.getRefundTime(), "yyyy-MM-dd HH:mm:ss").getTime());
                refundItems.add(refundItem);
            }
        } catch (Throwable e) {
            refundStatus = PayRefundStatus.FAIL;
        }
        PayRefundResponse payRefundResponse = this.handlePayRefundResponse(refundStatus, fmRefundNo);
        payRefundResponse.setPayRefundItemList(refundItems);
        return payRefundResponse;
    }














    private PayRefundStatus getFinalRefundStatus(Integer resultCode) {
        return PayRefundStatus.getByPayResultCode(resultCode);
    }

    private PayRefundResponse handlePayRefundResponse(PayRefundStatus refundStatus, String refundId) {
        PayRefundResponse payRefundResponse = new PayRefundResponse();
        payRefundResponse.setPayRefundStatus(refundStatus);
        payRefundResponse.setRefundId(refundId);
        payRefundResponse.setMessage(refundStatus.getDesc());
        return payRefundResponse;
    }

}
