package cn.freemud.management.service.handle;

import cn.freemud.management.adapter.PaymentSdkAdapter;
import cn.freemud.management.entities.dto.request.order.OrderManagerRequest;
import cn.freemud.management.entities.dto.request.pay.AgentPayRefundReq;
import cn.freemud.management.entities.dto.request.pay.PayRefundRequestDto;
import cn.freemud.management.entities.dto.request.pay.PaymentQueryOrderRequestDto;
import cn.freemud.management.entities.dto.response.pay.*;
import cn.freemud.management.enums.PaymentRefundStatus;
import cn.freemud.management.enums.ResponseResult;
import cn.freemud.management.intercept.OrderServiceException;
import cn.freemud.management.thirdparty.MulitiPaymentClient;
import cn.freemud.management.thirdparty.OMSPaymentClient;
import cn.freemud.management.util.RedisUtil;
import cn.freemud.redis.RedisCache;
import com.alibaba.fastjson.JSONObject;
import com.freemud.api.assortment.datamanager.entity.db.AssortmentOpenPlatformIappWxappStore;
import com.freemud.api.assortment.datamanager.manager.AssortmentOpenPlatformIappWxappStoreManager;
import com.freemud.application.sdk.api.base.BaseResponse;
import com.freemud.application.sdk.api.log.ErrorLog;
import com.freemud.application.sdk.api.ordercenter.entities.v1.OrderBeanV1;
import com.freemud.application.sdk.api.ordercenter.enums.PayChannelType;
import com.freemud.application.sdk.api.ordercenter.enums.orderv1.OrderTypeV1;
import com.freemud.application.sdk.api.ordercenter.request.OrderExtInfoDto;
import com.freemud.application.sdk.api.ordercenter.request.OrderExtendedReq;
import com.freemud.application.sdk.api.ordercenter.response.OrderBaseResp;
import com.freemud.application.sdk.api.ordercenter.response.orderInfo.AfterSalesOrderResp;
import com.freemud.application.sdk.api.ordercenter.service.OrderSdkService;
import com.freemud.application.sdk.api.ordercenter.util.LogUtil;
import com.freemud.application.sdk.api.util.ResponseUtils;
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.ObjectUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

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


/**
 * All rights Reserved, Designed By www.freemud.cn
 *
 * @version V1.0
 * @Title: PaymentService
 * @Package cn.freemud.management.service.impl
 * @Description:
 * @author: shuhu.hou
 * @date: 2020/4/24 10:45
 * @Copyright: 2020 www.freemud.cn Inc. All rights reserved.
 * 注意：本内容仅限于上海非码科技内部传阅，禁止外泄以及用于其他的商业目
 */
@Component
public class PaymentHandle {

    private static final String SUCCESS = "100";
    public static final Integer SUCCESS_RESPONSE_CODE_INT = 100;
    public static final Integer SUCCESS_RESPONSE_101_CODE_INT = 101;

    public static final Integer REFUND_RESPONSE_CODE = 8200305;


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

    @Autowired
    private OMSPaymentClient paymentNewClient;

    @Autowired
    private AssortmentOpenPlatformIappWxappStoreManager assortmentOpenPlatformIappWxappStoreManager;
    @Autowired
    private LogUtil logUtil;

    /**
     * 点餐订单退款入口
     * 支付退款，包含纯现金，代付，混合支付
     *
     * @param request
     * @param orderBean
     * @return
     */
    public PayRefundResponse getCommonPayRefundResponse(OrderManagerRequest request, OrderBeanV1 orderBean) {
        PayRefundResponse refundResponse;
        try {
            if (null != orderBean.getOrderPayItem() && orderBean.getOrderPayItem().size() > 0) {
                //  payment/application/refund
                refundResponse = this.multiRefund(orderBean);
            } else {
                OrderExtendedReq ext = orderBean.getOrderExtended();
                if (StringUtils.isNotBlank(ext.getAgentPayerId()) && !Objects.equals(ext.getAgentPayerId(), orderBean.getUserId())) {
                    //代付人信息不为空  并且和订单创建人不一样，表示代付单   payment/application/agentRefund
                    refundResponse = this.agentPayRefund(orderBean);
                } else {
                    //正常订单现金退款  paymentcenter/refund
                    refundResponse = this.payRefund(request.getReason(), orderBean);
                }
            }
        } catch (OrderServiceException orderEx) {
            ResponseResult result = orderEx.getResult();
            refundResponse = new PayRefundResponse();
            refundResponse.setPayRefundStatus(PayRefundStatus.COMPATIBILITY_STATUS);
            refundResponse.setMessage(result.getMessage());
            refundResponse.setResult(result);
            return refundResponse;
        } catch (Exception e) {
            refundResponse = new PayRefundResponse();
            refundResponse.setPayRefundStatus(PayRefundStatus.COMPATIBILITY_STATUS);
            refundResponse.setMessage("请稍后再试！");
            refundResponse.setResult(ResponseResult.SYSTEM_ERROR);
            return refundResponse;
        }
        return refundResponse;
    }

    /**
     * 纯现金支付退款，非代付和混合支付退款
     *
     * @param reason    退款原因
     * @param orderBean
     * @return
     */
    private PayRefundResponse payRefund(String reason, OrderBeanV1 orderBean) {
        PayRefundStatus refundStatus = PayRefundStatus.SUCCESS;
        PayRefundRequestDto orderRefundRequest = paymentSdkAdapter.getOrderRefundRequest(orderBean, getRefundAmount(orderBean));
        //抖音支付必传
        orderRefundRequest.setRefundDesc(reason == null ? "商家退款" : reason);
        if (ObjectUtils.equals(orderBean.getAmount(), 0L)) {
            return handlePayRefundResponse(refundStatus, orderRefundRequest.getRefundId());
        }
        BaseResponse<OrderRefundResponse> orderRefundResponse = this.orderPayRefund(orderRefundRequest);
        String message = null;
        if (orderRefundResponse == null) {
            refundStatus = PayRefundStatus.RUNNING;
        } else {
            refundStatus = this.getFinalRefundStatus(Integer.valueOf(orderRefundResponse.getCode()));
            message = orderRefundResponse.getMessage();
        }
        PayRefundResponse payRefundResponse = handlePayRefundResponse(refundStatus, orderRefundRequest.getRefundId());
        if(message != null){
            payRefundResponse.setMessage(message);
        }
        return payRefundResponse;
    }

    /**
     * 混合支付退款
     */
    private PayRefundResponse multiRefund(OrderBeanV1 orderBean) {
        PayRefundStatus refundStatus = PayRefundStatus.SUCCESS;
        MultiOrderRefundRequest multiOrderRefundRequest = paymentSdkAdapter.getMultiOrderPayRefundRequest(orderBean, getRefundAmount(orderBean));
        MultiOrderRefundResponse multiOrderRefundResponse = mulitiPaymentClient.paymentApplicationRefund(multiOrderRefundRequest, orderBean.getCompanyId());
        String message = "";
        if (multiOrderRefundResponse == null || multiOrderRefundResponse.getData() == null || !com.freemud.sdk.api.assortment.order.domain.ResponseCodeConstant.ORDER_PAY_RESPONSE_SUCCESS.equals(multiOrderRefundResponse.getCode())) {
            // fisherman 退款异常 也当做 退款中处理
            refundStatus = PayRefundStatus.RUNNING;
        } else {
            List<MultiOrderRefundResponse.RefundPlatformResponse> refundPlatformResponseList = multiOrderRefundResponse.getData().refundPlatformResponseList;
            if (null != refundPlatformResponseList && refundPlatformResponseList.size() > 0) {
                redisCache.save(RedisUtil.getPaymentTransIdSequenceKey(refundPlatformResponseList.get(0).getTransId()), orderBean.getOid(), 1L, TimeUnit.DAYS);
            }
            if (CollectionUtils.isNotEmpty(refundPlatformResponseList)) {
                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, multiOrderRefundRequest.getRefundTradeNo());
        if(StringUtils.isNotEmpty(message)){
            payRefundResponse.setMessage(message);
        }
        return payRefundResponse;
    }

    /**
     * 代付订单退款
     *
     * @param orderBean
     * @return
     */
    private PayRefundResponse agentPayRefund(OrderBeanV1 orderBean) {
        PayRefundStatus refundStatus = PayRefundStatus.SUCCESS;
        String fmRefundNo = "";
        try {
            AgentPayRefundReq req = paymentSdkAdapter.getAgentPayefundReq(orderBean, this.getRefundAmount(orderBean));
            AgentPayRefundResp resp = mulitiPaymentClient.agentPayRefund(req);
            if (!resp.isOk()) {
                refundStatus = PayRefundStatus.RUNNING;
            }
            AgentPayRefundResp.DataDTO data = resp.getData();
            if (Objects.nonNull(data)) {
                refundStatus = this.getFinalRefundStatus(data.getResultCode());
            }
            fmRefundNo = resp.getData().getFmRefundNo();
        } catch (Throwable e) {
            refundStatus = PayRefundStatus.FAIL;
        }
        return this.handlePayRefundResponse(refundStatus, fmRefundNo);
    }


    private PayRefundStatus getFinalRefundStatus(Integer resultCode) {
        switch (resultCode) {
            // 退款中状态码需要单独处理
            case 8200305:
                return PayRefundStatus.RUNNING;
            // 重复请求,按照退款中处理
            case 82004005:
                return PayRefundStatus.RUNNING;
            // 退款成功
            case 100:
                return PayRefundStatus.SUCCESS;
            default:
                return PayRefundStatus.FAIL;
        }
    }


    /**
     * 查询退款配置
     */
    private PayRefundRequestDto queryWxAppStore(BaseResponse<PaymentQueryOrderResponseDto> payQueryOrderResponse, PayRefundRequestDto refundRequest) {
        String payCode = null;
        if (Objects.equals(payQueryOrderResponse.getCode(), "100") && payQueryOrderResponse.getData() != null) {
            refundRequest.setTotalAmount((payQueryOrderResponse.getData()).getAmount());
            payCode = payQueryOrderResponse.getCode();
        }

        if (refundRequest.getTotalAmount() == null || refundRequest.getTotalAmount() == 0L) {
            refundRequest.setTotalAmount(refundRequest.getRefundAmount());
        }
        AssortmentOpenPlatformIappWxappStore wxAppStore = this.assortmentOpenPlatformIappWxappStoreManager.selectWxappStoreByWxAppIdAndStoreId(refundRequest.getAppId(), refundRequest.getStoreId(), payCode);
        PayRefundRequestDto request = new PayRefundRequestDto();
        request.setStoreId(refundRequest.getStoreId());
        request.setStationId(refundRequest.getStationId());
        request.setOperatorId(refundRequest.getOperatorId());
        request.setTransId(refundRequest.getOrgTransId());
        request.setBusinessDate(refundRequest.getBusinessDate());
        request.setFmId(refundRequest.getOrgPayFmId());
        request.setTotalAmount(refundRequest.getTotalAmount());
        request.setRefundAmount(refundRequest.getRefundAmount());
        request.setRefundId(refundRequest.getRefundId());
        request.setRefundDesc(refundRequest.getRefundDesc());
        request.setNotifyUrl(refundRequest.getNotifyUrl());
        request.setPartnerId(refundRequest.getPartnerId());
        request.setVer(2);
        request.setExtendParams(refundRequest.getExtendParams());
        com.freemud.application.sdk.api.base.BaseResponse<OrderRefundResponse> checkParam = this.checkParam(refundRequest.getPartnerId(), refundRequest.getStoreId(), refundRequest.getRefundAmount(), wxAppStore);
        if (!Objects.equals(checkParam.getCode(), "100")) {
            return null;
        }
        return request;
    }

    /**
     * @param refundRequest
     * @return
     */
    private BaseResponse<PaymentQueryOrderResponseDto> queryPayOrder(PayRefundRequestDto refundRequest) {
        PaymentQueryOrderRequestDto paymentQueryOrderRequest = new PaymentQueryOrderRequestDto();

        paymentQueryOrderRequest.setPartnerId(refundRequest.getPartnerId());
        paymentQueryOrderRequest.setStoreId(refundRequest.getStoreId());
        paymentQueryOrderRequest.setFrontTransId(refundRequest.getOrgTransId());
        BaseResponse<PaymentQueryOrderResponseDto> payQueryOrderResponse = null;
        try {
            payQueryOrderResponse = paymentNewClient.payQueryOrder(paymentQueryOrderRequest);
        } catch (Exception e) {
            cn.freemud.base.log.ErrorLog.errorConvertJson(this.getClass(), "paymentcenter/queryOrder error", e);
        }
        if (payQueryOrderResponse == null) {
            return null;
        }
        return payQueryOrderResponse;
    }


    /**
     * 卖券调用退款
     *
     * @param reason
     * @param orderBean
     * @return -2正常 -1 不需要退款 0其他异常 1账户余额不足 2 系统异常
     */
    public PayRefundResponse refund(String reason, OrderBeanV1 orderBean) {
        PayRefundStatus refundStatus = PayRefundStatus.SUCCESS;

        PayRefundRequestDto orderRefundRequest = paymentSdkAdapter.getOrderRefundRequest(orderBean, getRefundAmount(orderBean));
        //抖音支付必传
        orderRefundRequest.setRefundDesc(reason);
        if (ObjectUtils.equals(orderBean.getAmount(), 0L)) {
            return handlePayRefundResponse(refundStatus, orderRefundRequest.getRefundId());
        }
        BaseResponse<OrderRefundResponse> orderRefundResponse;
        orderRefundResponse = this.orderPayRefund(orderRefundRequest);
        if (orderRefundResponse == null) {
            // 退款失败
            refundStatus = PayRefundStatus.FAIL;
            return handlePayRefundResponse(refundStatus, orderRefundRequest.getRefundId());
        }
        if (ObjectUtils.notEqual(orderRefundResponse.getCode(), SUCCESS)) {
            //商户余额不足的情况下，返回异常特殊处理.
            refundStatus = PayRefundStatus.FAIL;
            if (ResponseResult.NOT_SUFFICIENT_FUNDS.getCode().equals(orderRefundResponse.getCode())) {
                refundStatus = PayRefundStatus.NOT_SUFFICIENT_FUNDS;
            }
        }
        return handlePayRefundResponse(refundStatus, orderRefundRequest.getRefundId());
    }

    /**
     * 线下pos下单使用储值卡支付，储值卡退款
     *
     * @param orderBean
     * @return
     */
    public PayRefundResponse posOrderPayRefund(OrderBeanV1 orderBean, OrderExtInfoDto orderExtInfoDto) {
        PayRefundStatus refundStatus = PayRefundStatus.SUCCESS;
        PayRefundRequestDto refundRequest = paymentSdkAdapter.convert2OrderRefundNewRequest(orderBean, orderExtInfoDto);
        if (ObjectUtils.equals(orderBean.getAmount(), 0L)) {
            return handlePayRefundResponse(refundStatus, refundRequest.getRefundId());
        }
        BaseResponse<PayRefundData> orderRefundResponse;
        try {
            orderRefundResponse = paymentNewClient.payRefund(refundRequest);
        } catch (Exception ex) {
            ErrorLog.errorConvertJson(this.getClass(), "paymentNewService.newOrderRefundError", ex);
            throw new OrderServiceException(ResponseResult.REFUND_EXCEPTION);
        }
        if (orderRefundResponse == null || orderRefundResponse.getData() == null) {
            throw new OrderServiceException(ResponseResult.REFUND_EXCEPTION);
        }
        if (ObjectUtils.notEqual(orderRefundResponse.getCode(), SUCCESS)) {
            throw new OrderServiceException(ResponseResult.REFUND_FAIL, orderRefundResponse.getMessage());
        }
        if (ObjectUtils.equals(orderRefundResponse.getData().getResultCode(), 101)) {
            refundStatus = PayRefundStatus.SUCCESS;
            return handlePayRefundResponse(refundStatus, refundRequest.getRefundId());
        }
        refundStatus = ObjectUtils.equals(orderRefundResponse.getData().getResultCode(), 100) ? PayRefundStatus.SUCCESS : PayRefundStatus.FAIL;
        return handlePayRefundResponse(refundStatus, refundRequest.getRefundId());
    }

    /**
     * 获取退款金额
     *
     * @param data
     * @return
     */
    private BigDecimal getRefundAmount(OrderBeanV1 data) {
        BigDecimal refundAmount = new BigDecimal(data.getAmount());
        OrderBaseResp<List<AfterSalesOrderResp>> listBaseResponse = orderSdkService.queryAfterSaleByOrderCode(data.getCompanyId(), data.getOid());
        if (CollectionUtils.isNotEmpty(listBaseResponse.getResult())) {
            refundAmount = new BigDecimal(listBaseResponse.getResult().get(0).getActualAmount());
        }
        return refundAmount;
    }

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


    /**
     * 纯现金支付退款，非代付和混合支付退款
     */
    private BaseResponse<OrderRefundResponse> orderPayRefund(PayRefundRequestDto refundRequest) {

        // step1 查询支付结果
        BaseResponse<PaymentQueryOrderResponseDto> paymentQueryOrderResponseDtoBaseResponse = this.queryPayOrder(refundRequest);
        if (Objects.isNull(paymentQueryOrderResponseDtoBaseResponse)) {
            throw new OrderServiceException(ResponseResult.REFUND_EXCEPTION);
        }
        // step2 查询退款配置
        PayRefundRequestDto request = this.queryWxAppStore(paymentQueryOrderResponseDtoBaseResponse, refundRequest);
        if (Objects.isNull(request)) {
            throw new OrderServiceException(ResponseResult.CHECK_PARAM_ERROR);
        }

        // step3 退款
        BaseResponse<PayRefundData> refundNewResponse = null;
        try {
            refundNewResponse = paymentNewClient.payRefund(request);
        } catch (Exception e) {
            ErrorLog.errorConvertJson(this.getClass(), "paymentcenter/refund error", e);
        }

        if (refundNewResponse == null) {
            return null;
        }
        logUtil.info("paymentcenter/refund", JSONObject.toJSONString(request), JSONObject.toJSONString(refundNewResponse));
        //支付状态码取内部值
        if (Objects.equals(refundNewResponse.getCode(), "100") && refundNewResponse.getData() != null) {
            refundNewResponse.setCode(refundNewResponse.getData().getResultCode().toString());
            refundNewResponse.setMessage(refundNewResponse.getData().getResultMsg());
        }
        if (Objects.equals(refundNewResponse.getCode(), "100")) {
            PayRefundData refundData = refundNewResponse.getData();
            if (null != refundData) {
                OrderRefundResponse refundResponse = new OrderRefundResponse();
                refundResponse.setStatusCode(refundData.getResultCode());
                refundResponse.setMsg(refundData.getResultMsg());
                refundResponse.setRefundAmount(refundData.getRefundAmount());
                refundResponse.setTotalAmount(refundData.getTotalAmount());
                refundResponse.setRefundStatus(this.getRefundStatus(refundData.getResultCode()));
                refundResponse.setRefundTradeNo(refundData.getRefundTradeNo());
                refundResponse.setTradeNo(refundData.getRefundTradeNo());
                refundResponse.setThirdPartRefundTradeNo(refundData.getThirdPartRefundTradeNo());
                refundResponse.setThirdPartTradeNo(refundData.getThirdPartTradeNo());
                refundResponse.setTotalAmount(refundData.getTotalAmount());
                return ResponseUtils.success(refundResponse);
            }
        }
        return ResponseUtils.error(refundNewResponse.getCode(), refundNewResponse.getMessage());
    }


    private com.freemud.application.sdk.api.base.BaseResponse<OrderRefundResponse> checkParam(String partnerId, String storeId, Long amount, AssortmentOpenPlatformIappWxappStore wxAppStore) {
        if (StringUtils.isBlank(partnerId)) {
            return ResponseUtils.error("501", "商户号不能为空");
        } else if (StringUtils.isBlank(storeId)) {
            return ResponseUtils.error("501", "门店号不能为空");
        } else if (amount == null) {
            return ResponseUtils.error("501", "金额不能为空");
        } else {
            return wxAppStore == null ? ResponseUtils.error("500", "支付信息没有配置") : ResponseUtils.success();
        }
    }


    private Integer getRefundStatus(Integer resultCode) {
        if (Objects.equals(resultCode, SUCCESS_RESPONSE_CODE_INT)) {
            return PaymentRefundStatus.PAYMENT_REFUND_STATUS_1.getCode();
        } else if (Objects.equals(resultCode, SUCCESS_RESPONSE_101_CODE_INT)) {
            return PaymentRefundStatus.PAYMENT_REFUND_STATUS_1.getCode();
        } else {
            return Objects.equals(resultCode, REFUND_RESPONSE_CODE) ? PaymentRefundStatus.PAYMENT_REFUND_STATUS_4.getCode() : PaymentRefundStatus.PAYMENT_REFUND_STATUS_2.getCode();
        }
    }

}
