package cn.freemud.service.impl.calculate;

import cn.freemud.constant.ResponseCodeConstant;
import cn.freemud.entities.dto.ActivityCalculationDiscountResponseDto;
import cn.freemud.entities.dto.CheckSpqInfoRequestDto;
import cn.freemud.entities.dto.CheckSpqInfoResponseDto;
import cn.freemud.entities.dto.calculate.CalculationSharingDiscountRequestDto;
import cn.freemud.entities.dto.calculate.CalculationSharingDiscountResponseDto;
import cn.freemud.entities.dto.shoppingCart.SendPoint;
import cn.freemud.entities.vo.CartGoods;
import cn.freemud.entities.vo.ShoppingCartGoodsResponseVo;
import cn.freemud.entities.vo.ShoppingCartInfoRequestVo;
import cn.freemud.enums.*;
import cn.freemud.interceptor.BizServiceException;
import cn.freemud.interceptor.ServiceException;
import cn.freemud.service.CommonService;
import cn.freemud.service.CouponService;
import cn.freemud.service.active.ActiveFactory;
import cn.freemud.service.active.ActiveService;
import cn.freemud.service.impl.AssortmentSdkService;
import cn.freemud.service.impl.CouponServiceImpl;
import cn.freemud.service.impl.calculate.promotion.GiftSharingService;
import cn.freemud.service.thirdparty.CalculationClient;
import cn.freemud.utils.PropertyConvertUtil;
import com.alibaba.fastjson.JSON;
import com.freemud.application.sdk.api.log.ApiLog;
import com.freemud.application.sdk.api.log.ErrorLog;
import com.freemud.sdk.api.assortment.shoppingcart.constant.CommonsConstant;
import com.freemud.sdk.api.assortment.shoppingcart.enums.BusinessTypeEnum;
import com.freemud.sdk.api.assortment.shoppingcart.service.impl.ShoppingCartBaseServiceImpl;
import javafx.util.Pair;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang.ObjectUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

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

/**
 * All rights Reserved, Designed By www.freemud.cn
 *
 * @Title: cn.freemud.service.impl.calculate CalculationSharingDiscountServiceImpl
 * @Description: 对接促销新的算价服务
 * @author: family
 * @date: 2020/9/4
 * @Copyright: www.freemud.cn Inc. All rights reserved.
 * 注意：本内容仅限于上海非码科技内部传阅，禁止外泄以及用于其他的商业目
 */
@Service
public class CalculationSharingDiscountService {
    @Autowired
    private CouponService couponService;
    @Autowired
    private AssortmentSdkService assortmentSdkService;
    @Autowired
    private ShoppingCartBaseServiceImpl shoppingCartBaseService;
    @Autowired
    private CommonService commonService;
    @Autowired
    private CalculationClient calculationClient;

    @Autowired
    private ActiveFactory activeFactory;


    public CalculationSharingDiscountResponseDto.CalculationDiscountResult getCalculationSharingDiscountResult(String menuType
            , String partnerId
            , String storeId
            , String userId
            , String appId
            , Integer orderType
            , boolean isMember
            , List<CartGoods> cartGoodsList
            , List<CalculationSharingDiscountRequestDto.CalculationDiscountCoupon> coupons
            , List<ShoppingCartInfoRequestVo.SendGoods> sendGoodsList
            , Long deliveryAmount
            , ShoppingCartInfoRequestVo shoppingCartInfoRequestVo) {

        CalculationSharingDiscountRequestDto calculationSharingDiscountRequestDto = this.commonSharingDto(partnerId, storeId, userId, appId, orderType);

        // 校验后有效的商品券map
        HashMap<String, CheckSpqInfoResponseDto> validCouponMap = new HashMap<>(16);
        List<CalculationSharingDiscountRequestDto.CalculationDiscountGoods> calculationDiscountGoodsList = new ArrayList<>();
        int cartSize = cartGoodsList.size() - 1;
        HashMap<String, List<String>> spqIdToCartUuid = new HashMap<>(16);
        for (int i = cartSize; i >= 0; i--) {
            CartGoods cartGoods = cartGoodsList.get(i);
            if (StringUtils.isBlank(cartGoods.getCouponCode()) && !cartGoods.getCartGoodsUid().startsWith(CommonsConstant.COUPON_PREFIX)) {//非商品券
                this.setCommonDiscountGoods(calculationDiscountGoodsList,cartGoods);
            }
            else {//商品券->商品券ID换取商品
                String couponCode = cartGoods.getCouponCode();
                boolean useCoupon = true; // 优惠券放在coupon字段而不是uuid中
                if (cartGoods.getCartGoodsUid().startsWith(CommonsConstant.COUPON_PREFIX)){
                    couponCode = cartGoods.getCartGoodsUid().substring(CommonsConstant.COUPON_PREFIX.length());
                    useCoupon = false;
                }
                CheckSpqInfoRequestDto checkSpqInfoRequestDto = new CheckSpqInfoRequestDto(partnerId, storeId, couponCode, menuType);
                CheckSpqInfoResponseDto checkSpqInfo = null;
                if (GoodsTypeEnum.HG_COUPON_GOODS.getGoodsType().equals(cartGoods.getGoodsType())) {
                    checkSpqInfo = couponService.checkSpqInfo(checkSpqInfoRequestDto, cartGoods.getSkuId());
                    ApiLog.debug("coupon:{},{}", "hg", JSON.toJSONString(checkSpqInfo));
                } else {
                    checkSpqInfo = couponService.checkSpqInfo(checkSpqInfoRequestDto);
                    ApiLog.debug("coupon:{},{}", "sp", JSON.toJSONString(checkSpqInfo));
                }
                if (null == checkSpqInfo) {
                    cartGoodsList.remove(i);
                    assortmentSdkService.setShoppingCart(partnerId, storeId, userId, cartGoodsList, null, null, this.shoppingCartBaseService);
                    //跑业务异常 商品券不存
                } else {
                    if(useCoupon){
                        validCouponMap.put(couponCode + checkSpqInfo.getSkuId(), checkSpqInfo);
                    } else{
                        validCouponMap.put(couponCode, checkSpqInfo);
                    }
                    if (spqIdToCartUuid.containsKey(couponCode)){
                        List<String> uuidList = spqIdToCartUuid.get(couponCode);
                        uuidList.add(cartGoods.getCartGoodsUid());
                        spqIdToCartUuid.put(couponCode, uuidList);
                    } else {
                        List<String> uuidList = new ArrayList<>();
                        uuidList.add(cartGoods.getCartGoodsUid());
                        spqIdToCartUuid.put(couponCode, uuidList);
                    }
                    validCouponMap.put(couponCode, checkSpqInfo);
                    cartGoods.setName(checkSpqInfo.getCouponName());
                    cartGoods.setSpuName(checkSpqInfo.getCouponName());
                    cartGoods.setStockLimit(checkSpqInfo.isStockLimit());
                    CalculationSharingDiscountRequestDto.CalculationDiscountCoupon coupon = new CalculationSharingDiscountRequestDto.CalculationDiscountCoupon();
                    coupon.setCode(checkSpqInfo.getCouponCode());
                    coupon.setActivityCode(checkSpqInfo.getActiveCode());
                    CalculationSharingDiscountRequestDto.CalculationDiscountCoupon calculationDiscountCoupon = coupons.stream().filter(p -> coupon.getActivityCode().equals(p.getActivityCode()) && coupon.getCode().equals(p.getCode())).findFirst().orElse(null);
                    if (calculationDiscountCoupon == null){
                        coupons.add(coupon);
                    }
                    // 添加商品券代表的商品放入促销
                    String goodsId = StringUtils.isNotBlank(checkSpqInfo.getSkuId()) ? checkSpqInfo.getSkuId() : checkSpqInfo.getSpuId();
                    if (GoodsTypeEnum.HG_COUPON_GOODS.getGoodsType().equals(cartGoods.getGoodsType())) {
                        this.setSpqDiscountGoods(calculationDiscountGoodsList, cartGoods, goodsId, checkSpqInfo.getPrice(), cartGoods.getSpuId());
                    } else {
                        this.setSpqDiscountGoods(calculationDiscountGoodsList, cartGoods, goodsId, checkSpqInfo.getPrice());
                    }
                }
            }

            if (GoodsTypeEnum.SET_MEAL_GOODS.getGoodsType().equals(cartGoods.getGoodsType())) {
                if (CollectionUtils.isEmpty(cartGoods.getProductGroupList()) && CollectionUtils.isEmpty(cartGoods.getProductComboList())) {
                    cartGoodsList.remove(i);
                    assortmentSdkService.setShoppingCart(partnerId, storeId, userId, cartGoodsList, null, null, this.shoppingCartBaseService);
                    throw new ServiceException(ResponseResult.SHOPPING_CART_NO_MEAL);
                }
            }
        }

        /*加价购商品不为空*/
        if (CollectionUtils.isNotEmpty(sendGoodsList)) {
            String activityCode = "";
            List<CalculationSharingDiscountRequestDto.CalculationSendGoodsReqVO> sends = new ArrayList<>();
            List<CalculationSharingDiscountRequestDto.CalculationActivityReqVO> selectActivityLists = new ArrayList<>();
            CalculationSharingDiscountRequestDto.CalculationActivityReqVO calculationActivityReqVO = new CalculationSharingDiscountRequestDto.CalculationActivityReqVO();
            for (ShoppingCartInfoRequestVo.SendGoods send : sendGoodsList) {
                CalculationSharingDiscountRequestDto.CalculationSendGoodsReqVO reqs = new CalculationSharingDiscountRequestDto.CalculationSendGoodsReqVO();
                reqs.setGoodsId(send.getGoodsId());
                reqs.setGoodsQuantity(send.getQty());
                reqs.setOriginalPrice(send.getOriginalPrice().intValue());
                reqs.setNowPrice(send.getOriginalPrice().intValue());
                sends.add(reqs);
                activityCode = send.getActivityCode();
            }
            calculationActivityReqVO.setActivityCode(activityCode);
            calculationActivityReqVO.setSendGoods(sends);
            selectActivityLists.add(calculationActivityReqVO);
            calculationSharingDiscountRequestDto.setSelectActivityList(selectActivityLists);
        }

        //剔除商品数量为空的
        calculationDiscountGoodsList.removeIf(v->v.getGoodsQuantity().equals(0));
        if (CollectionUtils.isEmpty(calculationDiscountGoodsList)) {
            ApiLog.debug("calculationDiscountGoodsList:{}", JSON.toJSON(calculationDiscountGoodsList));
            //throw new BizServiceException(ResponseResult.SHOPPING_CART_COUPON_NOT_EXIST,"参数促销计算商品有异常");
            return null;
        }

        //组装促销
        calculationSharingDiscountRequestDto.setGoods(calculationDiscountGoodsList);
        calculationSharingDiscountRequestDto.setCoupons(coupons);
        calculationSharingDiscountRequestDto.setOrgIds(commonService.getOrgIdsForCoupon(partnerId,storeId));
        calculationSharingDiscountRequestDto.setDistributionFee(deliveryAmount);
        calculationSharingDiscountRequestDto.setIsMember(isMember);
        CalculationSharingDiscountResponseDto sharingDiscountResponseDto;
        // 构建买一送一寄杯活动用户选择信息
        ActiveService activeService = activeFactory.getBuildChooseGoodsService(partnerId);
        activeService.buildChooseGoodsService(calculationSharingDiscountRequestDto,shoppingCartInfoRequestVo == null ? null : shoppingCartInfoRequestVo.getChooseGoods());
        try {
            sharingDiscountResponseDto = calculationClient.calculationSharingDiscount(calculationSharingDiscountRequestDto);
        }
        catch (Exception e) {
            ErrorLog.printErrorLog("calculation_discount_error", "/calculation/discount/sharing", calculationSharingDiscountRequestDto, e);
            throw new ServiceException(ResponseResult.OPERATE_TOO_OFTEN);
        }
        // 返回成功
        if (sharingDiscountResponseDto != null && StringUtils.equals(sharingDiscountResponseDto.getStatusCode(), ResponseCodeConstant.RESPONSE_SUCCESS_STR)) {
            CalculationSharingDiscountResponseDto.CalculationDiscountResult result = sharingDiscountResponseDto.getResult();

            List<Integer> activityTypes = result.getDiscounts().stream().map(CalculationSharingDiscountResponseDto.CalculationDiscountResult.Discount::getType).collect(Collectors.toList());
            if (activityTypes.contains(221)) {
                CalculationSharingDiscountResponseDto.CalculationDiscountResult.Discount discountDTO = result.getDiscounts().stream().filter(d -> 221 == d.getType()).findFirst().get();
                convert2SendPoint(result, discountDTO);
            }

            result.setValidCouponMap(validCouponMap);
            result.setSpqIdToCartUuid(spqIdToCartUuid);
            // fisherman  这里传递过来的 配送费 是否要计算一下 配送券的逻辑
            result.setDeliveryAmount(deliveryAmount);
            result.setDistributionFee(result.getDistributionFee());
            return result;
        }

        // 这个是专门给coco使用的券验证错误的异常，message要抛出去
        if(sharingDiscountResponseDto != null && StringUtils.equals(sharingDiscountResponseDto.getStatusCode(), ResponseCodeConstant.COCO_RESPONSE_COUPON_ERR_STR)){
            throw new BizServiceException(ResponseResult.COCO_COUPON_VALIDATOR_FAIL,sharingDiscountResponseDto.getMsg());
        }

        // 支付宝华莱士紧急修改代码，当促销返回103错误码时，需要报券不适用于该门店，且清空购物车
        //throw new ServiceException(ResponseResult.OPERATE_TOO_OFTEN);
        return null;
    }

    private void convert2SendPoint(CalculationSharingDiscountResponseDto.CalculationDiscountResult result, CalculationSharingDiscountResponseDto.CalculationDiscountResult.Discount discountDTO) {
        SendPoint sendPointNew = new SendPoint();

        CalculationSharingDiscountResponseDto.CalculationDiscountResult.SendPointDto sendPointVo = discountDTO.getSendPointVo();
        if (sendPointVo != null) {
            sendPointNew.setMaxNum(sendPointVo.getMaxNum());
            sendPointNew.setSendPoint(sendPointVo.getSendPoint());
            sendPointNew.setValidityDateDays(sendPointVo.getValidityDateDays());
            sendPointNew.setActivityCode(discountDTO.getActivityCode());
            sendPointNew.setEndTime(discountDTO.getEndTime());
            sendPointNew.setStoreLevel(sendPointVo.getStoreLevel());
            result.setSendPointVo(sendPointNew);
        }

    }

    /**
     * 实物商品
     * @param calculationDiscountGoodsList
     * @param cartGoods
     */
    private void setCommonDiscountGoods(List<CalculationSharingDiscountRequestDto.CalculationDiscountGoods> calculationDiscountGoodsList
            , CartGoods cartGoods) {

        CalculationSharingDiscountRequestDto.CalculationDiscountGoods calculationDiscountGoods = new CalculationSharingDiscountRequestDto.CalculationDiscountGoods();
        calculationDiscountGoods.setGoodsId(cartGoods.getGoodsId());
        calculationDiscountGoods.setCartGoodsUid(cartGoods.getCartGoodsUid());
        calculationDiscountGoods.setGoodsQuantity(cartGoods.getQty());
        calculationDiscountGoods.setAddCartTime(cartGoods.getAddCartTime() == null ? 0 : cartGoods.getAddCartTime());
        //if (cartGoods.getGoodsType().equals(GoodsTypeEnum.SET_MEAL_GOODS))
        if (CollectionUtils.isNotEmpty(cartGoods.getProductGroupList()) || CollectionUtils.isNotEmpty(cartGoods.getProductComboList())) {
            calculationDiscountGoods.setOriginalPrice(cartGoods.getFinalPrice()!=null ? cartGoods.getFinalPrice() : cartGoods.getOriginalPrice());
        }
        else {
            calculationDiscountGoods.setOriginalPrice(cartGoods.getOriginalPrice());
        }
        calculationDiscountGoods.setMemberDiscount(cartGoods.getMemberDiscount());
        calculationDiscountGoods.setSpuId(cartGoods.getSpuId());
        //商品加料
        if (CollectionUtils.isNotEmpty(cartGoods.getProductMaterialList())) {
            ArrayList<CalculationSharingDiscountRequestDto.CalculationDiscountGoods.Material> materials = new ArrayList<>();
            for (CartGoods.MaterialGoods materialGoods : cartGoods.getProductMaterialList()) {
                CalculationSharingDiscountRequestDto.CalculationDiscountGoods.Material material = new CalculationSharingDiscountRequestDto.CalculationDiscountGoods.Material();
                material.setType(1);
                material.setGoodsId(materialGoods.getSpuId());
                material.setGoodsQuantity(materialGoods.getQty());
                material.setOriginalPrice(materialGoods.getFinalPrice());
                materials.add(material);
            }
            calculationDiscountGoods.setSmallMaterial(materials);
        }
        //商品组或是套餐或是固定搭配
        if (CollectionUtils.isNotEmpty(cartGoods.getProductComboList())) {
            ArrayList<CalculationSharingDiscountRequestDto.CalculationDiscountGoods.GroupCombox> groupBoxes = new ArrayList<>();
            for (CartGoods.ComboxGoods boxes : cartGoods.getProductComboList()) {
                CalculationSharingDiscountRequestDto.CalculationDiscountGoods.GroupCombox combo = new CalculationSharingDiscountRequestDto.CalculationDiscountGoods.GroupCombox();
                combo.setGoodsId(boxes.getGoodsId());
                combo.setGoodsQuantity(boxes.getQty());
                combo.setOriginalPrice(boxes.getOriginalPrice().intValue());
                groupBoxes.add(combo);
            }
            calculationDiscountGoods.setMeal(true);
            calculationDiscountGoods.setGroupCombox(groupBoxes);
            calculationDiscountGoods.setOriginalPrice(cartGoods.getFinalPrice());
        }

        //可选搭配
        if (CollectionUtils.isNotEmpty(cartGoods.getProductGroupList())) {
            ArrayList<CalculationSharingDiscountRequestDto.CalculationDiscountGoods.Material> groups = new ArrayList<>();
            for (CartGoods.ComboxGoods group : cartGoods.getProductGroupList()) {
                CalculationSharingDiscountRequestDto.CalculationDiscountGoods.Material material = new CalculationSharingDiscountRequestDto.CalculationDiscountGoods.Material();
                material.setType(2);
                material.setGoodsId(group.getGoodsId());
                material.setGoodsQuantity(group.getQty());
                material.setOriginalPrice(group.getFinalPrice());
                groups.add(material);
            }
            calculationDiscountGoods.setSmallMaterial(groups);
        }

        calculationDiscountGoodsList.add(calculationDiscountGoods);
    }

    /**
     * 组队券码商品
     * @param calculationDiscountGoodsList
     * @param cartGoods
     * @param goodsId
     * @param originalPrice
     */
    private void setSpqDiscountGoods(List<CalculationSharingDiscountRequestDto.CalculationDiscountGoods> calculationDiscountGoodsList
            , CartGoods cartGoods, String goodsId, Long originalPrice) {
        CalculationSharingDiscountRequestDto.CalculationDiscountGoods calculationDiscountGoods = new CalculationSharingDiscountRequestDto.CalculationDiscountGoods();
        calculationDiscountGoods.setGoodsId(goodsId);
        calculationDiscountGoods.setCartGoodsUid(cartGoods.getCartGoodsUid());
        calculationDiscountGoods.setAddCartTime(cartGoods.getAddCartTime() == null ? 0 : cartGoods.getAddCartTime());
        calculationDiscountGoods.setGoodsQuantity(cartGoods.getQty());
        calculationDiscountGoods.setOriginalPrice(originalPrice);
        calculationDiscountGoods.setMemberDiscount(100);
        this.setCalculationDiscountGoods(calculationDiscountGoodsList,calculationDiscountGoods);
    }
    private void setSpqDiscountGoods(List<CalculationSharingDiscountRequestDto.CalculationDiscountGoods> calculationDiscountGoodsList
            , CartGoods cartGoods
            , String goodsId
            , Long originalPrice
            ,String couponCode) {
        CalculationSharingDiscountRequestDto.CalculationDiscountGoods calculationDiscountGoods = new CalculationSharingDiscountRequestDto.CalculationDiscountGoods();
        calculationDiscountGoods.setGoodsId(goodsId);
        calculationDiscountGoods.setCartGoodsUid(cartGoods.getCartGoodsUid());
        calculationDiscountGoods.setAddCartTime(cartGoods.getAddCartTime() == null ? 0 : cartGoods.getAddCartTime());
        calculationDiscountGoods.setGoodsQuantity(cartGoods.getQty());
        calculationDiscountGoods.setOriginalPrice(originalPrice);
        calculationDiscountGoods.setMemberDiscount(100);
        calculationDiscountGoods.setCouponCode(couponCode);
        this.setCalculationDiscountGoods(calculationDiscountGoodsList,calculationDiscountGoods);
    }

    /**
     * 需要促销计算的商品
     * @param calculationDiscountGoodsList
     * @param calculationDiscountGoods
     */
    private void setCalculationDiscountGoods(List<CalculationSharingDiscountRequestDto.CalculationDiscountGoods> calculationDiscountGoodsList
            ,CalculationSharingDiscountRequestDto.CalculationDiscountGoods calculationDiscountGoods) {
        int index = 0;
        //当商品已经存在时，需要累加数量
        if ((index = calculationDiscountGoodsList.indexOf(calculationDiscountGoods))>=0) {
            CalculationSharingDiscountRequestDto.CalculationDiscountGoods old = calculationDiscountGoodsList.get(index);
            calculationDiscountGoodsList.get(index).setGoodsQuantity(old.getGoodsQuantity()+calculationDiscountGoods.getGoodsQuantity());
        }
        else {
            calculationDiscountGoodsList.add(calculationDiscountGoods);
        }

    }

    /**
     * 公共DTO头
     *
     * @param partnerId
     * @param storeId
     * @param userId
     * @param appId
     * @param orderType
     * @return
     */
    private CalculationSharingDiscountRequestDto commonSharingDto(String partnerId, String storeId, String userId, String appId, Integer orderType) {
        CalculationSharingDiscountRequestDto calculationSharingDiscountRequestDto = new CalculationSharingDiscountRequestDto();

        calculationSharingDiscountRequestDto.setPartnerCode(partnerId);
        calculationSharingDiscountRequestDto.setStoreId(storeId);
        calculationSharingDiscountRequestDto.setIsShowGoodsActivity(1);
        calculationSharingDiscountRequestDto.setUserId(userId);
        calculationSharingDiscountRequestDto.setAppId(appId);
        calculationSharingDiscountRequestDto.setVer(1);
        calculationSharingDiscountRequestDto.setSelectActivityList(new ArrayList<>());
        ActivityChannelEnum activityChannelEnum = PropertyConvertUtil.orderTypeConvert2ActivityChannel(orderType);
        if (!Objects.isNull(activityChannelEnum)) {
            calculationSharingDiscountRequestDto.setChannel(activityChannelEnum.getCode());
        }

        //==========================  购物车查询特有逻辑  =================================
        // 到店自取包装费设为null,外卖要计算包装费，flag为1表示去结算
        // 兼容老版本判断null
        if (Objects.equals(orderType, CreateOrderType.COLLECT_GOODS.getCode())) {
            calculationSharingDiscountRequestDto.setProductChannel(BusinessTypeEnum.SAAS_PICKUP.getCode());
        } else if (Objects.equals(orderType, CreateOrderType.TAKE_OUT.getCode())) {
            calculationSharingDiscountRequestDto.setProductChannel(BusinessTypeEnum.SAAS_DELIVERY.getCode());
        }
        return calculationSharingDiscountRequestDto;
    }
}
