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.JSON;
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.orderv1.OrderTypeV1;
import com.freemud.application.sdk.api.ordercenter.request.OrderExtInfoDto;
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;


    @Value("${mccafe.partner.id}")
    private String macCafePartnerId;

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

    @Autowired
    private OMSPaymentClient paymentNewClient;

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

    /**
     * 退款
     *
     * @param request
     * @param orderBean
     * @return
     */
    public PayRefundResponse refund(OrderManagerRequest request, OrderBeanV1 orderBean) {
        PayRefundStatus refundStatus = PayRefundStatus.SUCCESS;
        PayRefundRequestDto orderRefundRequest = paymentSdkAdapter.getOrderRefundRequest(orderBean, getRefundAmount(orderBean));
        //抖音支付必传
        orderRefundRequest.setRefundDesc(request.getReason() == null ? "商家退款" : request.getReason());
        if (ObjectUtils.equals(orderBean.getAmount(), 0L)) {
            return handlePayRefundResponse(refundStatus, orderRefundRequest.getRefundId());
        }
        BaseResponse<OrderRefundResponse> orderRefundResponse;
//        orderRefundResponse = standardPaymentService.orderRefund(orderRefundRequest, LogThreadLocal.getTrackingNo());
        orderRefundResponse = this.orderPayRefund(orderRefundRequest);
        if (orderRefundResponse == null) {
            throw new OrderServiceException(ResponseResult.REFUND_EXCEPTION);
        }
        if (ObjectUtils.notEqual(orderRefundResponse.getCode(), SUCCESS)) {
            //商户余额不足的情况下，返回异常特殊处理.
            if (ResponseResult.NOT_SUFFICIENT_FUNDS.getCode().equals(orderRefundResponse.getCode())) {
                throw new OrderServiceException(ResponseResult.NOT_SUFFICIENT_FUNDS);
            }
            ResponseResult refundFail = ResponseResult.REFUND_FAIL;
            refundFail.setMessage(orderRefundResponse.getMessage());
            throw new OrderServiceException(refundFail);
        }
        refundStatus = ObjectUtils.equals(PayRefundStatus.SUCCESS.getCode(), orderRefundResponse.getData().getRefundStatus()) ? PayRefundStatus.SUCCESS : PayRefundStatus.RUNNING;
        return handlePayRefundResponse(refundStatus, orderRefundRequest.getRefundId());
    }

    /**
     * 代付订单退款
     *
     * @param request
     * @param orderBean
     * @return
     */
    public PayRefundResponse agentPayRefund(OrderManagerRequest request, OrderBeanV1 orderBean) {
        PayRefundResponse ret = new PayRefundResponse();
        try {
            OrderExtInfoDto ext = JSON.parseObject(orderBean.getExtInfo(), OrderExtInfoDto.class);
            AgentPayRefundReq req = new AgentPayRefundReq();
            req.setPartnerId(orderBean.getCompanyId());
            req.setStoreId(orderBean.getShopId());
            req.setFmTradeNo(ext.getPayTransId());
            req.setOutOrderNo(orderBean.getOid());
            req.setVer("V1");
            AgentPayRefundResp resp = mulitiPaymentClient.agentPayRefund(req);
            if (!resp.isOk()) throw new Exception("退款失败");
            ret.setRefundId(resp.getData().getFmRefundNo());
            ret.setPayRefundStatus(PayRefundStatus.SUCCESS);
        } catch (Throwable e) {
            ret.setPayRefundStatus(PayRefundStatus.FAIL);
        }
        return ret;
    }


    /**
     * 卖券调用退款
     * @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());
    }

    /**
     * 退款
     *
     * @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());
        }
//        com.freemud.application.sdk.api.base.BaseResponse<RefundNewResponse> orderRefundResponse;
        BaseResponse<PayRefundData> orderRefundResponse;
        try {
//            orderRefundResponse = paymentNewService.newOrderRefund(refundRequest, LogThreadLocal.getTrackingNo());
            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 request
     * @param orderBean
     * @return
     */
    public PayRefundResponse mcCafeRefund(OrderManagerRequest request, OrderBeanV1 orderBean) {
        PayRefundStatus refundStatus = PayRefundStatus.SUCCESS;
        PayRefundRequestDto orderRefundRequest = paymentSdkAdapter.getOrderRefundRequest(orderBean, new BigDecimal(orderBean.getAmount()));
        if (ObjectUtils.equals(orderBean.getAmount(), 0L)) {
            return handlePayRefundResponse(refundStatus, orderRefundRequest.getRefundId());
        }
        if (macCafePartnerId.equals(orderBean.getCompanyId())) {
            Map<String, String> extendParams = new HashMap<>();
            if (OrderTypeV1.TAKE_OUT.getCode().equals(orderBean.getOrderType())) {
                extendParams.put("mealType", "delivery");
            } else {
                extendParams.put("mealType", "pickup");
            }
            orderRefundRequest.setExtendParams(extendParams);
        }
        BaseResponse<OrderRefundResponse> orderRefundResponse;
        try {
//            orderRefundResponse = standardPaymentService.orderRefund(orderRefundRequest, "");
            orderRefundResponse = this.orderPayRefund(orderRefundRequest);
        } catch (Exception ex) {
            ErrorLog.errorConvertJson(this.getClass(), "refundError", ex);
            return handlePayRefundResponse(PayRefundStatus.FAIL, orderRefundRequest.getRefundId());
        }
        if (orderRefundResponse == null || ObjectUtils.notEqual(orderRefundResponse.getCode(), SUCCESS)) {
            return handlePayRefundResponse(PayRefundStatus.FAIL, orderRefundRequest.getRefundId());
        }
        refundStatus = ObjectUtils.equals(PayRefundStatus.SUCCESS.getCode(), orderRefundResponse.getData().getRefundStatus()) ? PayRefundStatus.SUCCESS : PayRefundStatus.FAIL;
        return handlePayRefundResponse(refundStatus, orderRefundRequest.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, Long refundId) {
        PayRefundResponse payRefundResponse = new PayRefundResponse();
        payRefundResponse.setPayRefundStatus(refundStatus);
        payRefundResponse.setRefundId(refundId.toString());
        return payRefundResponse;
    }

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

    public PayRefundResponse multiRefund(OrderBeanV1 orderBean) {
        PayRefundStatus refundStatus = PayRefundStatus.SUCCESS;
        MultiOrderRefundRequest multiOrderRefundRequest = paymentSdkAdapter.getMultiOrderPayRefundRequest(orderBean, getRefundAmount(orderBean));
        MultiOrderRefundResponse multiOrderRefundResponse = mulitiPaymentClient.paymentApplicationRefund(multiOrderRefundRequest, orderBean.getCompanyId());
        if (multiOrderRefundResponse == null || multiOrderRefundResponse.getData() == null || !com.freemud.sdk.api.assortment.order.domain.ResponseCodeConstant.ORDER_PAY_RESPONSE_SUCCESS.equals(multiOrderRefundResponse.getCode())) {
            throw new OrderServiceException(ResponseResult.REFUND_EXCEPTION);
        }
        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);
        }
        return handlePayRefundResponse(refundStatus, multiOrderRefundRequest.getRefundTradeNo());
    }


    /**
     * 支付退款
     */
    public BaseResponse<OrderRefundResponse> orderPayRefund(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;
        }
        Long vipAmount = 0L;
        String payCode = null;
        if (Objects.equals(payQueryOrderResponse.getCode(), "100") && payQueryOrderResponse.getData() != null) {
            if ((payQueryOrderResponse.getData()).getVipAmount() != null && (payQueryOrderResponse.getData()).getVipAmount() != 0) {
                vipAmount = (long) (payQueryOrderResponse.getData()).getVipAmount();
            }

            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 checkParam;
        } else {
//            String receiveJsonStr = this.setPayValueFromSDKByManager(refundRequest.getPartnerId(), refundRequest.getStoreId(), refundRequest.getRefundAmount() + vipAmount, vipAmount, wxAppStore.getIndirectId(), false);
//            if (!StringUtils.isEmpty(receiveJsonStr)) {
//                request.setAccountDivided(receiveJsonStr);
//            }

            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")) {
                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);
                }
            }

            if (!Arrays.asList("8200201", "8200202", "8200203", "8200204", "8200205").contains(refundNewResponse.getCode())) {
//                this.emailAlertService.sendEmailAlert("支付退款失败", "请求json:" + JSONObject.toJSONString(request) + "返回msg:" + refundNewResponse.getMessage());
            }

            return ResponseUtils.error(refundNewResponse.getCode(), refundNewResponse.getMessage());
        }

    }

    public 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();
        }
    }


    public 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();
        }
    }

}
