/*
 * Copyright (c) 2018-2999 广州亚米信息科技有限公司 All rights reserved.
 *
 * https://www.gz-yami.com/
 *
 * 未经允许，不可做商业用途！
 *
 * 版权所有，侵权必究！
 */

package com.yami.shop.api.listener;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.yami.shop.bean.app.dto.ShopCartItemDiscountDto;
import com.yami.shop.bean.app.dto.ShopCartItemDto;
import com.yami.shop.bean.app.dto.ShopCartOrderDto;
import com.yami.shop.bean.app.dto.ShopCartOrderMergerDto;
import com.yami.shop.bean.enums.OrderStatus;
import com.yami.shop.bean.enums.OrderType;
import com.yami.shop.bean.event.SubmitOrderEvent;
import com.yami.shop.bean.model.*;
import com.yami.shop.bean.order.SubmitOrderOrder;
import com.yami.shop.common.enums.PayType;
import com.yami.shop.common.exception.GlobalException;
import com.yami.shop.common.util.Arith;
import com.yami.shop.dao.*;
import com.yami.shop.security.api.util.SecurityUtils;
import com.yami.shop.service.ProductService;
import com.yami.shop.service.SkuService;
import com.yami.shop.service.UserAddrOrderService;
import lombok.AllArgsConstructor;
import ma.glasnost.orika.MapperFacade;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.context.event.EventListener;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 订单提交监听器
 *
 * @author LGH
 */
@Component("defaultSubmitOrderListener")
@AllArgsConstructor
public class SubmitOrderListener {

    private static final String XSB = "XSB";

    private final MapperFacade mapperFacade;

    private final UserAddrOrderService userAddrOrderService;

    private final ProductService productService;

    private final SkuService skuService;

    private final Snowflake snowflake;

    private final PointsRecordMapper pointsRecordMapper;

    private final OrderSettlementMapper orderSettlementMapper;

    private final BasketMapper basketMapper;

    /**
     * 默认订单提交监听器
     */
    @EventListener(SubmitOrderEvent.class)
    @Order(SubmitOrderOrder.DEFAULT)
    @Transactional(rollbackFor = Exception.class)
    public void defaultSubmitOrderListener(SubmitOrderEvent event) {
        Date now = new Date();
        String userId = SecurityUtils.getUser().getUserId();

        ShopCartOrderMergerDto mergerOrder = event.getMergerOrder();

        // 获取所有店铺的订单
        List<ShopCartOrderDto> shopCartOrders = mergerOrder.getShopCartOrders();

        List<Long> basketIds = new ArrayList<>();
        // 库存检查Map
        Map<Long, Sku> skuStocksMap = new HashMap<>(16);
        // 商品库存检查Map
        Map<Long, Product> prodStocksMap = new HashMap<>(16);

        // 保存收货地址
        UserAddrOrder userAddrOrder = mapperFacade.map(mergerOrder.getUserAddr(), UserAddrOrder.class);
        if (userAddrOrder == null) {
            throw new GlobalException("请填写收货地址");
        }
        userAddrOrder.setUserId(userId);
        userAddrOrder.setCreateTime(now);
        userAddrOrderService.save(userAddrOrder);
        // 查询用户可用积分记录
        List<PointsRecord> pointsRecords = pointsRecordMapper.selectList(new LambdaQueryWrapper<PointsRecord>()
                        .eq(PointsRecord::getUserId, userId)
                        .eq(PointsRecord::getChannelId, mergerOrder.getChannelId())
                        .in(PointsRecord::getPointsType, Arrays.asList(1, 3))
                        .in(PointsRecord::getPointsAudit, Arrays.asList(1, 2)).and(wrapper -> wrapper
                                .gt(PointsRecord::getExpiryDate, LocalDateTime.now())
                                .or()
                                .isNull(PointsRecord::getExpiryDate)
                        )).stream()
                .sorted(Comparator
                        .comparing(PointsRecord::getExpiryDate,
                                Comparator.nullsLast(Comparator.naturalOrder()))
                        .thenComparing(PointsRecord::getId))
                .collect(Collectors.toList());
        ;
        // 积分记录队列
        ArrayDeque<PointsRecord> expiryQueue = new ArrayDeque<>(pointsRecords);
        // 收货地址ID
        Long addrOrderId = userAddrOrder.getAddrOrderId();

        if (CollectionUtils.isNotEmpty(shopCartOrders)) {
            // 遍历每个店铺订单
            for (ShopCartOrderDto shopCartOrderDto : shopCartOrders) {
                // 获取用户可用积分
                Long point = pointsRecordMapper.statisticsPoint(userId, mergerOrder.getChannelId());
                // 生成订单号
                String orderNumber = "FD" + snowflake.nextId();
                shopCartOrderDto.setOrderNumber(orderNumber);

                Long shopId = shopCartOrderDto.getShopId();
                // 创建订单对象
                com.yami.shop.bean.model.Order order = new com.yami.shop.bean.model.Order();
                order.setIsPayed(0);
                order.setHbOrderStatus(OrderStatus.UNPAY.value());
                order.setOrderType(OrderType.ORDINARY.value());
                // 获取订单实际金额
                double actualTotal = shopCartOrderDto.getActualTotal();
                // 判断是否使用积分支付
                if (null != point && point > 0) {
                    order.setOrderType(OrderType.SCORE.value());
                    // 计算积分抵扣金额
                    Double mul = Arith.mul(actualTotal, 100);
                    Double vp = Double.valueOf(point);
                    if (vp >= mul) {
                        order.setPayType(PayType.SCOREPAY.value());
                        order.setIsPayed(1);
                        order.setPayTime(new Date());
                        order.setHbOrderStatus(OrderStatus.CONSIGNMENT.value());
                        // 设置抵扣积分数
                        order.setOffsetPoints(Long.valueOf(String.valueOf(mul).split("\\.")[0]));
                        actualTotal = 0.0;//剩余需要付的钱
                    } else {
                        // 积分不足，计算剩余需支付金额
                        double sub = Arith.sub(mul, vp);
                        order.setOffsetPoints(point);
                        // 设置剩余需支付金额
                        actualTotal = sub / 100;
                        mergerOrder.setNextPay(Boolean.TRUE);
                    }
                } else {
                    mergerOrder.setNextPay(Boolean.TRUE);
                }
                double sumItemA = 0.0;
                boolean hasXsbMemberDiscount = false;
                // 拼接商品名称
                StringBuilder orderProdName = new StringBuilder(100);
                List<OrderItem> orderItems = new ArrayList<>();
                List<ShopCartItemDiscountDto> shopCartItemDiscounts = shopCartOrderDto.getShopCartItemDiscounts();
                boolean isUseTransfee = false;
                for (ShopCartItemDiscountDto shopCartItemDiscount : shopCartItemDiscounts) {
                    List<ShopCartItemDto> shopCartItems = shopCartItemDiscount.getShopCartItems();
                    for (ShopCartItemDto shopCartItem : shopCartItems) {
                        Sku sku = checkAndGetSku(shopCartItem.getSkuId(), mergerOrder.getChannelId(), shopCartItem, skuStocksMap);
                        Product product = checkAndGetProd(shopCartItem.getProdId(), shopCartItem, prodStocksMap,shopId);
                        OrderItem orderItem = new OrderItem();
                        orderItem.setShopId(shopId);
                        orderItem.setOrderNumber(orderNumber);
                        orderItem.setSkuId(sku.getSkuId());
                        orderItem.setProdId(sku.getProdId());
                        orderItem.setSkuName(sku.getSkuName());
                        orderItem.setProdCount(shopCartItem.getProdCount());
                        orderItem.setProdName(sku.getProdName());
                        orderItem.setPic(StrUtil.isBlank(sku.getPic()) ? product.getPic() : sku.getPic());
                        orderItem.setPrice(shopCartItem.getPrice());
                        orderItem.setUserId(userId);
                        orderItem.setProductTotalAmount(shopCartItem.getProductTotalAmount());
                        orderItem.setRecTime(now);
                        orderItem.setCommSts(0);
                        orderItem.setBasketDate(shopCartItem.getBasketDate());
                        // 设置平台分摊优惠
                        orderItem.setPlatformShareReduce(shopCartItem.getPlatformShareReduce());
                        if (XSB.equalsIgnoreCase(shopCartItem.getBusinessType())) {
                            Double memberDiscountShareAmount = shopCartItem.getMemberDiscountShareAmount();
                            orderItem.setMemberDiscountShareAmount(memberDiscountShareAmount == null ? 0.0 : memberDiscountShareAmount);
                            hasXsbMemberDiscount = hasXsbMemberDiscount || (memberDiscountShareAmount != null && memberDiscountShareAmount > 0);
                        } else {
                            orderItem.setMemberDiscountShareAmount(0.0);
                        }
                        Double actualItem = shopCartItem.getActualTotal();
                        // 计算积分抵扣后的实际金额
                        if (null != point && point > 0) {
                            Double useActualItem = actualItem;
                            if (!isUseTransfee) {//每个订单增加运费，都只扣丢?
                                Double transfee = shopCartOrderDto.getTransfee();
                                useActualItem = Arith.add(useActualItem, transfee);
                                isUseTransfee = Boolean.TRUE;
                            }
                            // 使用积分抵扣
                            actualItem = this.doGetOrderItemPoints(Arith.mul(useActualItem, 100), expiryQueue, orderNumber, userId, mergerOrder.getChannelId());
                            // 判断是否需要继续支付
                            if (actualItem > 0) {
                                actualItem = Arith.div(actualItem, 100);
                            }
                        }
                        // 累计订单商品实际金额
                        sumItemA = Arith.add(sumItemA, actualItem);
                        // 设置订单商品项
                        
                        orderItem.setActualTotal(actualItem);
                        // 设置商品项实际金额
                        orderItem.setShareReduce(shopCartItem.getShareReduce());
                        orderProdName.append(orderItem.getProdName()).append(",");
                        // 设置分销卡号
                        orderItem.setDistributionCardNo(shopCartItem.getDistributionCardNo());
                        orderItem.setWeight( shopCartItem.getWeight());
                        // 设置使用积分数
                        orderItem.setUseScore((int) Arith.mul(Arith.sub(shopCartItem.getActualTotal(), actualItem), 100));
                        orderItems.add(orderItem);

                        if (shopCartItem.getBasketId() != null && shopCartItem.getBasketId() != 0) {
                            basketIds.add(shopCartItem.getBasketId());
                        }
                    }

                }

                orderProdName.subSequence(0, Math.min(orderProdName.length() - 1, 100));
                if (orderProdName.lastIndexOf(",") == orderProdName.length() - 1) {
                    orderProdName.deleteCharAt(orderProdName.length() - 1);
                }

                order.setShopId(shopId);
                order.setOrderNumber(orderNumber);
                // 设置商品名称
                order.setProdName(orderProdName.toString());
                // 设置用户ID
                order.setUserId(userId);
                // 设置订单总金额
                order.setTotal(shopCartOrderDto.getTotal());
                // 设置订单实际金额
                order.setActualTotal(actualTotal);
                order.setNextPay(sumItemA > 0);//true是需要微信支?
                order.setChannelId(Long.valueOf(mergerOrder.getChannelId()));
                order.setUpdateTime(now);
                order.setCreateTime(now);
                order.setDeleteStatus(0);
                order.setProductNums(shopCartOrderDto.getTotalCount());
                order.setAddrOrderId(addrOrderId);
                order.setDvyType(mergerOrder.getDvyType());
                order.setReduceAmount(shopCartOrderDto.getShopReduce());
                if (hasXsbMemberDiscount) {
                    order.setMemberDiscountAmount(shopCartOrderDto.getMemberDiscountAmount());
                    order.setMemberDiscountDesc(shopCartOrderDto.getMemberDiscountDesc());
                } else {
                    order.setMemberDiscountAmount(0.0);
                    order.setMemberDiscountDesc(null);
                }
                order.setFreightAmount(shopCartOrderDto.getTransfee());
                order.setRemarks(shopCartOrderDto.getRemarks());

                order.setPlatformAmount(shopCartOrderDto.getPlatformAmount());
                order.setOrderItems(orderItems);
                order.setScore(shopCartOrderDto.getUseScore());
                order.setDvyType(mergerOrder.getDvyType());
                event.getOrders().add(order);
                // 创建订单结算记录
                OrderSettlement orderSettlement = new OrderSettlement();
                orderSettlement.setUserId(userId);
                orderSettlement.setIsClearing(0);
                orderSettlement.setCreateTime(now);
                orderSettlement.setOrderNumber(orderNumber);
                orderSettlement.setPayAmount(order.getActualTotal());
                orderSettlement.setPayStatus(0);
                orderSettlement.setVersion(0);
                orderSettlement.setPayScore(0);
                // 判断是否积分支付
                if (mergerOrder.getIsScorePay() != null && mergerOrder.getIsScorePay() == 1) {
                    orderSettlement.setPayScore(shopCartOrderDto.getUseScore());
                }
                orderSettlementMapper.insert(orderSettlement);
            }
        }

        // 删除购物车商品
        if (!basketIds.isEmpty()) {
            basketMapper.deleteShopCartItemsByBasketIds(userId, basketIds);
        }
    }

    @SuppressWarnings({"Duplicates"})
    private Product checkAndGetProd(Long prodId, ShopCartItemDto shopCartItem, Map<Long, Product> prodStocksMap,Long shopId) {
        Product product = productService.getProductByProdIdAndShopId(prodId, shopId);
        if (product == null) {
            throw new GlobalException("购物车包含无法识别的商品");
        }

        if (product.getStatus() != 1) {
            throw new GlobalException("Product[" + product.getProdName() + "] is unavailable");
        }

        // 检查商品库存
        Product mapProduct = prodStocksMap.get(prodId);

        if (mapProduct == null) {
            mapProduct = new Product();
            mapProduct.setTotalStocks(0);
            mapProduct.setProdId(prodId);
            mapProduct.setProdName(product.getProdName());

        }

        if (product.getTotalStocks() != -1) {
            mapProduct.setTotalStocks(mapProduct.getTotalStocks() + shopCartItem.getProdCount());
            prodStocksMap.put(product.getProdId(), mapProduct);
        }

        // 检查库存是否足够
        if (product.getTotalStocks() != -1 && mapProduct.getTotalStocks() > product.getTotalStocks()) {
            throw new GlobalException("商品：[" + product.getProdName() + "]库存不足");
        }

        return product;
    }

    @SuppressWarnings({"Duplicates"})
    private Sku checkAndGetSku(Long skuId, ShopCartItemDto shopCartItem, Map<Long, Sku> skuStocksMap) {
        // 获取SKU信息
        Sku sku = skuService.getSkuBySkuId(skuId);
        if (sku == null) {
            throw new GlobalException("购物车包含无法识别的商品");
        }

        if (sku.getStatus() != 1) {
            throw new GlobalException("Product[" + sku.getProdName() + "] is unavailable");
        }
        // 检查SKU库存
        if (sku.getActualStocks() != -1 && shopCartItem.getProdCount() > sku.getActualStocks()) {
            throw new GlobalException("商品：[" + sku.getProdName() + "]库存不足");
        }

        if (sku.getActualStocks() != -1) {
            Sku mapSku = new Sku();
            mapSku.setProdId(sku.getProdId());
            // 设置SKU库存
            mapSku.setStocks(shopCartItem.getProdCount());
            mapSku.setSkuId(sku.getSkuId());
            mapSku.setProdName(sku.getProdName());
            skuStocksMap.put(sku.getSkuId(), mapSku);
        }
        return sku;
    }

    @SuppressWarnings({"Duplicates"})
    private Sku checkAndGetSku(Long skuId, Long channelId, ShopCartItemDto shopCartItem, Map<Long, Sku> skuStocksMap) {
        // 获取SKU信息（带渠道）
        Sku sku = skuService.getSkuBySkuId(skuId, channelId, shopCartItem.getShopId());
        if (sku == null) {
            throw new GlobalException("购物车包含无法识别的商品");
        }

        if (sku.getStatus() != 1) {
            throw new GlobalException("Product[" + sku.getProdName() + "] is unavailable");
        }
        // 检查SKU库存（带渠道）
        if (sku.getActualStocks() != -1 && shopCartItem.getProdCount() > sku.getActualStocks()) {
            throw new GlobalException("商品：[" + sku.getProdName() + "]库存不足");
        }

        if (sku.getActualStocks() != -1) {
            Sku mapSku = new Sku();
            mapSku.setProdId(sku.getProdId());
            // 设置SKU库存（带渠道）
            mapSku.setStocks(shopCartItem.getProdCount());
            mapSku.setSkuId(sku.getSkuId());
            mapSku.setProdName(sku.getProdName());
            skuStocksMap.put(sku.getSkuId(), mapSku);
        }
        return sku;
    }


    private Double doGetOrderItemPoints(Double actualTotal, ArrayDeque<PointsRecord> expiryQueue, String orderNumber, String userId, Long channelId) {
        PointsRecord pointsRecord = expiryQueue.poll();
        PointsRecord pr = new PointsRecord();
        if (pointsRecord != null) {
            Long point = pointsRecordMapper.statisticsPoint(userId, channelId);
            // 获取可用积分
            BigDecimal points = pointsRecord.getPoints() != null ? pointsRecord.getPoints() : BigDecimal.ZERO;
            BigDecimal variablePoints = pointsRecord.getVariablePoints() != null ? pointsRecord.getVariablePoints() : BigDecimal.ZERO;
            // 计算可用积分余额
            double available = points.subtract(variablePoints).doubleValue();
            BeanUtil.copyProperties(pointsRecord, pr);
            if (available > actualTotal) {
                // 积分足够抵扣
                
                pointsRecord.setVariablePoints(variablePoints.add(BigDecimal.valueOf(actualTotal)));
                pr.setVariablePoints(BigDecimal.valueOf(actualTotal));
                expiryQueue.addFirst(pointsRecord);
                pointsRecord.setPointsAudit(2);//閮ㄥ垎浣跨敤
                pr.setPointsAudit(2);//閮ㄥ垎浣跨敤
                actualTotal = 0.0;
            } else if (actualTotal > available) {
                actualTotal = Arith.sub(actualTotal, available);
                // 积分部分抵扣
                pointsRecord.setVariablePoints(BigDecimal.valueOf(available));
                pr.setVariablePoints(BigDecimal.valueOf(available));
                pr.setPointsAudit(3);
                pointsRecord.setPointsAudit(3);
            } else {
                // 积分刚好抵扣
                pr.setPointsAudit(3);
                pointsRecord.setPointsAudit(3);
                pointsRecord.setVariablePoints(variablePoints.add(BigDecimal.valueOf(actualTotal)));
                pr.setVariablePoints(BigDecimal.valueOf(actualTotal));
                actualTotal = 0.0;
            }
            int update = pointsRecordMapper.updateById(pointsRecord);
            if (update > 0) {
                pr.setId(null);
                pr.setPointsType(2);
                pr.setOrderNumber(orderNumber);
                pr.setCurrentlyAvailablePoints(BigDecimal.valueOf(point).subtract(pr.getVariablePoints()));
                pr.setCreationDate(new Date());
                pointsRecordMapper.insert(pr);
            }
            // 递归处理剩余金额
            if (actualTotal > 0.0) {
                actualTotal = this.doGetOrderItemPoints(actualTotal, expiryQueue, orderNumber, userId, channelId);
            }
        }
        return actualTotal;
    }

}
