/**
 * 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.enums.*;
import cn.freemud.service.coupon.CouponRelationService;
import cn.freemud.service.impl.StoreServiceImpl;
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.JSONObject;
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.ordercenter.entities.v1.AccountBeanV1;
import com.freemud.application.sdk.api.ordercenter.entities.v1.OrderBeanV1;
import com.freemud.application.sdk.api.ordercenter.entities.v1.ProductBeanV1;
import com.freemud.application.sdk.api.ordercenter.entities.v1.ProductDiscountV1;
import com.freemud.application.sdk.api.ordercenter.enums.BizTypeEnum;
import com.freemud.application.sdk.api.service.EmailAlertService;
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.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
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<AccountBeanV1> accountList, OrderBeanV1 orderBean, CouponReqType couponReqType) {
        if (CollectionUtils.isEmpty(accountList)) {
            return ResponseUtil.success();
        }
        // fisherman  【01测16灰18全，【华莱士】【疑难专项】一个订单多张优惠券使用场景】 https://www.tapd.cn/43862731/prong/stories/view/1143862731001037477
        BaseResponse baseResponse = this.batchCouponHandle(orderBean, couponReqType);
        return baseResponse;
    }

    /**
     * 要校验一遍是否 使用了 需要核销的券 代金券 商品券 运费全 折扣券 需要核销
     *
     * @param accountList 这里会传递 多张券 和其他的计算 类型
     * @return
     */
    private boolean checkAccountList(List<AccountBeanV1> accountList) {
        // 里面只有一个值 直接使用老逻辑  不管是 什么券
        if (accountList.size() == 1) {
            return false;
        }
        // 拿出 所有的使用券信息  代金券 商品券 运费全 折扣券 需要核销
        int count = 0;
        for (AccountBeanV1 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<AccountBeanV1> accountList, OrderBeanV1 orderBean, CouponReqType couponReqType) {

        //orderBean.getOrderClient();
        String couponChannel = CouponTradeChannelEnum.getCouponChannel(orderBean.getOrderClient());
        for (AccountBeanV1 accountBean : accountList) {
            List<CouponCodeVerificationProductDto> products = new ArrayList<>();
            //商品券核销核销参数
            if (OrderAccountType.PRODUCT_COUPON.getCode().equals(accountBean.getType())) {
                for (int i = 0; i < orderBean.getProductList().size(); i++) {
                    ProductBeanV1 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<ProductDiscountV1> discounts = orderBean.getProductList().get(i).getDiscountList().stream().
                                filter(productDiscount -> productDiscount.getDiscountId().equals(accountBean.getAccountId())).collect(Collectors.toList());
                        for (ProductDiscountV1 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);
                            couponCodeVerificationProductDto.setRedeem_price(new BigDecimal(productBean.getPrice()));
                            products.add(couponCodeVerificationProductDto);
                        }
                    }
                }
            }

            Integer orderType = orderBean.getOrderType();
            ActivityChannelEnum activityChannelEnum = PropertyConvertUtil.orderTypeEnumConvert2ActivityChannel(orderType);
            if (activityChannelEnum == null) {
                activityChannelEnum = ActivityChannelEnum.pickup;
            }
            //微商城单独处理
            if (Objects.equals(BizTypeEnum.MALL.getBizType(), orderBean.getBizType())) {
                activityChannelEnum = ActivityChannelEnum.saasmall;
            }
            // 核销优惠券 需要一起核销 配送券
            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()));
                couponCodeVerificationDto.setTradeNo(orderBean.getThirdPartTradeNo());
                couponCodeVerificationDto.setTradeChannel(couponChannel);

                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
     * @param couponReqType
     * @return
     */
    private BaseResponse batchCouponHandle(OrderBeanV1 orderBean, CouponReqType couponReqType) {
        CouponCodeVerificationDto couponCodeVerificationDto = couponAdapter.convert2CouponCodeVerificationDto(orderBean, couponReqType);
        if (Objects.isNull(couponCodeVerificationDto) || couponCodeVerificationDto.getTransactions().isEmpty()) {
            return ResponseUtil.success();
        }
        couponCodeVerificationDto.setOrderTotalAmount(orderBean.getOriginalAmount() == null ? 0L : orderBean.getOriginalAmount().longValue());
        couponCodeVerificationDto.setOrderPaymentAmount(orderBean.getAmount());

        // 核销券新增参数：组织机构ID
        couponCodeVerificationDto.setChannel_ids(storeService.getOrgIdsArr(orderBean.getCompanyId(), orderBean.getShopId()));
        boolean ok = false;
        Exception lastException = null;
        CouponCodeResponseDto couponCodeResponseDto = null;
        try {
            couponCodeResponseDto = couponOfflineClient.verification(couponCodeVerificationDto);
            ThirdPartyLog.infoConvertJson(System.currentTimeMillis(), System.currentTimeMillis(), "/api", couponCodeVerificationDto, couponCodeResponseDto);
            if (Objects.nonNull(couponCodeResponseDto) && Objects.equals(couponCodeResponseDto.getStatusCode(), ResponseResult.SUCCESS.getCode())) {
                ok = true;
            }
        } 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(OrderBeanV1 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( "sendMessage COUPON_VERIFICATION error!!! routingKey = order-resource-push-log-routing-key", JSONObject.toJSONString(dto), null, e);
        }
    }
}
