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

import cn.hutool.core.collection.CollectionUtil;
import com.tmerclub.cloud.api.delivery.dto.CalculateAndGetDeliverInfoDTO;
import com.tmerclub.cloud.api.delivery.feign.DeliveryFeignClient;
import com.tmerclub.cloud.api.order.manager.ConfirmOrderManager;
import com.tmerclub.cloud.api.order.manager.SubmitOrderManager;
import com.tmerclub.cloud.api.product.manager.ShopCartAdapter;
import com.tmerclub.cloud.api.product.manager.ShopCartItemAdapter;
import com.tmerclub.cloud.common.exception.LuckException;
import com.tmerclub.cloud.common.leaf.manager.SegmentManager;
import com.tmerclub.cloud.common.order.constant.DeliveryType;
import com.tmerclub.cloud.common.order.constant.OrderActivityType;
import com.tmerclub.cloud.common.order.constant.OrderType;
import com.tmerclub.cloud.common.order.util.OrderLangUtil;
import com.tmerclub.cloud.common.order.vo.*;
import com.tmerclub.cloud.common.response.ResponseEnum;
import com.tmerclub.cloud.common.response.ServerResponseEntity;
import com.tmerclub.cloud.common.rocketmq.config.RocketMqConstant;
import com.tmerclub.cloud.common.security.AuthUserContext;
import com.tmerclub.cloud.group.bo.GroupOrderBO;
import com.tmerclub.cloud.group.bo.mongo.MongoGroupTeamBO;
import com.tmerclub.cloud.group.constant.DistributedIdKey;
import com.tmerclub.cloud.group.constant.GroupActivityStatusEnum;
import com.tmerclub.cloud.group.constant.TeamStatusEnum;
import com.tmerclub.cloud.group.dto.GroupOrderDTO;
import com.tmerclub.cloud.group.dto.SubmitGroupOrderDTO;
import com.tmerclub.cloud.group.service.GroupActivityService;
import com.tmerclub.cloud.group.service.GroupOrderService;
import com.tmerclub.cloud.group.service.GroupTeamService;
import com.tmerclub.cloud.group.vo.app.AppGroupActivityVO;
import com.tmerclub.cloud.group.vo.app.AppGroupSkuVO;
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.apache.rocketmq.client.producer.LocalTransactionState;
import org.apache.rocketmq.client.producer.TransactionSendResult;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.support.GenericMessage;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Collections;
import java.util.List;
import java.util.Objects;

/**
 * 团购的代码其实可以和订单的代码一起写的，不过
 *
 * @author tmerclub
 * @date 2021-04-07 10:39:32
 */
@RestController("appGroupOrderController")
@RequestMapping("/groupOrder")
@Tag(name = "拼团订单表")
public class GroupOrderController {

    @Autowired
    private GroupOrderService groupOrderService;

    @Autowired
    private GroupTeamService groupTeamService;

    @Autowired
    private GroupActivityService groupActivityService;

    @Autowired
    private ShopCartAdapter shopCartAdapter;

    @Autowired
    private ShopCartItemAdapter shopCartItemAdapter;

    @DubboReference
    private DeliveryFeignClient deliveryFeignClient;

    @Autowired
    private ConfirmOrderManager confirmOrderManager;

    @Autowired
    private SubmitOrderManager submitOrderManager;

    @Autowired
    private RocketMQTemplate groupOrderCreateTemplate;

    @Autowired
    private SegmentManager segmentManager;


    @PostMapping("/confirm")
    @Operation(summary = "确认订单", description = "传入参团/开团所需要的参数进行下单,如果用户为开团时拼团团队Id(groupTeamId)为0,如用户为开团则需要将拼团团队Id(groupTeamId)需要带上")
    public ServerResponseEntity<ShopCartOrderMergerVO> confirm(@Valid @RequestBody GroupOrderDTO orderParam) {
        Long userId = AuthUserContext.get().getUserId();
        Long spuId = orderParam.getShopCartItem().getSpuId();

        AppGroupActivityVO activityVO = groupActivityService.getBySpuId(spuId);

        // 校验活动
        if (Objects.isNull(activityVO) || !Objects.equals(activityVO.getStatus(), GroupActivityStatusEnum.ENABLE.value()) || activityVO.getEndTime().getTime() < System.currentTimeMillis()) {
            // 拼团活动不在进行中，请稍后重试
            return ServerResponseEntity.showFailMsg("拼团活动已结束");
        }


        AppGroupSkuVO appGroupSkuVO = null;
        List<AppGroupSkuVO> groupSkuList = activityVO.getGroupSkuList();
        for (AppGroupSkuVO dbAppGroupSkuVO : groupSkuList) {
            if (Objects.equals(dbAppGroupSkuVO.getGroupSkuId(), orderParam.getGroupSkuId())) {
                appGroupSkuVO = dbAppGroupSkuVO;
                break;
            }
        }
        if (appGroupSkuVO == null) {
            throw new LuckException("sku 信息有误");
        }
        List<ShopCartItemVO> shopCartItemsDb = shopCartItemAdapter.conversionShopCartItem(orderParam.getShopCartItem(), appGroupSkuVO.getPriceFee(), userId, orderParam.getDvyTypes());
        // 获取用户地址信息
        UserDeliveryInfoVO userDeliveryInfoVO = confirmOrderManager.getUserDeliveryInfoVO(shopCartItemsDb, userId, orderParam);
        OrderLangUtil.shopCartItemList(shopCartItemsDb);

        // 将要返回给前端的完整的订单信息
        ShopCartOrderMergerVO shopCartOrderMerger = new ShopCartOrderMergerVO();
        shopCartOrderMerger.setDvyTypes(orderParam.getDvyTypes());
        shopCartOrderMerger.setOrderType(OrderType.GROUP);
        // 筛选过滤掉不同配送的商品
        List<ShopCartItemVO> shopCartItems = confirmOrderManager.filterShopItemsByType(shopCartOrderMerger, userDeliveryInfoVO, shopCartItemsDb);

        // 该商品不满足任何的配送方式
        if (CollectionUtil.isEmpty(shopCartItems)) {
            return ServerResponseEntity.success(shopCartOrderMerger);
        }

        // 自提订单处理
        confirmOrderManager.handleStationOrder(shopCartOrderMerger, shopCartItems, userDeliveryInfoVO);

        // 商品类别 0.实物商品 1. 虚拟商品 2.组合商品
        int mold = 0;
        if (shopCartItemsDb.stream().filter(shopCartItemDto -> Objects.nonNull(shopCartItemDto.getMold()) && shopCartItemDto.getMold() == 1).count() == shopCartItemsDb.size()) {
            // 订单项中的所有商品都为虚拟商品时，才是虚拟订单
            mold = 1;
            shopCartOrderMerger.getDvyTypes().forEach(s -> s.setDvyType(DeliveryType.NOT_DELIVERY.value()));
        }
        shopCartOrderMerger.setSpuMold(mold);

        // 购物车
        List<ShopCartVO> shopCarts = shopCartAdapter.conversionShopCart(shopCartItems);

        // 计算运费，获取用户地址，自提信息
        ServerResponseEntity<UserDeliveryInfoVO> userDeliveryInfoResponseEntity = deliveryFeignClient.calculateAndGetDeliverInfo(new CalculateAndGetDeliverInfoDTO(shopCartItems, userDeliveryInfoVO));

        userDeliveryInfoVO = userDeliveryInfoResponseEntity.getData();

        // 组装完购物车后，插入订单项库存区域id
        confirmOrderManager.handleShopCartStockPoint(userDeliveryInfoVO, shopCarts, shopCartItemsDb, shopCartOrderMerger.getSpuMold());

        // 计算一遍订单金额
        confirmOrderManager.recalculateAmountWhenFinishingCalculateShop(shopCartOrderMerger, shopCarts, userDeliveryInfoVO);

        // 结束平台优惠的计算之后，还要重算一遍金额
        confirmOrderManager.recalculateAmountWhenFinishingCalculatePlatform(shopCartOrderMerger, userDeliveryInfoVO);

        // 计算平台佣金-跟订单其他金额是独立的，可以单独计算
        confirmOrderManager.confirmPlatformCommission(shopCartOrderMerger);
        // 缓存计算新
        confirmOrderManager.cacheCalculatedInfo(userId, shopCartOrderMerger);
        return ServerResponseEntity.success(shopCartOrderMerger);
    }

    @PostMapping("/submit")
    @Operation(summary = "提交订单，返回支付流水号", description = "根据传入的参数判断是否为购物车提交订单，同时对购物车进行删除，用户开始进行支付")
    public ServerResponseEntity<List<Long>> submitOrders(@Valid @RequestBody SubmitGroupOrderDTO submitOrderParam) {
        Long userId = AuthUserContext.get().getUserId();
        // 在这里面已经生成了订单id了
        ServerResponseEntity<ShopCartOrderMergerVO> checkResult = submitOrderManager.checkSubmitInfo(submitOrderParam, userId);
        if (!checkResult.isSuccess()) {
            return ServerResponseEntity.transform(checkResult);
        }
        ShopCartOrderMergerVO mergerOrder = checkResult.getData();
        mergerOrder.setUserId(userId);

        ShopCartOrderVO shopCartOrderVO = mergerOrder.getShopCartOrders().get(0);
        // 生成订单id
        Long orderId = segmentManager.getSegmentIdWithDateTime(DistributedIdKey.tmerclub_ORDER, mergerOrder.getUserId());
        shopCartOrderVO.setOrderId(orderId);

        // 设置为团购订单
        shopCartOrderVO.setOrderType(OrderType.GROUP.value());
        // 上面已经校验过订单信息了，所以商品信息从缓存中获取没有错
        ShopCartItemVO shopCartItemVO = shopCartOrderVO.getShopCartItemDiscounts().get(0).getShopCartItems().get(0);
        Long spuId = Objects.nonNull(shopCartItemVO.getMainComboSpuId()) ? shopCartItemVO.getMainComboSpuId() :  shopCartItemVO.getSpuId();
        Integer count = Objects.nonNull(shopCartItemVO.getComboCount()) ? shopCartItemVO.getComboCount() :  shopCartItemVO.getCount();

        // 校验活动
        AppGroupActivityVO activityVO = groupActivityService.getBySpuId(spuId);
        if (Objects.isNull(activityVO) || !Objects.equals(activityVO.getStatus(), GroupActivityStatusEnum.ENABLE.value()) || activityVO.getEndTime().getTime() < System.currentTimeMillis()) {
            // 拼团活动不在进行中，不能参与拼团
            return ServerResponseEntity.showFailMsg("拼团活动不在进行中，不能参与拼团");
        }
        Integer groupOrderCount = groupOrderService.getOrderBySpuIdAndUserId(activityVO.getGroupActivityId(), spuId, userId);
        if (groupOrderCount > 0) {
            throw new LuckException("您已有拼团中的订单，请耐心等待拼团成功");
        }

        // 购买数量限制
        if (Objects.equals(activityVO.getHasMaxNum(), 1)) {
            Integer dbSpuCount = groupOrderService.getUserHadSpuCountByGroupActivityId(userId, activityVO.getGroupActivityId());
            if (dbSpuCount + count > activityVO.getMaxNum()) {
                return ServerResponseEntity.showFailMsg("您购买数量已超过活动限购数量，无法提交订单");
            }
        }

        // 校验活动商品是否处于失效状态
        if (activityVO.getStatus() != 1) {
            // 活动商品已失效或不存在
            return ServerResponseEntity.showFailMsg("活动商品已失效或不存在");
        }

        MongoGroupTeamBO groupTeam;
        // 校验拼团团队是否可以参团
        if (!Objects.equals(submitOrderParam.getGroupTeamId(), 0L)) {
            groupTeam = groupTeamService.getByGroupTeamId(submitOrderParam.getGroupTeamId());
            if (Objects.isNull(groupTeam)) {
                // 未找到拼团团队信息
                return ServerResponseEntity.showFailMsg("未找到拼团团队信息");
            }
            if (!TeamStatusEnum.IN_GROUP.value().equals(groupTeam.getStatus())) {
                // 拼团团队不在拼团中，不能参与拼团
                return ServerResponseEntity.showFailMsg("拼团团队不在拼团中，不能参与拼团");
            }
            if (groupTeam.getEndTime() != null && System.currentTimeMillis() > groupTeam.getEndTime().getTime()) {
                // 该拼团单不存在
                return ServerResponseEntity.showFailMsg("该拼团单不存在");
            }
        }
        // 锁定库存
        submitOrderManager.tryLockStock(mergerOrder);
        GroupOrderBO groupOrderBO = getGroupOrderBO(submitOrderParam, userId, mergerOrder, shopCartOrderVO, spuId, activityVO);
        mergerOrder.setActivityType(OrderActivityType.GROUP.value());
        mergerOrder.setActivityId(activityVO.getGroupActivityId());

        // 开启事务消息，通知订单订单服务开始创建订单
        TransactionSendResult transactionSendResult = groupOrderCreateTemplate.sendMessageInTransaction(RocketMqConstant.GROUP_ORDER_CREATE_TOPIC, new GenericMessage<>(groupOrderBO), mergerOrder);


        if (!Objects.equals(transactionSendResult.getLocalTransactionState(), LocalTransactionState.COMMIT_MESSAGE)) {
            return ServerResponseEntity.fail(ResponseEnum.EXCEPTION);
        }

        return ServerResponseEntity.success(Collections.singletonList(shopCartOrderVO.getOrderId()));
    }

    private static GroupOrderBO getGroupOrderBO(SubmitGroupOrderDTO submitOrderParam, Long userId, ShopCartOrderMergerVO mergerOrder, ShopCartOrderVO shopCartOrderVO, Long spuId, AppGroupActivityVO activityVO) {
        GroupOrderBO groupOrderBO = new GroupOrderBO();
        groupOrderBO.setGroupTeamId(submitOrderParam.getGroupTeamId());
        groupOrderBO.setGroupActivityId(activityVO.getGroupActivityId());
        groupOrderBO.setShopId(activityVO.getShopId());
        groupOrderBO.setUserId(userId);
        groupOrderBO.setShareUserId(userId);
        groupOrderBO.setActivityProdPrice(mergerOrder.getTotal());
        groupOrderBO.setPayPrice(mergerOrder.getActualTotal());
        groupOrderBO.setOrderId(shopCartOrderVO.getOrderId());
        groupOrderBO.setCount(shopCartOrderVO.getTotalCount());
        groupOrderBO.setSpuId(spuId);
        return groupOrderBO;
    }

}
