/**
 * All rights Reserved, Designed By www.freemud.cn
 *
 * @Title: CocoOrderRelationServiceImpl
 * @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.base.constant.Version;
import cn.freemud.base.entity.BaseResponse;
import cn.freemud.base.util.DateUtil;
import cn.freemud.entities.dto.*;
import cn.freemud.enums.ActivityChannelEnum;
import cn.freemud.enums.CouponReqType;
import cn.freemud.enums.OrderAccountType;
import cn.freemud.enums.ResponseResult;
import cn.freemud.service.coupon.CouponRelationService;
import cn.freemud.service.impl.StoreServiceImpl;
import cn.freemud.service.thirdparty.CouponOfflineClient;
import cn.freemud.utils.LogUtil;
import cn.freemud.utils.PropertyConvertUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.freemud.application.sdk.api.log.ApiLog;
import com.freemud.application.sdk.api.log.ErrorLog;
import com.freemud.application.sdk.api.log.ThirdPartyLog;
import com.freemud.application.sdk.api.ordercenter.response.orderInfo.OrderSettlementResp;
import com.freemud.application.sdk.api.service.EmailAlertService;
import com.freemud.sdk.api.assortment.order.adapter.OrderSdkAdapter;
import com.google.common.base.Throwables;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import cn.freemud.utils.ResponseUtil;

import java.math.BigDecimal;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service("cocoCouponRelationService")
@Slf4j
public class CocoCouponRelationServiceImpl implements CouponRelationService {

    @Autowired
    private CouponAdapter couponAdapter;
    @Autowired
    private CouponOfflineClient couponOfflineClient;
    @Autowired
    private EmailAlertService emailAlertService;
    @Autowired
    private StoreServiceImpl storeService;
    @Autowired
    private OrderSdkAdapter orderSdkAdapter;


    @Override
    public BaseResponse verificationCoupon(List<QueryOrdersResponseDto.DataBean.OrderBean.AccountBean> accountList,
                                           QueryOrdersResponseDto.DataBean.OrderBean orderBean,
                                           CouponReqType couponReqType) {

        log.info("coco订单核销优惠券,orderBean:{}",JSONObject.toJSONString(orderBean));

        // 订单商品信息
        List<QueryOrdersResponseDto.DataBean.OrderBean.ProductBean> productList = orderBean.getProductList();
        if(CollectionUtils.isEmpty(orderBean.getProductList())){
            ApiLog.info("coco订单没有商品信息不用核销优惠券",orderBean.getOid(),"");
            return ResponseUtil.success();
        }

        // 订单促销信息
        List<OrderSettlementResp> orderSettlementList = orderBean.getOrderSettlementDetailList();
        if (CollectionUtils.isEmpty(orderSettlementList)) {
            ApiLog.info("coco订单没有促销信息不用核销优惠券",orderBean.getOid(),"");
            return ResponseUtil.success();
        }

        // 根据商品id转map
        Map<String,QueryOrdersResponseDto.DataBean.OrderBean.ProductBean> productMap = new HashMap<>();
        for(QueryOrdersResponseDto.DataBean.OrderBean.ProductBean pb : productList){
            productMap.put(pb.getSpecification(),pb);
            List<QueryOrdersResponseDto.DataBean.OrderBean.ProductBean> materialProducts = pb.getMaterialProduct();
            if(materialProducts != null && !materialProducts.isEmpty()){
                for(QueryOrdersResponseDto.DataBean.OrderBean.ProductBean materialProduct : materialProducts){
                    productMap.put(materialProduct.getSpecification(),materialProduct);
                }
            }
        }

        log.info("coco订单核销优惠券,orderCode:{},productMap:{}",orderBean.getOid(),JSONObject.toJSONString(productMap));

        // 根据活动号分组，没有活动号的直接筛选掉
        Map<String,List<OrderSettlementResp>> orderSettlementMap = orderSettlementList.stream().filter(os -> StringUtils.isNotEmpty(os.getExternalObjectId()))
                .collect(Collectors.groupingBy(OrderSettlementResp::getExternalObjectId));

        Integer orderType = orderBean.getType();
        ActivityChannelEnum activityChannelEnum = PropertyConvertUtil.orderTypeEnumConvert2ActivityChannel(orderType);
        if (activityChannelEnum == null) {
            activityChannelEnum = ActivityChannelEnum.pickup;
        }

        // 核销主体信息
        CouponCodeVerificationDto couponCodeVerificationDto = new CouponCodeVerificationDto();
        couponCodeVerificationDto.setVer(Integer.valueOf(Version.VERSION_1));
        couponCodeVerificationDto.setReqtype(couponReqType.getCode());
        couponCodeVerificationDto.setPartnerId(orderBean.getCompanyId());
        couponCodeVerificationDto.setChannel(activityChannelEnum.getCode());
        couponCodeVerificationDto.setStation_id("-1");
        couponCodeVerificationDto.setOperator_id("-1");
        couponCodeVerificationDto.setStore_id(orderBean.getShopId());
        couponCodeVerificationDto.setMemberId(orderBean.getUserId());
        // 订单号 替换成唯一序号
        couponCodeVerificationDto.setTrans_id(orderBean.getOid());
        couponCodeVerificationDto.setBusiness_date(DateUtil.convert2Str(new Date(), DateUtil.FORMAT_yyyyMMdd));
        // 核销券新增参数：组织机构ID
        couponCodeVerificationDto.setChannel_codes(storeService.getOrgIdsArr(orderBean.getCompanyId(), orderBean.getShopId()));

        // 核销交易信息
        List<CouponCodeVerificationTransDto> transactions = new ArrayList<>();

        // 保存没有商品code的用券信息，主要是整单代金券
        List<OrderSettlementResp>  orderSettlementRemain = new ArrayList<>();
        // 已经计算过的促销商品优惠信息
        List<OrderSettlementResp> orderSettlementAlready = new ArrayList<>();
        log.info("coco订单核销优惠券,orderCode:{},orderSettlementMap:{}",orderBean.getOid(),JSONObject.toJSONString(orderSettlementMap));
        for (Map.Entry<String,List<OrderSettlementResp>> m : orderSettlementMap.entrySet()) {

            // 活动相应的促销明细
            List<OrderSettlementResp> orderSettlementInfo = m.getValue();
            if(orderSettlementInfo == null || orderSettlementInfo.isEmpty()){
                continue;
            }

            // 活动类型
            Integer settlementType = orderSettlementInfo.get(0).getSettlementType();
            // 券号
            String couponCode = orderSettlementInfo.get(0).getExternalObjectId();

            // 根据活动号转类型
            Integer orderAccountType = orderSdkAdapter.getOldOrderAccountType(settlementType);


            // 不是商品券、代金券、折扣券、商品代金券不处理
            if(!OrderAccountType.COCO_PRODUCT_CASH_COUPON.getCode().equals(orderAccountType) &&
                    !OrderAccountType.COUPON.getCode().equals(orderAccountType) &&
                    !OrderAccountType.PRODUCT_COUPON.getCode().equals(orderAccountType) &&
                    !OrderAccountType.DISCOUNT_COUPON.getCode().equals(orderAccountType)){
                continue;
            }

            if(OrderAccountType.COUPON.getCode().equals(orderAccountType) && "0".equals(orderSettlementInfo.get(0).getProductId())){
                // 整单代金券，最后在计算
                orderSettlementRemain.add(orderSettlementInfo.get(0));
            }

            CouponCodeVerificationTransDto couponCodeVerificationTransDto = new CouponCodeVerificationTransDto();
            // 券号
            couponCodeVerificationTransDto.setCode(couponCode);

            Integer totalAmount = 0;
            Integer oriAmount = 0;
            List<CouponCodeVerificationProductDto> products = new ArrayList<>();
            for(OrderSettlementResp osr : orderSettlementInfo){
                // 优惠金额大于0,此时取得是具体的商品优惠信息
                if(osr.getSettlementAmount() != null && osr.getSettlementAmount().compareTo(new BigDecimal(0)) == 1){
                    totalAmount = totalAmount + (osr.getSettlementAmount() == null ? 0 : osr.getSettlementAmount().intValue());
                }

                // 商品code不为0,此时取得是具体的商品
                if(!"0".equals(osr.getProductId())){
                    // 计算商品原价
                    Integer num = osr.getNumber();
                    String productId = osr.getProductId();
                    QueryOrdersResponseDto.DataBean.OrderBean.ProductBean pb = productMap.get(productId);
                    if(pb == null){
                        continue;
                    }

                    oriAmount = oriAmount + (pb.getPrice() == null ? 0 : pb.getPrice().intValue()) * (num == null ? 0 : num);

                    orderSettlementAlready.add(osr);
                    // 统计商品
                    CouponCodeVerificationProductDto couponCodeVerificationProductDto = new CouponCodeVerificationProductDto();
                    couponCodeVerificationProductDto.setConsume_num(num);
                    couponCodeVerificationProductDto.setPID(osr.getProductId());
                    couponCodeVerificationProductDto.setSeq(osr.getProductSeq());
                    couponCodeVerificationProductDto.setProductName(pb.getProductName());

                    Integer price = pb.getPrice() == null ? 0 : pb.getPrice().intValue();
                    couponCodeVerificationProductDto.setInitPrice(price);
                    couponCodeVerificationProductDto.setNowPrice(price);
                    couponCodeVerificationProductDto.setPayMoney(price);

                    products.add(couponCodeVerificationProductDto);
                }

            }
            couponCodeVerificationTransDto.setProducts(products);
            //处理第三方外卖单优惠金额信息
            if(totalAmount != null && totalAmount.intValue() > 0){
                totalAmount = 0 - Math.abs(totalAmount);
            }

            // 总优惠金额单位：分
            couponCodeVerificationTransDto.setTotalAmount(totalAmount);
            // 订单号
            couponCodeVerificationTransDto.setOrderNumber(orderBean.getOid());

            // 应收金额
            couponCodeVerificationTransDto.setAmountRec(oriAmount);
            // 实收金额
            couponCodeVerificationTransDto.setAmountPaid(oriAmount);
            transactions.add(couponCodeVerificationTransDto);

        }

        // 带有商品的券，计算完之后，要计算整单的优惠券，
        // 整单的商品减掉单品优惠后的剩下的就都是整单券的商品
        log.info("coco订单核销优惠券,orderCode:{},orderSettlementRemain:{}",orderBean.getOid(),JSONObject.toJSONString(orderSettlementRemain));
        if(!orderSettlementRemain.isEmpty()){

            Map<String, IntSummaryStatistics> collect = orderSettlementAlready.stream().collect(Collectors.groupingBy(OrderSettlementResp::getProductId, Collectors.summarizingInt(OrderSettlementResp::getNumber)));
            log.info("coco订单核销优惠券,orderCode:{},collect:{}",orderBean.getOid(),JSONObject.toJSONString(collect));
            for(OrderSettlementResp osr: orderSettlementRemain){
                CouponCodeVerificationTransDto couponCodeVerificationTransFull = new CouponCodeVerificationTransDto();
                // 券号
                couponCodeVerificationTransFull.setCode(osr.getExternalObjectId());
                // 总优惠金额单位：分
                couponCodeVerificationTransFull.setTotalAmount(0 - osr.getSettlementAmount().intValue());
                // 订单号
                couponCodeVerificationTransFull.setOrderNumber(orderBean.getOid());
                List<CouponCodeVerificationProductDto> productsFull = new ArrayList<>();
                Integer totalAmountOriFull = 0;
                for(QueryOrdersResponseDto.DataBean.OrderBean.ProductBean pb : productList){

                    totalAmountOriFull = buidVerificationProduct(collect,osr,pb,productsFull,totalAmountOriFull);
                    // 小料商品也取出来
                    List<QueryOrdersResponseDto.DataBean.OrderBean.ProductBean> materialProducts = pb.getMaterialProduct();
                    if(materialProducts != null && !materialProducts.isEmpty()){
                        for(QueryOrdersResponseDto.DataBean.OrderBean.ProductBean materialProduct : materialProducts){
                            totalAmountOriFull = buidVerificationProduct(collect,osr,materialProduct,productsFull,totalAmountOriFull);
                        }
                    }
                }

                couponCodeVerificationTransFull.setProducts(productsFull);
                couponCodeVerificationTransFull.setAmountPaid(totalAmountOriFull);
                couponCodeVerificationTransFull.setAmountRec(totalAmountOriFull);
                transactions.add(couponCodeVerificationTransFull);
            }

        }

        couponCodeVerificationDto.setTransactions(transactions);

        try {
            //71.券核销
            for (int i = 2; i >= 0; i--) {
                log.info("coco核销券码开始==", JSON.toJSONString(couponCodeVerificationDto), null);
                CouponCodeResponseDto couponCodeResponseDto = couponOfflineClient.verification(couponCodeVerificationDto);
                log.info("coco核销券码返回==", JSON.toJSONString(couponCodeResponseDto), null);
                ThirdPartyLog.infoConvertJson(System.currentTimeMillis(), System.currentTimeMillis(), "/api", couponCodeVerificationDto, couponCodeResponseDto);
                if (Objects.equals(couponCodeResponseDto.getStatusCode(), ResponseResult.SUCCESS.getCode())) {
                    LogUtil.info("coco 核销券码返回成功，couponCodeVerificationDto：{},couponCodeResponseDto，", JSON.toJSONString(couponCodeVerificationDto), JSON.toJSONString(couponCodeResponseDto));
                    break;
                }
                if (!Objects.equals(couponCodeResponseDto.getStatusCode(), ResponseResult.SUCCESS.getCode())) {
                    emailAlertService.sendEmailAlert("cooc核销券码失败", String.format("request:%s \r\nresponse:%s", JSONObject.toJSONString(couponCodeVerificationDto), JSONObject.toJSONString(couponCodeResponseDto)));
                    LogUtil.info("coco 核销券码返回失败，couponCodeVerificationDto：{},couponCodeResponseDto，", JSON.toJSONString(couponCodeVerificationDto), JSON.toJSONString(couponCodeResponseDto));
                    return ResponseUtil.error(ResponseResult.COUPON_VERIFICATION_FAIL);
                }
            }

        } catch (Exception ex) {
            emailAlertService.sendEmailAlert("coco核销券码异常", String.format("request:%s \r\nexception:%s", JSONObject.toJSONString(couponCodeVerificationDto), Throwables.getStackTraceAsString(ex)));
            ErrorLog.printErrorLog("coco verification_error", "/api", couponCodeVerificationDto, ex);
            return ResponseUtil.error(ResponseResult.COUPON_VERIFICATION_FAIL);
        }


        return ResponseUtil.success();
    }

    /**
     * 构建整单券的商品
     * @param collect
     * @param osr
     * @param pb
     * @param productsFull
     * @param totalAmountOriFull
     * @return
     */
    public Integer buidVerificationProduct(Map<String, IntSummaryStatistics> collect,
                                        OrderSettlementResp osr,
                                        QueryOrdersResponseDto.DataBean.OrderBean.ProductBean pb,
                                        List<CouponCodeVerificationProductDto> productsFull,
                                        Integer totalAmountOriFull){
        Long alreadyNum = collect.get(pb.getProductId()) == null ? 0L : collect.get(pb.getProductId()).getSum();
        Integer num = pb.getNumber();
        Integer remainNum = num - alreadyNum.intValue();
        if(Objects.equals(remainNum,0)){
            return totalAmountOriFull;
        }

        // 统计商品
        CouponCodeVerificationProductDto couponCodeVerificationProductFull = new CouponCodeVerificationProductDto();
        couponCodeVerificationProductFull.setConsume_num(remainNum);
        couponCodeVerificationProductFull.setPID(pb.getProductId());
        couponCodeVerificationProductFull.setSeq(pb.getSequence());
        couponCodeVerificationProductFull.setProductName(pb.getProductName());

        Integer price = pb.getPrice() == null ? 0 : pb.getPrice().intValue();
        couponCodeVerificationProductFull.setInitPrice(price);
        couponCodeVerificationProductFull.setNowPrice(price);
        couponCodeVerificationProductFull.setPayMoney(price);

        productsFull.add(couponCodeVerificationProductFull);

        totalAmountOriFull = totalAmountOriFull + price * remainNum;
        return totalAmountOriFull;
    }
}
