package cn.freemud.demo.service.impl;

import cn.freemud.adapter.ActivityAdapter;
import cn.freemud.base.entity.BaseResponse;
import cn.freemud.demo.entities.bo.promotion.GetActivityBO;
import cn.freemud.demo.constant.ResponseConstant;
import cn.freemud.demo.entities.bo.goods.ShoppingCartGoodsBO;
import cn.freemud.demo.entities.bo.coupon.GetCouponDetailBO;
import cn.freemud.demo.entities.bo.goods.*;
import cn.freemud.demo.entities.bo.goods.update.UpdateAddGoodsBO;
import cn.freemud.demo.entities.bo.member.CustomerInfo;
import cn.freemud.demo.entities.bo.product.GetProductBySkuIdBO;
import cn.freemud.demo.entities.bo.product.GetProductStock;
import cn.freemud.demo.entities.bo.product.ProductStockBO;
import cn.freemud.demo.entities.bo.promotion.ActivityBO;
import cn.freemud.demo.manager.coupon.CouponManager;
import cn.freemud.demo.manager.customer.CustomerManager;
import cn.freemud.demo.manager.product.ProductManager;
import cn.freemud.demo.manager.promotion.PromotionManager;
import cn.freemud.demo.service.DistributeService;
import cn.freemud.demo.service.MessageService;
import cn.freemud.demo.service.UpdateGoodsQtyService;
import cn.freemud.demo.utils.CommonUtils;
import cn.freemud.entities.dto.ActivityCalculationDiscountRequestDto;
import cn.freemud.entities.dto.PromotionMessageDto;
import cn.freemud.entities.dto.activity.ActivityQueryDto;
import cn.freemud.entities.vo.ActivityList;
import cn.freemud.entities.vo.ActivityTip;
import cn.freemud.entities.vo.CartGoods;
import cn.freemud.enums.*;
import cn.freemud.interceptor.BizServiceException;
import cn.freemud.interceptor.ServiceException;
import cn.freemud.redis.RedisCache;
import cn.freemud.service.impl.AssortmentSdkService;
import cn.freemud.service.impl.calculate.CalculationCommonService;
import cn.freemud.utils.WebUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
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 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.stereotype.Service;

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

@Service
public abstract class AbstractUpdateGoodsQtyService implements UpdateGoodsQtyService {

    @Autowired
    private CustomerManager customerManager;

    @Autowired
    private ProductManager productManager;

    @Autowired
    private CouponManager couponManager;

    @Autowired
    private AssortmentSdkService assortmentSdkService;

    @Autowired
    private ShoppingCartBaseServiceImpl shoppingCartBaseService;

    @Autowired
    private ShoppingBaseServiceImpl shoppingBaseService;

    @Autowired
    private PromotionManager promotionManager;

    @Autowired
    private CalculationCommonService calculationCommonService;

    @Autowired
    private ActivityAdapter activityAdapter;

    @Autowired
    private DistributeService distributeService;

    @Autowired
    private MessageService messageService;



    /**
     * 加车的流程
     *
     * @return
     */
    public final ShoppingCartGoodsBO updateGoodsQty(UpdateAddGoodsBO updateAddGoodsBO) {
        // 基本参数校验
        this.checkParams(updateAddGoodsBO);

        // 获取购物车和加车商品信息
        CheckBussinessRulesBO checkBussinessRulesBO = this.getShoppingCartInfo(updateAddGoodsBO);

        // 业务校验,例如商品数量库存之类的信息
        AddGoodsToShoppingCartBO addGoodsToShoppingCartBO = this.checkBusinessRules(updateAddGoodsBO, checkBussinessRulesBO);

        // 添加商品到购物车
        DiscountResultBO discountResultBO = this.addGoodsToShoppingCart(updateAddGoodsBO, addGoodsToShoppingCartBO);

        // 去促销计算优惠
        CalCostBO calCostBO = this.getDiscountResult(updateAddGoodsBO, discountResultBO);

        // 计算促销不计算的费用,例如配送费
        DistributeBO distributeBO = this.calCost(updateAddGoodsBO, calCostBO);

        // 拼装购物车价格
        SetMessageBO setMessageBO = this.distribute(updateAddGoodsBO, distributeBO);

        // 提示语设置,例如满减信息
        ShoppingCartGoodsBO addGoodsShoppingCartBO = this.setMessage(updateAddGoodsBO, setMessageBO);

        return addGoodsShoppingCartBO;
    }

    /**
     * 计算不在促销计算范围里的费用
     * @param addGoodsBO
     * @return
     */
    public final DistributeBO calCost(UpdateAddGoodsBO addGoodsBO, CalCostBO calCostBO) {
        DistributeBO commonSetMessageBO = this.calCommCost(addGoodsBO, calCostBO);

        DistributeBO customSetMessageBO = this.calCustomCost(addGoodsBO, calCostBO, commonSetMessageBO);

        return customSetMessageBO;
    }

    public final CalCostBO getDiscountResult(UpdateAddGoodsBO addGoodsBO, DiscountResultBO discountResultBO) {
        CalCostBO before = this.getDiscountResultBefore(addGoodsBO, discountResultBO);

        CalCostBO commonSetMessageBO = this.getComDiscountResult(addGoodsBO, discountResultBO, before);

        CalCostBO customSetMessageBO = this.getDiscountResultAfter(addGoodsBO, discountResultBO, commonSetMessageBO);

        return customSetMessageBO;
    }

    public final SetMessageBO distribute(UpdateAddGoodsBO addGoodsBO, DistributeBO distributeBO) {
        SetMessageBO commonSetMessageBO = this.commDistribute(addGoodsBO, distributeBO);

        SetMessageBO customSetMessageBO = this.customDistribute(addGoodsBO, distributeBO, commonSetMessageBO);

        return customSetMessageBO;
    }

    /**
     * 设置提示语
     * @param addGoodsBO
     * @return
     */
    public final ShoppingCartGoodsBO setMessage(UpdateAddGoodsBO addGoodsBO, SetMessageBO setMessageBO) {
        ShoppingCartGoodsBO commonAddGoodsShoppingCartBO = this.setCommMessage(addGoodsBO, setMessageBO);

        ShoppingCartGoodsBO customAddGoodsShoppingCartBO = this.setCustomMessage(addGoodsBO, setMessageBO, commonAddGoodsShoppingCartBO);

        return customAddGoodsShoppingCartBO;
    }


    /**
     * 请求基本参数校验
     * @return
     */
    public final BaseResponse checkParams(UpdateAddGoodsBO baseRequestDTO) {
        BaseResponse commonBaseResponse = this.checkCommParams(baseRequestDTO);
        if (!ResponseConstant.RESPONSE_SUCCESS_STR.equals(commonBaseResponse.getCode())){
            return commonBaseResponse;
        }
        BaseResponse customBaseResponse = this.checkCustomParams(baseRequestDTO);
        if (!ResponseConstant.RESPONSE_SUCCESS_STR.equals(customBaseResponse.getCode())){
            return customBaseResponse;
        }
        return ResponseBuilder.success();
    }

    /**
     * 1. 获取加车的商品信息
     * 2. 获取购物车的商品信息
     *
     * @return
     */
    public final CheckBussinessRulesBO getShoppingCartInfo(UpdateAddGoodsBO baseRequestBO) {
        CheckBussinessRulesBO bo = new CheckBussinessRulesBO();
        // 获取用户信息
        CustomerInfo userInfo = customerManager.getUserInfo(baseRequestBO.getSessionId(), baseRequestBO.getManagerService().getCustomerService());
        bo.setUserId(userInfo.getUserId());
        bo.setIsMember(userInfo.getIsMember());
        baseRequestBO.setUserId(userInfo.getUserId());

        // 先验证商品是否存在
        CartGoods cartGoods = assortmentSdkService.getCartGoodsBySdk(baseRequestBO.getPartnerId(), userInfo.getUserId(), baseRequestBO.getShopId(),
                baseRequestBO.getCartGoodsUid(), "", shoppingCartBaseService);
        if (cartGoods == null) {
            throw new ServiceException(ResponseResult.SHOPPING_CART_UPDATE_ERROR);
        }

        List<CartGoods> cartGoodsList = new ArrayList<>();
        cartGoods.setQty(baseRequestBO.getQty());
        cartGoodsList.add(cartGoods);
        bo.setCartGoods(cartGoodsList);

        // 获取商品信息
        GetProductBO getProductBO = convert2ProductBO(baseRequestBO, cartGoods);
        List<ProductBO>  productsInfoList = productManager.getProductsInfo(getProductBO, baseRequestBO.getManagerService().getProductService());
        ProductBO productsInfo = productsInfoList.get(0);
        bo.setProduct(productsInfo);


        return bo;
    }

    private GetProductBO convert2ProductBO(UpdateAddGoodsBO baseRequestBO, CartGoods cartGoods) {
        GetProductBO getProductBO = new GetProductBO();
        if (CommonUtils.isProductCoupon(baseRequestBO.getCouponCode(), cartGoods.getCartGoodsUid())) {
            getProductBO.setGoodsId(Collections.singletonList(cartGoods.getSkuId()));
        } else {
            getProductBO.setGoodsId(Collections.singletonList(cartGoods.getGoodsId()));
        }

        getProductBO.setStoreId(baseRequestBO.getShopId());
        getProductBO.setPartnerId(baseRequestBO.getPartnerId());
        getProductBO.setMenuType(BusinessTypeEnum.getByType(baseRequestBO.getMenuType()).getCode());

        return getProductBO;
    }

    /**
     * 具体业务逻辑校验, 例如商品数量,库存等校验
     *
     * @return
     */
    public final AddGoodsToShoppingCartBO checkBusinessRules(UpdateAddGoodsBO baseRequestDTO, CheckBussinessRulesBO checkBussinessRulesBO) {
        AddGoodsToShoppingCartBO commAddGoodsToShoppingCartBO = this.checkCommBusinessRules(baseRequestDTO, checkBussinessRulesBO);
        AddGoodsToShoppingCartBO customAddGoodsToShoppingCartBO = this.checkCustomBusinessRules(baseRequestDTO, checkBussinessRulesBO, commAddGoodsToShoppingCartBO);
        return customAddGoodsToShoppingCartBO;
    }


    /**
     * 添加商品到购物车,并重新设置购物车
     *
     * @return
     */
    public final DiscountResultBO addGoodsToShoppingCart(UpdateAddGoodsBO baseRequestDTO, AddGoodsToShoppingCartBO addGoodsToShoppingCartBO) {

        DiscountResultBO commCalCostBO = this.commAddGoodsToShoppingCart(baseRequestDTO, addGoodsToShoppingCartBO);

        DiscountResultBO customCalCostBO = this.customAddGoodsToShoppingCart(baseRequestDTO, addGoodsToShoppingCartBO, commCalCostBO);

        return customCalCostBO;
    }


    private BaseResponse checkCommParams(UpdateAddGoodsBO baseRequestDTO) {

        if (StringUtils.isEmpty(baseRequestDTO.getShopId())){
            throw new ServiceException(ResponseResult.SHOPPING_CART_SHOP_ID_NOT_EMPTY);
        }

        return ResponseBuilder.success();
    }

    private AddGoodsToShoppingCartBO checkCommBusinessRules(UpdateAddGoodsBO baseRequestDTO, CheckBussinessRulesBO checkBussinessRulesBO) {
        AddGoodsToShoppingCartBO bo = new AddGoodsToShoppingCartBO();

        //购物车添加数量限制
        // this.limitGoodsQty(checkBussinessRulesBO.getCartGoods(), addGoods, baseRequestDTO.getAppId());
        CartGoods cartGoods = checkBussinessRulesBO.getCartGoods().get(0);
        // 校验数量, 库存
        this.checkStocks(baseRequestDTO, checkBussinessRulesBO);

        // 检查校验购物车商品(是否合法,上下架,点餐方式,是否在当前菜单中...),并移除非法商品
        ShoppingCartContext cartContext = convert2ShopingCartContext(baseRequestDTO);

        // 更新购物车信息
        List<CartGoods> cartGoodsList = assortmentSdkService.updateGoodsQtyBySdk(baseRequestDTO.getPartnerId(), checkBussinessRulesBO.getUserId(),
                baseRequestDTO.getShopId(), cartGoods.getCartGoodsUid(), cartGoods.getQty()<0?0:cartGoods.getQty(), "", shoppingCartBaseService);

        CheckCartRequest checkCartRequest = shoppingBaseService.checkShoppingCart(cartGoodsList, null, cartContext);

        checkBussinessRulesBO.setChanged(checkCartRequest.getChanged());
        checkBussinessRulesBO.setToastMsg(checkCartRequest.getToastMsg());

        bo.setCartGoods(JSONArray.parseArray(JSONObject.toJSONString(checkCartRequest.getCartGoodsList()), CartGoods.class));
        bo.setChanged(checkCartRequest.getChanged());
        bo.setProduct(checkBussinessRulesBO.getProduct());
        bo.setShoppingCartContext(cartContext);
        bo.setToastMsg(checkCartRequest.getToastMsg());
        bo.setIsMember(checkBussinessRulesBO.getIsMember());

        return bo;
    }

    private DiscountResultBO commAddGoodsToShoppingCart(UpdateAddGoodsBO baseRequestDTO, AddGoodsToShoppingCartBO addGoodsToShoppingCartBO) {
        DiscountResultBO calCostBO = new DiscountResultBO();
        ShoppingCartContext cartContext = addGoodsToShoppingCartBO.getShoppingCartContext();

        assortmentSdkService.setShoppingCart(cartContext.getPartnerId(), cartContext.getShopId(), cartContext.getUserId(),
                addGoodsToShoppingCartBO.getCartGoods(), baseRequestDTO.getSessionId(), "", shoppingCartBaseService);

        calCostBO.setCartGoods(addGoodsToShoppingCartBO.getCartGoods());
        calCostBO.setChanged(addGoodsToShoppingCartBO.getChanged());
        calCostBO.setShoppingCartContext(addGoodsToShoppingCartBO.getShoppingCartContext());
        calCostBO.setValidCouponMap(addGoodsToShoppingCartBO.getValidCouponMap());
        calCostBO.setSpqIdToCartUuidMap(addGoodsToShoppingCartBO.getSpqIdToCartUuidMap());
        calCostBO.setToastMsg(addGoodsToShoppingCartBO.getToastMsg());
        calCostBO.setIsMember(addGoodsToShoppingCartBO.getIsMember());
        return calCostBO;
    }

    private DistributeBO calCommCost(UpdateAddGoodsBO baseRequestDTO, CalCostBO calCostBO) {
        DistributeBO distributeBO = new  DistributeBO();
        distributeBO.setCalculationDiscountBO(calCostBO.getCalculationDiscountBO());
        distributeBO.setCartGoods(calCostBO.getCartGoods());
        distributeBO.setChanged(calCostBO.getChanged());
        distributeBO.setToastMsg(calCostBO.getToastMsg());
        return distributeBO;
    }

    private ShoppingCartGoodsBO setCommMessage(UpdateAddGoodsBO baseRequestDTO, SetMessageBO setMessageBO) {

        ShoppingCartGoodsBO shoppingCartGoodsBO = setMessageBO.getShoppingCartGoodsBO();

        CalculationDiscountBO.CalculationDiscountResult discountResult = setMessageBO.getCalculationDiscountBO().getResult();

        // 满减提示

        StringBuilder messageBuilder = new StringBuilder();
        ActivityBO activityBO = setMessageBO.getActivityBO();
        List<ActivityList> activityList = messageService.fullReduceMessage(discountResult, messageBuilder, activityBO);

        /**
        * 调用促销统一活动查询,过滤出参与的满减(目前只有每满减和阶梯满减)
        */

        PromotionMessageDto promotionMessageDto = new PromotionMessageDto();
        if (activityBO != null){
            promotionMessageDto.setActivityId(activityBO.getActivityCode());
            promotionMessageDto.setActivityName(activityBO.getActivityName());
            promotionMessageDto.setActivityType(activityBO.getActivityType());
        }
        promotionMessageDto.setPromotionAmount(0L);
        promotionMessageDto.setPromotionMessage(messageBuilder.toString());
        ActivityTip activityTip = new ActivityTip();
        activityTip.setActivityCode(promotionMessageDto.getActivityId());
        activityTip.setActivityType(promotionMessageDto.getActivityType());
        activityTip.setActivityName(promotionMessageDto.getPromotionMessage());
        activityTip.setActivityList(activityList);
        shoppingCartGoodsBO.setActivityTip(activityTip);
        shoppingCartGoodsBO.setDeliveryFeeZeroReason(0);
        // 设置提示消息和变更标记
        setToastMsgIfNotExist(shoppingCartGoodsBO, setMessageBO.getToastMsg());
        if (!Objects.equals(shoppingCartGoodsBO.getChanged(),true)){
            shoppingCartGoodsBO.setChanged(Objects.equals(true,setMessageBO.getChanged()));
        }
        return shoppingCartGoodsBO;
    }

    private CalCostBO getComDiscountResult(UpdateAddGoodsBO baseRequestDTO, DiscountResultBO discountResultBO, CalCostBO before) {
        if (before.getGetCalculationDiscountBO() == null){
            before.setCalculationDiscountBO(new CalculationDiscountBO());
            return before;
        }
        CalculationDiscountBO calculationDiscountBO = promotionManager.calculationDiscount(before.getGetCalculationDiscountBO(), baseRequestDTO.getManagerService().getPromotionService());
        calculationDiscountBO.getResult().setValidCouponMap(before.getValidCouponMap());
        calculationDiscountBO.getResult().setSpqIdToCartUuidMap(before.getSpqIdToCartUuidMap());
        before.setCalculationDiscountBO(calculationDiscountBO);

        return before;
    }

    private SetMessageBO commDistribute(UpdateAddGoodsBO baseRequestDTO, DistributeBO distributeBO) {

        SetMessageBO setMessageBO = new SetMessageBO();

        ActivityQueryDto activityQueryDto = activityAdapter.getActivityQueryDto(baseRequestDTO.getPartnerId(), baseRequestDTO.getShopId(),
                baseRequestDTO.getUserId(), baseRequestDTO.getAppId(), baseRequestDTO.getOrderType());

        ShoppingCartGoodsBO shoppingCartGoodsBO = new ShoppingCartGoodsBO();

        /**
         * 用促销价格初始化购物车行记录成交价
         */
        ShoppingGoodsAmountBO shoppingGoodsAmountBO = distributeService.initShoppingCart(distributeBO.getCalculationDiscountBO().getResult(), distributeBO.getCartGoods(), null);

        // 满减
        FullReductionBO fullReductionBO = distributeService.fullReduction(baseRequestDTO, distributeBO.getCalculationDiscountBO().getResult(), distributeBO.getCartGoods(), activityQueryDto);

        // 买赠
        List<CartGoods> giftGoods = distributeService.buyGift(distributeBO.getCalculationDiscountBO().getResult(), distributeBO.getCartGoods(), activityQueryDto, baseRequestDTO);

        // 买一赠一寄杯
        List<ChooseGoodsBO> chooseGoodsBO = distributeService.bugGiftAndSendCup(distributeBO.getCalculationDiscountBO().getResult(), distributeBO.getCartGoods(), activityQueryDto, baseRequestDTO);


        shoppingCartGoodsBO.setOriginalTotalAmount(shoppingGoodsAmountBO.getOriginalTotalAmount());
        shoppingCartGoodsBO.setNewPackAmount(null);
        shoppingCartGoodsBO.setTotalAmount(shoppingGoodsAmountBO.getTotalAmount());
        shoppingCartGoodsBO.setTotalDiscountAmount(shoppingGoodsAmountBO.getTotalDiscountAmount());

        shoppingCartGoodsBO.setFullDiscount(fullReductionBO.getDiscount());
        if (distributeBO.getCartGoods() == null){
            distributeBO.setCartGoods(new ArrayList<>());
        }
        distributeBO.getCartGoods().addAll(giftGoods);
        shoppingCartGoodsBO.setChooseGoods(chooseGoodsBO);
        shoppingCartGoodsBO.setVersion(2);
        shoppingCartGoodsBO.setProducts(distributeBO.getCartGoods());
        shoppingCartGoodsBO.setProductsCount(distributeBO.getCartGoods().size());


        setMessageBO.setActivityBO(fullReductionBO.getActivityBO());
        setMessageBO.setShoppingCartGoodsBO(shoppingCartGoodsBO);
        setMessageBO.setCartGoods(distributeBO.getCartGoods());
        setMessageBO.setCalculationDiscountBO(distributeBO.getCalculationDiscountBO());

        return setMessageBO;
    }


    private void setToastMsgIfNotExist(ShoppingCartGoodsBO shoppingCartGoodsBO, String message) {
        if (StringUtils.isEmpty(shoppingCartGoodsBO.getToastMsg())) {
            shoppingCartGoodsBO.setToastMsg(message);
        }
    }

    private ShoppingCartContext convert2ShopingCartContext(UpdateAddGoodsBO baseRequestDTO){
        ShoppingCartContext cartContext = new ShoppingCartContext();
        cartContext.setMenuType(baseRequestDTO.getMenuType());
        cartContext.setOrderType(baseRequestDTO.getOrderType());
        cartContext.setPartnerId(baseRequestDTO.getPartnerId());
        cartContext.setShopId(baseRequestDTO.getShopId());
        cartContext.setUserId(baseRequestDTO.getUserId());
        cartContext.setSessionId(baseRequestDTO.getSessionId());
        cartContext.setTableNumber(baseRequestDTO.getTableNumber());
        return cartContext;
    }

    private void checkStocks(UpdateAddGoodsBO baseRequestDTO, CheckBussinessRulesBO checkBussinessRulesBO){
        CartGoods cartGoods = checkBussinessRulesBO.getCartGoods().get(0);
        ProductBO product = checkBussinessRulesBO.getProduct();
        if (product == null || product.getStockLimit() != 1) {
            return;
        }

        ProductStockBO availableStocks = null;
        GetProductStock getProductStock = new GetProductStock();

        getProductStock.setChannel(BusinessTypeEnum.getByType(baseRequestDTO.getMenuType()).getCode());
        getProductStock.setPartnerId(baseRequestDTO.getPartnerId());
        getProductStock.setProductIds(Collections.singletonList(Long.parseLong(cartGoods.getGoodsId())));
        getProductStock.setStoreId(baseRequestDTO.getShopId());

        List<ProductStockBO> productStock = productManager.getProductStock(getProductStock, baseRequestDTO.getManagerService().getProductService());
        if (CollectionUtils.isNotEmpty(productStock)){
            availableStocks = productStock.get(0);
        }

        int stock = availableStocks == null || availableStocks.getQty() == null ? 0 : availableStocks.getQty();
        if (stock <= 0) {
            throw new ServiceException(ResponseResult.SHOPPING_CART_STOCK_NOT_HAVE);
        } else if (stock < baseRequestDTO.getQty()) {
            throw new BizServiceException(ResponseResult.SHOPPING_CART_STOCK_NOT_HAVE, "仅剩" + stock + "件库存了");
        }
    }

}
