/**
 * All rights Reserved, Designed By www.freemud.cn
 *
 * @Title: PlatformOrderRelationServiceImpl
 * @Description:
 * @author: pengfei.liu
 * @date: 2020/11/23
 * @version V1.0
 * @Copyright: 2020 www.freemud.cn Inc. All rights reserved.
 * 注意：本内容仅限于上海非码科技内部传阅，禁止外泄以及用于其他的商业目
 */

package cn.freemud.service.coupon.impl;

import cn.freemud.adapter.CouponAdapter;
import cn.freemud.amqp.Header;
import cn.freemud.amqp.MQAction;
import cn.freemud.amqp.MQMessage;
import cn.freemud.amqp.MQService;
import cn.freemud.base.entity.BaseResponse;
import cn.freemud.base.util.JsonUtil;
import cn.freemud.entities.dto.*;
import cn.freemud.entities.vo.CreateOrderVo;
import cn.freemud.entities.vo.QueryOrderResponseVo;
import cn.freemud.base.util.JsonUtil;
import cn.freemud.entities.dto.*;
import cn.freemud.enums.*;
import cn.freemud.management.enums.OrderSource;
import cn.freemud.service.coupon.CouponRelationFactory;
import cn.freemud.service.coupon.CouponRelationService;
import cn.freemud.service.impl.StoreServiceImpl;
import cn.freemud.service.order.OrderRelationService;
import cn.freemud.service.thirdparty.CouponOfflineClient;
import cn.freemud.utils.AppLogUtil;
import cn.freemud.utils.PropertyConvertUtil;
import cn.freemud.utils.ResponseUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.freemud.application.sdk.api.couponcenter.offline.service.OfflineCouponSdkService;
import com.freemud.application.sdk.api.log.ErrorLog;
import com.freemud.application.sdk.api.log.LogThreadLocal;
import com.freemud.application.sdk.api.log.ThirdPartyLog;
import com.freemud.application.sdk.api.service.EmailAlertService;
import com.freemud.application.sdk.api.storecenter.response.StoreResponse;
import com.freemud.sdk.api.assortment.order.response.order.QueryOrderByIdResponse;
import com.google.common.base.Throwables;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

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

@Service("platformCouponRelationService")
public class PlatformCouponRelationServiceImpl implements CouponRelationService {

    @Autowired
    private CouponAdapter couponAdapter;
    @Autowired
    private CouponOfflineClient couponOfflineClient;
    @Autowired
    private EmailAlertService emailAlertService;
    @Autowired
    private StoreServiceImpl storeService;
    @Autowired
    private MQService mqService;

    private static final String ORDER_RESOURCE_PUSH_LOG_EXCHANGE = "order-resource-push-log-exchange";
    private static final String ORDER_RESOURCE_PUSH_LOG_ROUTING_KEY = "order-resource-push-log-routing-key";

    @Value("${baffleOpen.verification.coupon:false}")
    private Boolean baffleOpen = false;

    @Override
    public BaseResponse verificationCoupon(List<QueryOrdersResponseDto.DataBean.OrderBean.AccountBean> accountList, QueryOrdersResponseDto.DataBean.OrderBean orderBean, CouponReqType couponReqType) {
        AppLogUtil.infoLog("fiserhman 券码核销 begin", JSON.toJSONString(accountList), JSON.toJSONString(orderBean));
        if (CollectionUtils.isEmpty(accountList)) {
            return ResponseUtil.success();
        }
        // 需要判断 accountList 里面 是都 同时包含  配送券+ other券
        boolean isDoubleCoupon = checkAccountList(accountList);
        if (isDoubleCoupon) {
            Integer code = OrderAccountType.FREIGHT_COUPON.getCode();
            // 运费券 塞进 核销接口里面,  这里真的是贼恶心 逻辑不敢动
            QueryOrdersResponseDto.DataBean.OrderBean.AccountBean freightCouponAccountBean = accountList.stream().filter(accountBean -> code.equals(accountBean.getType())).findFirst().orElse(null);
            CouponCodeVerificationTransDto couponCodeVerificationTransDto = null;
            if (!Objects.isNull(freightCouponAccountBean)) {
                couponCodeVerificationTransDto = new CouponCodeVerificationTransDto();
                couponCodeVerificationTransDto.setCode(freightCouponAccountBean.getAccountId());
                couponCodeVerificationTransDto.setTotalAmount(freightCouponAccountBean.getPrice().intValue());
            }
            // 过滤出配送券
            List<QueryOrdersResponseDto.DataBean.OrderBean.AccountBean> collect = accountList.stream().filter(accountBean -> !code.equals(accountBean.getType())).collect(Collectors.toList());
            return commonMethodVerification(couponCodeVerificationTransDto, collect, orderBean, couponReqType);
        } else {
            return commonMethodVerification(null, accountList, orderBean, couponReqType);
        }
    }

    /**
     * 要校验一遍是否 使用了 需要核销的券 代金券 商品券 运费全 折扣券 需要核销
     *
     * @param accountList 这里会传递 多张券 和其他的计算 类型
     * @return
     */
    private boolean checkAccountList(List<QueryOrdersResponseDto.DataBean.OrderBean.AccountBean> accountList) {
        // 里面只有一个值 直接使用老逻辑  不管是 什么券
        if (accountList.size() == 1) {
            return false;
        }
        // 拿出 所有的使用券信息  代金券 商品券 运费全 折扣券 需要核销
        int count = 0;
        for (QueryOrdersResponseDto.DataBean.OrderBean.AccountBean accountBean : accountList) {
            if (OrderAccountType.verificationCoupon.contains(accountBean.getType())){
                count ++;
            }
        }
        // 说明使用了 2张以上的优惠券 需要核销
        return count > 1;
    }

    /**
     * 原有逻辑没变动的基础上  加上 配送券信息对象
     *
     * @param couponCodeVerificationTransDto 配送券信息对象 如果为null 就是原来的逻辑
     * @param accountList
     * @param orderBean
     * @param couponReqType
     */
    private BaseResponse commonMethodVerification(CouponCodeVerificationTransDto couponCodeVerificationTransDto, List<QueryOrdersResponseDto.DataBean.OrderBean.AccountBean> accountList, QueryOrdersResponseDto.DataBean.OrderBean orderBean, CouponReqType couponReqType) {
        for (QueryOrdersResponseDto.DataBean.OrderBean.AccountBean accountBean : accountList) {
            List<CouponCodeVerificationProductDto> products = new ArrayList<>();
            //商品券核销核销参数
            if (OrderAccountType.PRODUCT_COUPON.getCode().equals(accountBean.getType())) {
                for (int i = 0; i < orderBean.getProductList().size(); i++) {
                    QueryOrdersResponseDto.DataBean.OrderBean.ProductBean productBean = orderBean.getProductList().get(i);
                    String pid = StringUtils.isNotBlank(productBean.getSpecification()) ? productBean.getSpecification() : productBean.getProductId();
                    if (!org.springframework.util.CollectionUtils.isEmpty(orderBean.getProductList().get(i).getDiscountList())) {
                        List<QueryOrdersResponseDto.DataBean.OrderBean.ProductBean.ProductDiscount> discounts = orderBean.getProductList().get(i).getDiscountList().stream().
                                filter(productDiscount -> productDiscount.getDiscountId().equals(accountBean.getAccountId())).collect(Collectors.toList());
                        for (QueryOrdersResponseDto.DataBean.OrderBean.ProductBean.ProductDiscount productDiscount : discounts) {
                            if (productDiscount.getDiscountType() == null || productDiscount.getDiscountType() == 0) {
                                continue;
                            }
                            CouponCodeVerificationProductDto couponCodeVerificationProductDto = new CouponCodeVerificationProductDto();
                            couponCodeVerificationProductDto.setPID(pid);
                            couponCodeVerificationProductDto.setConsume_num(productDiscount.getDiscountQty());
                            couponCodeVerificationProductDto.setSeq(i + 1);
                            products.add(couponCodeVerificationProductDto);
                        }
                    }
                }
            }

            Integer orderType = orderBean.getType();
            //商城单子用NewOrderType
            if (Objects.equals(OrderSource.MALL.getSource(), orderBean.getSource())) {
                orderType = orderBean.getNewOrderType();
            }
            ActivityChannelEnum activityChannelEnum = PropertyConvertUtil.orderTypeEnumConvert2ActivityChannel(orderType);
            if (activityChannelEnum == null) {
                activityChannelEnum = ActivityChannelEnum.pickup;
            }

            // 核销优惠券 需要一起核销 配送券
            if (OrderAccountType.COUPON.getCode().equals(accountBean.getType())
                    || OrderAccountType.PRODUCT_COUPON.getCode().equals(accountBean.getType())
                    // 运费券
                    || OrderAccountType.FREIGHT_COUPON.getCode().equals(accountBean.getType())
                    || OrderAccountType.DISCOUNT_COUPON.getCode().equals(accountBean.getType())) {

                CouponCodeVerificationDto couponCodeVerificationDto = couponAdapter.convert2CouponCodeVerificationDto(activityChannelEnum,
                        // 这里是活动code
                        accountBean.getAccountId(), orderBean.getOid(), orderBean.getCompanyId(),
                        orderBean.getShopId(), orderBean.getUserId(), products, accountBean.getPrice().intValue(), couponReqType);

                couponCodeVerificationDto.setOrderTotalAmount(orderBean.getOriginalAmount() == null ? 0L : orderBean.getOriginalAmount().longValue());
                couponCodeVerificationDto.setOrderPaymentAmount(orderBean.getAmount());
                // KA 【ID1032412】【订单聚合层】核销传入优惠金额之传劵优惠只设置券的优惠金额进行上报
                couponCodeVerificationDto.setOrderDiscountAmount(Math.abs(accountBean.getPrice()));
                // 核销券新增参数：组织机构ID
                couponCodeVerificationDto.setChannel_ids(storeService.getOrgIdsArr(orderBean.getCompanyId(), orderBean.getShopId()));
                boolean ok = false;
                Exception lastException = null;
                CouponCodeResponseDto couponCodeResponseDto = null;
                // 设置配送券的 transactions
                if (couponCodeVerificationTransDto != null) {
                    List<CouponCodeVerificationTransDto> transactions = couponCodeVerificationDto.getTransactions();
                    transactions.add(couponCodeVerificationTransDto);
                    //只 传递一次, 防止后续开发 多张优惠券使用情况
                    couponCodeVerificationTransDto = null;
                }
                try {
                    //71.券核销
                    // todo 这循环有啥用-.-
                    for (int i = 2; i >= 0; i--) {
                        AppLogUtil.infoLog("核销券码开始==", JSON.toJSONString(couponCodeVerificationDto), null);
                        couponCodeResponseDto = couponOfflineClient.verification(couponCodeVerificationDto);
                        AppLogUtil.infoLog("核销券码返回==", JSON.toJSONString(couponCodeVerificationDto), JSON.toJSONString(couponCodeResponseDto));
                        ThirdPartyLog.infoConvertJson(System.currentTimeMillis(), System.currentTimeMillis(), "/api", couponCodeVerificationDto, couponCodeResponseDto);
                        if (Objects.nonNull(couponCodeResponseDto) && Objects.equals(couponCodeResponseDto.getStatusCode(), ResponseResult.SUCCESS.getCode())) {
                            ok = true;
                            AppLogUtil.infoLog("CouponReverseServiceImpl", JSON.toJSONString(couponCodeVerificationDto), JSON.toJSONString(couponCodeResponseDto));
                        }
                        break;
                    }

                } catch (Exception ex) {
                    lastException = ex;
                    ErrorLog.printErrorLog("verification_error", "/api", couponCodeVerificationDto, ex);
                }
                if (lastException != null) {
                    sendMessage(orderBean, LogThreadLocal.getTrackingNo(), couponCodeVerificationDto, lastException);
                } else if (!ok || Objects.equals(baffleOpen, true)) {
                    sendMessage(orderBean, LogThreadLocal.getTrackingNo(), couponCodeVerificationDto, ok ? "模拟券核销失败" : couponCodeResponseDto);
                }
                if (!ok) {
                    emailAlertService.sendEmailAlert("核销券码失败", String.format("request:%s \r\nresponse:%s", JSONObject.toJSONString(couponCodeVerificationDto), JSONObject.toJSONString(lastException == null ? couponCodeResponseDto : lastException)));
                    return ResponseUtil.error(ResponseResult.COUPON_VERIFICATION_FAIL);
                }
            }
        }
        return ResponseUtil.success();
    }


    /**
     * 发送消息
     *
     * @param orderBean
     */
    private void sendMessage(QueryOrdersResponseDto.DataBean.OrderBean orderBean, String trackingNo, Object req, Object failObject) {
        OrderResourcePushLogMsgDto dto = new OrderResourcePushLogMsgDto();
        try {
            String failureReasons;
            if (failObject instanceof String) {
                failureReasons = (String) failObject;
            } else if (failObject instanceof Throwable) {
                failureReasons = ((Throwable) failObject).getMessage();
            } else {
                failureReasons = JsonUtil.toJSONString(failObject);
            }
            if (failureReasons.length() > 255) {
                failureReasons = failureReasons.substring(0, 255);
            }
            dto.setTraceId(trackingNo);
            dto.setOrderCode(orderBean.getOid());
            dto.setPartnerId(orderBean.getCompanyId());
            dto.setStoreId(orderBean.getShopId());
            dto.setUserId(orderBean.getUserId());
            dto.setOptType(OrderResourcePushOptType.COUPON_VERIFICATION.getIndex());
            dto.setRequestDate(new Date());
            dto.setRequestBody(JsonUtil.toJSONString(req));
            dto.setFailureReasons(failureReasons);

            Header header = new Header(MQAction.INSERT.getAction(), "verificationCoupon", orderBean.getOid(), ORDER_RESOURCE_PUSH_LOG_ROUTING_KEY);
            MQMessage<OrderResourcePushLogMsgDto> message = new MQMessage<>(header, dto);
            mqService.convertAndSend(ORDER_RESOURCE_PUSH_LOG_EXCHANGE, ORDER_RESOURCE_PUSH_LOG_ROUTING_KEY, message);
        } catch (Exception e) {
            AppLogUtil.errorLog(trackingNo, "sendMessage COUPON_VERIFICATION error!!! routingKey = order-resource-push-log-routing-key", JSONObject.toJSONString(dto), null, e);
        }
    }
}
