
package com.tmerclub.cloud.product.controller.app;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.tmerclub.cloud.api.auth.bo.UidInfoBO;
import com.tmerclub.cloud.api.delivery.dto.CalculateAndGetDeliverInfoDTO;
import com.tmerclub.cloud.api.delivery.feign.DeliveryFeignClient;
import com.tmerclub.cloud.api.discount.feign.DiscountFeignClient;
import com.tmerclub.cloud.api.multishop.bo.EsShopDetailBO;
import com.tmerclub.cloud.api.multishop.constant.ShopStatus;
import com.tmerclub.cloud.api.multishop.feign.ShopDetailFeignClient;
import com.tmerclub.cloud.api.product.manager.ShopCartAdapter;
import com.tmerclub.cloud.common.constant.Constant;
import com.tmerclub.cloud.common.constant.StatusEnum;
import com.tmerclub.cloud.common.exception.LuckException;
import com.tmerclub.cloud.common.order.constant.DeliveryType;
import com.tmerclub.cloud.common.order.dto.DvyTypeDTO;
import com.tmerclub.cloud.common.order.vo.ShopCartItemVO;
import com.tmerclub.cloud.common.order.vo.ShopCartVO;
import com.tmerclub.cloud.common.order.vo.ShopCartWithAmountVO;
import com.tmerclub.cloud.common.order.vo.UserDeliveryInfoVO;
import com.tmerclub.cloud.common.product.constant.PreSaleType;
import com.tmerclub.cloud.common.product.constant.SpuType;
import com.tmerclub.cloud.common.product.vo.SkuLangVO;
import com.tmerclub.cloud.common.product.vo.SkuVO;
import com.tmerclub.cloud.common.product.vo.SpuLangVO;
import com.tmerclub.cloud.common.product.vo.SpuVO;
import com.tmerclub.cloud.common.response.ResponseEnum;
import com.tmerclub.cloud.common.response.ServerResponseEntity;
import com.tmerclub.cloud.common.security.AuthUserContext;
import com.tmerclub.cloud.common.util.BeanUtil;
import com.tmerclub.cloud.common.util.LangUtil;
import com.tmerclub.cloud.product.dto.shopcart.AddShopCartItemsDTO;
import com.tmerclub.cloud.product.dto.shopcart.ChangeShopCartItemDTO;
import com.tmerclub.cloud.product.dto.shopcart.CheckShopCartItemDTO;
import com.tmerclub.cloud.product.model.ShopCartItem;
import com.tmerclub.cloud.product.service.*;
import com.tmerclub.cloud.product.service.*;
import com.tmerclub.cloud.product.vo.ShopCartAmountVO;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;

import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

/**
 * 购物车
 *
 * @author tmerclub
 * @date 2020-11-20 15:47:32
 */
@RestController
@RequestMapping("/shop_cart")
@Tag(name = "app-购物车")
public class ShopCartController {

    @Autowired
    private ShopCartService shopCartService;


    @Autowired
    private SpuService spuService;

    @Autowired
    private SkuService skuService;

    @Autowired
    private SkuStockService skuStockService;

    @DubboReference
    private DeliveryFeignClient deliveryFeignClient;
    @Autowired
    private ThreadPoolExecutor prodThreadPoolExecutor;
    @DubboReference
    private DiscountFeignClient discountFeignClient;

    @Autowired
    private ShopCartAdapter shopCartAdapter;

    @DubboReference
    private ShopDetailFeignClient shopDetailFeignClient;
    @Autowired
    private ComboShopCartService comboShopCartService;

    /**
     * 获取用户购物车信息
     *
     * @return
     */
    @GetMapping("/info")
    @Operation(summary = "获取用户购物车信息", description = "获取用户购物车信息")
    public ServerResponseEntity<ShopCartWithAmountVO> info() throws ExecutionException, InterruptedException {
        // 拿到购物车的所有item
        List<ShopCartItemVO> shopCartItems = shopCartService.getShopCartItems();
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        // 筛选下选中的商品用于计算运费
        List<ShopCartItemVO> filterShopCartItems = shopCartItems.stream().filter(shopCartItemVO -> shopCartItemVO.getIsChecked() == 1).collect(Collectors.toList());
        // 异步计算运费，运费暂时和优惠券没啥关联，可以与优惠券异步计算，获取用户地址，自提信息
        CompletableFuture<ServerResponseEntity<UserDeliveryInfoVO>> deliveryFuture = CompletableFuture.supplyAsync(() -> {
            RequestContextHolder.setRequestAttributes(requestAttributes);
            // TODO 这边目前只有快递配送一种方式，所以先写死快递配送
            List<DvyTypeDTO> dvyTypes = new ArrayList<>(Constant.INITIAL_CAPACITY);
            dvyTypes.add(new DvyTypeDTO(null, DeliveryType.DELIVERY.value()));
            UserDeliveryInfoVO userDeliveryInfoVO = new UserDeliveryInfoVO();
            userDeliveryInfoVO.setAddrId(0L);
            userDeliveryInfoVO.setDvyTypes(dvyTypes);
            return deliveryFeignClient.calculateAndGetDeliverInfo(new CalculateAndGetDeliverInfoDTO(filterShopCartItems, userDeliveryInfoVO));
        }, prodThreadPoolExecutor);
        // 运费用异步计算，最后要等运费出结果
        ServerResponseEntity<UserDeliveryInfoVO> userDeliveryInfoResponseEntity = deliveryFuture.get();
        if (!userDeliveryInfoResponseEntity.isSuccess()) {
            return ServerResponseEntity.transform(userDeliveryInfoResponseEntity);
        }
        List<ShopCartVO> shopCarts = shopCartAdapter.conversionShopCart(shopCartItems);
        ShopCartWithAmountVO shopCartWithAmountVO = new ShopCartWithAmountVO();
        shopCartWithAmountVO.setShopCarts(shopCarts);
        shopCartWithAmountVO.setUserDeliveryInfo(userDeliveryInfoResponseEntity.getData());
        return discountFeignClient.calculateDiscountAndMakeUpShopCartAndAmount(shopCartWithAmountVO);
    }

    /**
     * 获取用户购物车信息
     *
     * @return
     */
    @GetMapping("/amount_info")
    @Operation(summary = "获取用户购物车金额信息", description = "获取用户购物车金额信息")
    public ServerResponseEntity<ShopCartAmountVO> amountInfo() {
        // 拿到购物车的所有item
        List<ShopCartItemVO> shopCartItems = shopCartService.getShopCartItems();
        List<ShopCartVO> shopCarts = shopCartAdapter.conversionShopCart(shopCartItems);
        ShopCartWithAmountVO shopCartWithAmountVO = new ShopCartWithAmountVO();
        shopCartWithAmountVO.setShopCarts(shopCarts);
        ServerResponseEntity<ShopCartWithAmountVO> shopCartWithAmountResponse = discountFeignClient.calculateDiscountAndMakeUpShopCartAndAmount(shopCartWithAmountVO);

        if (!shopCartWithAmountResponse.isSuccess()) {
            return ServerResponseEntity.transform(shopCartWithAmountResponse);
        }

        return ServerResponseEntity.success(BeanUtil.map(shopCartWithAmountResponse.getData(), ShopCartAmountVO.class));
    }


    @PutMapping("/delete_item")
    @Operation(summary = "删除用户购物车物品", description = "通过购物车id删除用户购物车物品")
    public ServerResponseEntity<Void> deleteItem(@RequestBody List<Long> shopCartItemIds) {
        Long userId = AuthUserContext.get().getUserId();
        shopCartService.deleteShopCartItemsByShopCartItemIds(userId, shopCartItemIds);
        return ServerResponseEntity.success();
    }

    @DeleteMapping("/delete_all")
    @Operation(summary = "清空用户购物车所有物品", description = "清空用户购物车所有物品")
    public ServerResponseEntity<String> deleteAll() {
        Long userId = AuthUserContext.get().getUserId();
        shopCartService.deleteAllShopCartItems(userId);
        // 删除成功
        return ServerResponseEntity.success();
    }

    @PostMapping("/check_items")
    @Operation(summary = "勾选购物车")
    public ServerResponseEntity<Void> checkItems(@Valid @RequestBody List<CheckShopCartItemDTO> params) {
        if (CollectionUtil.isEmpty(params)) {
            return ServerResponseEntity.success();
        }
        Long userId = AuthUserContext.get().getUserId();
        shopCartService.checkShopCartItems(userId, params);
        return ServerResponseEntity.success();
    }


    @PostMapping("/change_item")
    @Operation(summary = "添加、修改用户购物车物品", description = "通过商品id(prodId)、skuId、店铺Id(shopId),添加/修改用户购物车商品，并传入改变的商品个数(count)，" +
            "当count为正值时，增加商品数量，当count为负值时，将减去商品的数量，当最终count值小于0时，会将商品从购物车里面删除")
    public ServerResponseEntity<Void> addItem(@Valid @RequestBody ChangeShopCartItemDTO param) {
        // 不用校验库存是否充足！！！
        Long userId = AuthUserContext.get().getUserId();
        List<ShopCartItemVO> shopCartItems = shopCartService.getShopCartItems();
        SpuVO spu = spuService.getBySpuId(param.getSpuId());
        Long skuId = param.getSkuId();
        SkuVO sku = skuService.getSkuBySkuId(skuId);
        //新增/修改套餐商品
        if (Objects.nonNull(param.getComboId()) && !Objects.equals(param.getComboId(), 0L)) {
            comboSpuChange(param, shopCartItems);
            return ServerResponseEntity.success();
        }
        // 当商品状态不正常时，不能添加到购物车
        if (Objects.isNull(spu) || Objects.isNull(sku) || !Objects.equals(spu.getStatus(), StatusEnum.ENABLE.value()) || !Objects.equals(sku.getStatus(), StatusEnum.ENABLE.value()) || !Objects.equals(sku.getSpuId(), spu.getSpuId())) {
            // 当返回商品不存在时，前端应该将商品从购物车界面移除
            return ServerResponseEntity.fail(ResponseEnum.SPU_NOT_EXIST);
        }
        // 定金预售商品不可加入购物车
        if (Objects.equals(spu.getPreSaleType(), PreSaleType.DEPOSIT.value())) {
            throw new LuckException("定金预售商品不可加入购物车");
        }
        // 保存shopId，不要让前端传过来
        param.setShopId(spu.getShopId());
        // 获取加购的sku库存
        Integer skuStock = getSkuStock(param, spu, skuId, sku);
        Long oldShopCartItemId = null;
        Integer oldCount = 0;
        for (ShopCartItemVO shopCartItemVo : shopCartItems) {
            if (Objects.equals(skuId, shopCartItemVo.getSkuId()) && Objects.equals(param.getComboId(), shopCartItemVo.getComboId())) {
                // 旧数量
                oldCount = shopCartItemVo.getCount();
                oldShopCartItemId = shopCartItemVo.getCartItemId();
                ShopCartItem shopCartItem = new ShopCartItem();
                shopCartItem.setUserId(userId);
                shopCartItem.setDistributionUserId(param.getDistributionUserId());
                shopCartItem.setCount(param.getCount() + shopCartItemVo.getCount());
                if (param.getCount() > 0 && shopCartItem.getCount() > skuStock) {
                    throw new LuckException("商品规格库存不足，无法进行此操作");
                }
                shopCartItem.setCartItemId(shopCartItemVo.getCartItemId());
                shopCartItem.setIsChecked(shopCartItemVo.getIsChecked());
                shopCartItem.setDiscountId(param.getDiscountId());
                // 如果有个旧的sku，就说明是在切换sku
                if (Objects.nonNull(param.getOldSkuId())) {
                    continue;
                }
                // 防止购物车变成负数，从购物车删除
                if (shopCartItem.getCount() <= 0) {
                    shopCartService.deleteShopCartItemsByShopCartItemIds(userId, Collections.singletonList(shopCartItem.getCartItemId()));
                    return ServerResponseEntity.success();
                }
                shopCartService.updateShopCartItem(userId, shopCartItem);
                return ServerResponseEntity.success();
            }
        }

        if (Objects.nonNull(param.getOldSkuId())) {
            for (ShopCartItemVO oldShopCartItem : shopCartItems) {
                // 旧sku
                if (Objects.equals(param.getOldSkuId(), oldShopCartItem.getSkuId())) {
                    ShopCartItem shopCartItem = getShopCartItem(param, userId, skuId, skuStock, oldCount, oldShopCartItem);
                    if (oldShopCartItemId != null) {
                        // 删除旧的购物项
                        shopCartService.deleteShopCartItemsByShopCartItemIds(userId, Collections.singletonList(oldShopCartItemId));
                    }
                    // 更新购物车
                    shopCartService.updateShopCartItem(userId, shopCartItem);
                    return ServerResponseEntity.success();
                }
            }
        }

        // 所有都正常时
        if (Objects.nonNull(skuStock) && skuStock > 0) {
            shopCartService.addShopCartItem(userId, param, sku.getPriceFee(), spu.getCategoryId());
        }
        // 添加成功
        return ServerResponseEntity.success();
    }

    private static ShopCartItem getShopCartItem(ChangeShopCartItemDTO param, Long userId, Long skuId, Integer skuStock, Integer oldCount, ShopCartItemVO oldShopCartItem) {
        ShopCartItem shopCartItem = new ShopCartItem();
        shopCartItem.setUserId(userId);
        shopCartItem.setCartItemId(oldShopCartItem.getCartItemId());
        // 如果以前就存在这个商品，还要把以前的商品数量累加
        shopCartItem.setCount(param.getCount() + oldCount);
        if (param.getCount() > 0 && shopCartItem.getCount() > skuStock) {
            throw new LuckException("变更的商品规格库存不足，无法进行此操作");
        }
        shopCartItem.setSkuId(skuId);
        return shopCartItem;
    }

    private Integer getSkuStock(ChangeShopCartItemDTO param, SpuVO spu, Long skuId, SkuVO sku) {
        Integer skuStock = null;
        if (param.getCount() > 0) {
            // 判断下是否为供应商商品,如果是商家代销供应商商品且为供应商发货设置供应商信息
            if (!Objects.equals(spu.getSupplierId(), 0L) && Objects.equals(spu.getSupplierDeliveryType(), 1)) {
                skuStock = skuStockService.getBySkuId(sku.getSupplierSkuId(),spu.getSpuMold()).getStock();
            } else {
                skuStock = skuStockService.getBySkuId(skuId, spu.getSpuMold()).getStock();
            }
        }
        return skuStock;
    }

    private void comboSpuChange(ChangeShopCartItemDTO param, List<ShopCartItemVO> shopCartItems) {
        if (Objects.nonNull(param.getOldSkuId())) {
            comboShopCartService.comboUpdateCart(param, shopCartItems);
        } else {
            comboShopCartService.comboAddCart(param, shopCartItems);
        }
    }


    @PostMapping("/add_items")
    @Operation(summary = "批量添加用户购物车物品", description = "通过一个对象集合，对象包含商品id(prodId)、skuId、店铺Id(shopId),添加用户购物车商品")
    public ServerResponseEntity<String> addItems(@Valid @RequestBody AddShopCartItemsDTO shopCartItemsDTO) {
        StringBuilder errorMsg = new StringBuilder(Constant.INITIAL_CAPACITY);
        Long userId = AuthUserContext.get().getUserId();
        HashMap<Long, EsShopDetailBO> shopDetailMap = new HashMap<>(16);
        for (ChangeShopCartItemDTO param : shopCartItemsDTO.getShopCartItemList()) {
            // 不用校验库存是否充足！！！
            List<ShopCartItemVO> shopCartItems = shopCartService.getShopCartItems();

            SpuVO spu = spuService.getBySpuId(param.getSpuId());
            SkuVO sku = skuService.getSkuBySkuId(param.getSkuId());
            if (Objects.isNull(shopDetailMap.get(param.getShopId()))) {
                ServerResponseEntity<EsShopDetailBO> shopDetailRes = shopDetailFeignClient.getShopByShopId(param.getShopId());
                if (!shopDetailRes.isSuccess()) {
                    throw new LuckException(shopDetailRes.getMsg());
                }
                shopDetailMap.put(param.getShopId(), shopDetailRes.getData());
            }
            EsShopDetailBO esShopDetailBO = shopDetailMap.get(param.getShopId());
            // 当商品状态不存在或店铺不存在时不能添加到购物车
            if (Objects.isNull(spu) || Objects.isNull(sku) || !Objects.equals(sku.getSpuId(), spu.getSpuId()) || Objects.isNull(esShopDetailBO)) {
                continue;
            }
            // 活动商品不加入购物车
            if (SpuType.ACTIVE.value().equals(spu.getSpuType())) {
                continue;
            }
            Map<Integer, String> spuMap = spu.getSpuLangList().stream().filter(spuLangVO -> StrUtil.isNotBlank(spuLangVO.getSpuName())).collect(Collectors.toMap(SpuLangVO::getLang, SpuLangVO::getSpuName));
            spu.setName(LangUtil.getLangValue(spuMap));
            Map<Integer, String> skuMap = sku.getSkuLangList().stream().filter(skuLangVO -> StrUtil.isNotBlank(skuLangVO.getSkuName())).collect(Collectors.toMap(SkuLangVO::getLang, SkuLangVO::getSkuName));
            sku.setSkuName(LangUtil.getLangValue(skuMap));

            // 当商品状态不正常或店铺已停业时，不能添加到购物车
            if (!Objects.equals(spu.getStatus(), StatusEnum.ENABLE.value()) || !Objects.equals(sku.getStatus(), StatusEnum.ENABLE.value()) || Objects.equals(esShopDetailBO.getShopStatus(), ShopStatus.STOP.value())) {
                // 当返回商品不存在时，记录哪些不能加入购物车
                errorMsg.append(spu.getName());
                if (StrUtil.isNotBlank(sku.getSkuName())) {
                    errorMsg.append(sku.getSkuName());
                }
                errorMsg.append(StrUtil.COMMA);
                continue;
            }
            loadAddItemsData(userId, param, shopCartItems, spu, sku);
        }

        if (StrUtil.isNotBlank(errorMsg)) {
            errorMsg.deleteCharAt(errorMsg.length() - 1);
            errorMsg.append("等商品已失效无法加入购物车，其余已加入购物车");
            return ServerResponseEntity.success(errorMsg.toString());
        }
        // 添加成功
        return ServerResponseEntity.success("操作成功");
    }

    /**
     * 加载加购项数据
     *
     * @param userId        用户id
     * @param param         加购数据
     * @param shopCartItems 购物车列表
     * @param spu           商品信息
     * @param sku           商品规格信息
     */
    private void loadAddItemsData(Long userId, ChangeShopCartItemDTO param, List<ShopCartItemVO> shopCartItems, SpuVO spu, SkuVO sku) {
        boolean isContinue = false;

        // 保存shopId，不要让前端传过来
        param.setShopId(spu.getShopId());

        Integer oldCount = 0;
        Long oldShopCartItemId = null;
        for (ShopCartItemVO shopCartItemVo : shopCartItems) {
            if (Objects.equals(param.getSkuId(), shopCartItemVo.getSkuId())) {
                // 旧数量
                oldCount = shopCartItemVo.getCount();
                oldShopCartItemId = shopCartItemVo.getCartItemId();
                ShopCartItem shopCartItem = new ShopCartItem();
                shopCartItem.setUserId(userId);
                shopCartItem.setCount(param.getCount() + shopCartItemVo.getCount());
                shopCartItem.setCartItemId(shopCartItemVo.getCartItemId());
                shopCartItem.setIsChecked(shopCartItemVo.getIsChecked());
                shopCartItem.setDiscountId(param.getDiscountId());
                // 如果有个旧的sku，就说明是在切换sku
                if (Objects.nonNull(param.getOldSkuId())) {
                    continue;
                }
                //套餐商品订单再次购买,不加入套餐中,变成普通商品加入
                if (Objects.nonNull(shopCartItemVo.getComboId())) {
                    continue;
                }
                // 防止购物车变成负数，从购物车删除
                if (shopCartItem.getCount() <= 0) {
                    shopCartService.deleteShopCartItemsByShopCartItemIds(userId, Collections.singletonList(shopCartItem.getCartItemId()));
                    isContinue = true;
                    break;
                }
                shopCartService.updateShopCartItem(userId, shopCartItem);
                isContinue = true;
                break;
            }
        }

        if (isContinue) {
            return;
        }

        if (Objects.nonNull(param.getOldSkuId())) {
            for (ShopCartItemVO oldShopCartItem : shopCartItems) {
                // 旧sku
                if (Objects.equals(param.getOldSkuId(), oldShopCartItem.getSkuId())) {

                    ShopCartItem shopCartItem = new ShopCartItem();
                    shopCartItem.setUserId(userId);
                    shopCartItem.setCartItemId(oldShopCartItem.getCartItemId());
                    // 如果以前就存在这个商品，还要把以前的商品数量累加
                    shopCartItem.setCount(param.getCount() + oldCount);
                    shopCartItem.setSkuId(param.getSkuId());

                    if (oldShopCartItemId != null) {
                        // 删除旧的购物项
                        shopCartService.deleteShopCartItemsByShopCartItemIds(userId, Collections.singletonList(oldShopCartItemId));
                    }
                    // 更新购物车
                    shopCartService.updateShopCartItem(userId, shopCartItem);
                    isContinue = true;
                    break;
                }
            }
        }

        if (isContinue) {
            return;
        }

        // 所有都正常时
        shopCartService.addShopCartItem(userId, param, sku.getPriceFee(), spu.getCategoryId());
    }

    @GetMapping("/ma/prod_count")
    @Operation(summary = "获取购物车商品数量", description = "获取购物车商品数量")
    public ServerResponseEntity<Integer> prodCount() {
        UidInfoBO uidInfoBO = AuthUserContext.get();
        if (uidInfoBO == null) {
            return ServerResponseEntity.fail(ResponseEnum.CLEAN_TOKEN);
        }
        return ServerResponseEntity.success(shopCartService.getShopCartItemCount(uidInfoBO.getUserId()));
    }

    @GetMapping("/expiry_prod_list")
    @Operation(summary = "获取购物车失效商品信息", description = "获取购物车失效商品列表")
    public ServerResponseEntity<List<ShopCartItemVO>> expiryProdList() {
        return ServerResponseEntity.success(shopCartService.getShopCartExpiryItems());
    }

}
