package com.zm.order.tool.server.service.impl;

import com.alibaba.fastjson.JSON;
import com.aliyun.openservices.shade.org.apache.commons.lang3.StringUtils;
import com.github.dozermapper.core.Mapper;
import com.google.common.collect.Lists;
import com.zm.order.tool.server.component.ShardingKeyGenerator;
import com.zm.order.tool.server.cy.WmKoubeiOrdersDao;
import com.zm.order.tool.server.cy.WmOrderAttachGoodsDao;
import com.zm.order.tool.server.cy.WmOrderGiveGoodsDao;
import com.zm.order.tool.server.dao.*;
import com.zm.order.tool.server.dto.OrderAddrDTO;
import com.zm.order.tool.server.manager.AsyncMessageManager;
import com.zm.order.tool.server.manager.CommonManager;
import com.zm.order.tool.server.manager.RedisManager;
import com.zm.order.tool.server.message.BatchSyncEsMessage;
import com.zm.order.tool.server.model.*;
import com.zm.order.tool.server.query.OrderAddressQuery;
import com.zm.order.tool.server.query.OrderItemQuery;
import com.zm.order.tool.server.query.OrderQuery;
import com.zm.order.tool.server.request.OrderDataReviseRequest;
import com.zm.order.tool.server.service.CyService;
import com.zm.order.tool.server.service.ExceptionConstants;
import com.zm.order.tool.server.utils.ConvertUtils;
import com.zm.util.dto.Result;
import org.apache.lucene.util.NamedThreadFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.*;
import java.util.stream.Collectors;

/**
 * @author nianchang
 * @ClassName CyServiceImpl
 * @date 2021/08/30 3:22 下午
 */
@Service
@SuppressWarnings("all")
public class CyServiceImpl implements CyService, InitializingBean {

    private static final Logger logger = LoggerFactory.getLogger(CyServiceImpl.class);

    private BlockingQueue workQueue;

    private ExecutorService executorService;

    @Autowired
    private RedisManager redisManager;

    @Autowired
    private CommonManager commonManager;
    @Autowired
    private OrderItemDao orderItemDao;

    @Autowired
    private Mapper mapper;
    @Autowired
    private OrderAddrDao orderAddrDao;

    @Autowired
    private ShardingKeyGenerator shardingKeyGenerator;

    @Autowired
    private OrderPayDetailsDao payDetailsDao;
    @Autowired
    private WmOrderAttachGoodsDao orderAttachGoodsDao;
    @Autowired
    private WmOrderGiveGoodsDao orderGiveGoodsDao;
    @Autowired
    private OrderItemBatchingDao itemBatchingDao;
    @Autowired
    private WmKoubeiOrdersDao wmKoubeiOrdersDao;
    @Autowired
    private AsyncMessageManager messageManager;

    @Autowired
    private OrderUserRelationDao ourDao;

    private static List<Integer> alipayList = new ArrayList<>();

    private static List<Integer> wechatList = new ArrayList<>();

    private static List<Integer> alipaySourceList = new ArrayList<>();

    static {
        wechatList.add(6508);
        wechatList.add(6512);
        wechatList.add(7508);
        wechatList.add(8508);
        wechatList.add(9508);
        wechatList.add(8608);
        wechatList.add(8708);

        alipayList.add(6509);
        alipayList.add(6513);
        alipayList.add(7509);
        alipayList.add(8509);
        alipayList.add(9509);
        alipayList.add(8609);
        alipayList.add(8709);

        alipaySourceList.add(2);
        alipaySourceList.add(3);
        alipaySourceList.add(6);
        alipaySourceList.add(7);
    }

    private static List<Long> sellerIdList = new ArrayList<>();

    static {
        sellerIdList.add(12321321111L);
    }

    @Override
    public Result cateringTransfer1(OrderDataReviseRequest request) {
        int count = 0;
        for (Long sellerId : sellerIdList) {
            OrderQuery orderQuery = new OrderQuery();
            orderQuery.setSellerId(sellerId);
            orderQuery.setSize(300);
            try {
                for (int i = 0; i < 8; i++) {
                    for (int j = 0; j < tbSize; j++) {
                        Long lastId = null;
                        for (;;) {
                            orderQuery.setLastId(lastId);
                            long startAt = System.currentTimeMillis();
                            List<Long> orderIdList = commonManager.scanOrderId(orderQuery, i, j);
                            if (CollectionUtils.isEmpty(orderIdList)) {
                                break;
                            }
                            List<Order> orderList = commonManager.listOrderById(orderIdList, i, j);
                            logger.info("query_time1:{}ms", System.currentTimeMillis() - startAt);
                            executeTransfer(orderList, i, j);
                            count += orderIdList.size();
                            logger.info("cateringTransfer1:{}条", count);
                            if (orderIdList.size() < 300) {
                                break;
                            }
                            lastId = orderIdList.get(orderIdList.size() - 1);
                            logger.info("cateringTransfer1_lastId:{},i:{},j:{}", lastId, i, j);
                            Result<String> redisData = redisManager.get("cateringTransfer1");
                            if (redisData.isStatus() && Objects.nonNull(redisData.getData())) {
                                return Result.successNullData();
                            }
                        }
                    }
                }
            } catch (Exception e) {
                logger.error("[cateringTransfer1]failed!cause by:{}", e);
                return Result.failureData(ExceptionConstants.SYSTEM_ERROR);
            }
        }
        return Result.successNullData();
    }

    @Override
    public Result cateringTransfer2(OrderDataReviseRequest request) {
        int count = 0;
        for (Long sellerId : sellerIdList) {
            OrderQuery orderQuery = new OrderQuery();
            orderQuery.setSellerId(sellerId);
            orderQuery.setSize(300);
            try {
                for (int i = 8; i < 16; i++) {
                    for (int j = 0; j < tbSize; j++) {
                        Long lastId = null;
                        for (;;) {
                            orderQuery.setLastId(lastId);
                            long startAt = System.currentTimeMillis();
                            List<Long> orderIdList = commonManager.scanOrderId(orderQuery, i, j);
                            if (CollectionUtils.isEmpty(orderIdList)) {
                                break;
                            }
                            List<Order> orderList = commonManager.listOrderById(orderIdList, i, j);
                            logger.info("query_time2:{}ms", System.currentTimeMillis() - startAt);
                            executeTransfer(orderList, i, j);
                            count += orderIdList.size();
                            logger.info("cateringTransfer2:{}条", count);
                            if (orderIdList.size() < 300) {
                                break;
                            }
                            lastId = orderIdList.get(orderIdList.size() - 1);
                            logger.info("cateringTransfer2_lastId:{},i:{},j:{}", lastId, i, j);
                            Result<String> redisData = redisManager.get("cateringTransfer2");
                            if (redisData.isStatus() && Objects.nonNull(redisData.getData())) {
                                return Result.successNullData();
                            }
                        }
                    }
                }
            } catch (Exception e) {
                logger.error("[cateringTransfer2]failed!cause by:{}", e);
                return Result.failureData(ExceptionConstants.SYSTEM_ERROR);
            }
        }
        return Result.successNullData();
    }

    @Override
    public Result cateringTransfer3(OrderDataReviseRequest request) {
        int count = 0;
        for (Long sellerId : sellerIdList) {
            OrderQuery orderQuery = new OrderQuery();
            orderQuery.setSellerId(sellerId);
            orderQuery.setSize(300);
            try {
                for (int i = 16; i < 24; i++) {
                    for (int j = 0; j < tbSize; j++) {
                        Long lastId = null;
                        for (;;) {
                            orderQuery.setLastId(lastId);
                            long startAt = System.currentTimeMillis();
                            List<Long> orderIdList = commonManager.scanOrderId(orderQuery, i, j);
                            if (CollectionUtils.isEmpty(orderIdList)) {
                                break;
                            }
                            List<Order> orderList = commonManager.listOrderById(orderIdList, i, j);
                            logger.info("query_time3:{}ms", System.currentTimeMillis() - startAt);
                            executeTransfer(orderList, i, j);
                            count += orderIdList.size();
                            logger.info("cateringTransfer3:{}条", count);
                            if (orderIdList.size() < 300) {
                                break;
                            }
                            lastId = orderIdList.get(orderIdList.size() - 1);
                            logger.info("cateringTransfer3_lastId:{},i:{},j:{}", lastId, i, j);
                            Result<String> redisData = redisManager.get("cateringTransfer3");
                            if (redisData.isStatus() && Objects.nonNull(redisData.getData())) {
                                return Result.successNullData();
                            }
                        }
                    }
                }
            } catch (Exception e) {
                logger.error("[cateringTransfer3]failed!cause by:{}", e);
                return Result.failureData(ExceptionConstants.SYSTEM_ERROR);
            }
        }
        return Result.successNullData();
    }

    @Override
    public Result cateringTransfer4(OrderDataReviseRequest request) {
        int count = 0;
        for (Long sellerId : sellerIdList) {
            OrderQuery orderQuery = new OrderQuery();
            orderQuery.setSellerId(sellerId);
            orderQuery.setSize(300);
            try {
                for (int i = 24; i < 32; i++) {
                    for (int j = 0; j < tbSize; j++) {
                        Long lastId = null;
                        for (;;) {
                            orderQuery.setLastId(lastId);
                            long startAt = System.currentTimeMillis();
                            List<Long> orderIdList = commonManager.scanOrderId(orderQuery, i, j);
                            if (CollectionUtils.isEmpty(orderIdList)) {
                                break;
                            }
                            List<Order> orderList = commonManager.listOrderById(orderIdList, i, j);
                            logger.info("query_time4:{}ms", System.currentTimeMillis() - startAt);
                            executeTransfer(orderList, i, j);
                            count += orderIdList.size();
                            logger.info("cateringTransfer4:{}条", count);
                            if (orderIdList.size() < 300) {
                                break;
                            }
                            lastId = orderIdList.get(orderIdList.size() - 1);
                            logger.info("cateringTransfer4_lastId:{},i:{},j:{}", lastId, i, j);
                            Result<String> redisData = redisManager.get("cateringTransfer4");
                            if (redisData.isStatus() && Objects.nonNull(redisData.getData())) {
                                return Result.successNullData();
                            }
                        }
                    }
                }
            } catch (Exception e) {
                logger.error("[cateringTransfer4]failed!cause by:{}", e);
                return Result.failureData(ExceptionConstants.SYSTEM_ERROR);
            }
        }
        return Result.successNullData();
    }

    private void executeTransfer(List<Order> orderList, int i, int j) {
        while (workQueue.remainingCapacity() < 20) {
            logger.info("workQueue size:{}", workQueue.size());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        executorService.submit(() -> {
            try {
                List<BatchSyncEsMessage> messageList = new ArrayList<>(500);

                long deletePayAt = System.currentTimeMillis();
                List<String> orderNoList = orderList.stream().map(Order::getOrderNo).collect(Collectors.toList());
                OrderQuery query = new OrderQuery();
                query.setOrderNoList(orderNoList);
//                List<OrderPayDetails> payIdList = commonManager.scanPayDetailsId(query, i, j);
//                if (!CollectionUtils.isEmpty(payIdList)) {
//                    List<Long> idList = payIdList.stream().map(OrderPayDetails::getId).collect(Collectors.toList());
//                    commonManager.deletePayDetailsById(idList, i, j);
//                }
//                logger.info("delete_pay_at_time:{}ms", System.currentTimeMillis() - deletePayAt);

                long startAt = System.currentTimeMillis();
                // 批量查询订单下的所有商品
                List<OrderItem> itemList = queryOrderItemList(orderList);
                Map<String, List<OrderAddrDTO>> addrMap = queryOrderAddressList(orderList);
                // 商品ID列表
                List<Long> itemIdList = itemList.stream().map(OrderItem::getId).collect(Collectors.toList());
                List<WmOrderAttachGoods> attachGoodsList = new ArrayList<>();
                List<WmOrderGiveGoods> orderGiveGoodsList = new ArrayList<>();
                if (!CollectionUtils.isEmpty(itemIdList)) {
                    // 商品加料
                    attachGoodsList = orderAttachGoodsDao.selectList(itemIdList);
                    // 套餐商品
                    orderGiveGoodsList = orderGiveGoodsDao.selectList(itemIdList);
                }
                // 按照订单号分组
                Map<String, List<OrderItem>> itemMap = itemList.stream().collect(Collectors.groupingBy(OrderItem::getOrderNo));
                // 新增商品加料列表
                List<OrderItemBatching> itemBatchingList = new ArrayList<>();
                // 新增套餐子商品列表
                List<OrderItem> setMealList = new ArrayList<>();
                // 更新商品itemType列表
                List<OrderItem> setMealUpdateItemList = new ArrayList<>();
                // 新增支付明细列表
                List<OrderPayDetails> payDetailsList = new ArrayList<>();
                logger.info("startAt_indexOrder_time:{}ms", System.currentTimeMillis() - startAt);

                long startAt1 = System.currentTimeMillis();
                for (Order order : orderList) {
                    messageList.add(buildMessage(order));
                    List<OrderPayDetails> orderPayList = new ArrayList<>();
                    buildOrderParam(order, itemMap, orderPayList);
                    if (!CollectionUtils.isEmpty(orderPayList)) {
                        payDetailsList.addAll(orderPayList);
                        order.setPayDetailInfo(JSON.toJSONString(orderPayList));
                    }
                    buildOrderAddress(order, addrMap);
                    buildItemBatchingParam(order, itemMap, itemBatchingList, attachGoodsList);
                    buildSetMealItem(order, setMealList, setMealUpdateItemList, itemMap, orderGiveGoodsList);
                    String itemInfo = order.getItemInfo();
                    if (!Objects.equals("TL", itemInfo)) {
                        List<InnerOrderItem> innerOrderItemList = JSON.parseArray(itemInfo, InnerOrderItem.class);
                        if (!CollectionUtils.isEmpty(innerOrderItemList) && innerOrderItemList.size() > 10) {
                            order.setItemInfo("TL");
                        }
                    }
                }
                logger.info("startAt1_indexOrder_time:{}ms", System.currentTimeMillis() - startAt1);

                // 执行变更
                long startAt2 = System.currentTimeMillis();
                commonManager.batchUpdateOrderInfo(orderList, i, j);
                logger.info("startAt2_indexOrder_time:{}ms", System.currentTimeMillis() - startAt2);

                long startAt3 = System.currentTimeMillis();
                List<OrderItem> newItemList = null;
                if (!CollectionUtils.isEmpty(setMealUpdateItemList)) {
                    newItemList = reBuildItemList(itemList, setMealUpdateItemList);
                } else {
                    newItemList = itemList;
                }
                if (!CollectionUtils.isEmpty(newItemList)) {
                    commonManager.batchUpdateItemType(newItemList, i ,j);
                }
                if (!CollectionUtils.isEmpty(setMealList)) {
                    orderItemDao.inserts(setMealList);
                }
                if (!CollectionUtils.isEmpty(itemBatchingList)) {
                    itemBatchingDao.insertList(itemBatchingList);
                }
                if (!CollectionUtils.isEmpty(payDetailsList)) {
                    payDetailsDao.insertList(payDetailsList);
                }
                logger.info("startAt3_indexOrder_time:{}ms", System.currentTimeMillis() - startAt3);

                long startAt4 = System.currentTimeMillis();
                List<BatchSyncEsMessage> pushList = new ArrayList<>(500);
                buildPushMessage(messageList, pushList);
                messageManager.sendBatchSyncMessage(pushList);
                logger.info("startAt4_indexOrder_time:{}ms", System.currentTimeMillis() - startAt4);
            } catch (Exception e) {
                logger.error("[executeTransfer]failed！cause by:{}", e);
            }
        });
    }

    private BatchSyncEsMessage buildMessage(Order order) {
        BatchSyncEsMessage message = new BatchSyncEsMessage();
        message.setUserId(order.getUserId());
        message.setId(order.getId());
        message.setOrderNo(order.getOrderNo());
        message.setOrderSubType(order.getOrderSubType());
        return message;
    }

    private List<OrderItem> reBuildItemList(List<OrderItem> itemList, List<OrderItem> setMealUpdateItemList) {
        Map<Long, List<OrderItem>> listMap = itemList.stream().collect(Collectors.groupingBy(OrderItem::getId));
        for (OrderItem orderItem : itemList) {
            listMap.put(orderItem.getId(), Lists.newArrayList(orderItem));
        }
        List<ArrayList<OrderItem>> arrayLists = listMap.values().stream().
                map(v -> (new ArrayList<OrderItem>(v))).collect(Collectors.toList());
        List<OrderItem> newItemList = new ArrayList<>();
        for (ArrayList<OrderItem> arrayList : arrayLists) {
            newItemList.addAll(arrayList);
        }
        return newItemList;
    }

    private List<OrderItem> queryOrderItemList(List<Order> orderList) {
        List<Long> userIdList = orderList.stream().map(Order::getUserId).collect(Collectors.toList());
        List<String> orderNoList = orderList.stream().map(Order::getOrderNo).collect(Collectors.toList());
        OrderItemQuery orderItemQuery = new OrderItemQuery();
        orderItemQuery.setUserIdList(userIdList);
        orderItemQuery.setOrderNoList(orderNoList);
        return orderItemDao.selectList(orderItemQuery);
    }

    private Map<String, List<OrderAddrDTO>> queryOrderAddressList(List<Order> orderList) {
        List<Long> userIdList = orderList.stream().map(Order::getUserId).collect(Collectors.toList());
        List<String> orderNoList = orderList.stream().map(Order::getOrderNo).collect(Collectors.toList());
        OrderAddressQuery query = new OrderAddressQuery();
        query.setUserIdList(userIdList);
        query.setOrderNoList(orderNoList);
        List<OrderAddrDTO> addrDTOList = ConvertUtils.convertList(orderAddrDao.selectList(query), OrderAddrDTO.class);
        if (CollectionUtils.isEmpty(addrDTOList)) {
            return Collections.EMPTY_MAP;
        }
        return addrDTOList.stream().collect(Collectors.groupingBy(OrderAddrDTO::getOrderNo));
    }

    private void buildSetMealItem(Order order, List<OrderItem> setMealList, List<OrderItem> updateItemList,
                                  Map<String, List<OrderItem>> itemMap, List<WmOrderGiveGoods> orderGiveGoodsList) {
        if (CollectionUtils.isEmpty(orderGiveGoodsList)) {
            return;
        }
        Map<Long, List<WmOrderGiveGoods>> goodsMap = orderGiveGoodsList.stream().collect(
                Collectors.groupingBy(WmOrderGiveGoods::getOrderGoodsId));

        List<OrderItem> itemList = itemMap.get(order.getOrderNo());
        if (CollectionUtils.isEmpty(itemList)) {
            return;
        }
        for (OrderItem orderItem : itemList) {
            Map<String, Object> extraMap = orderItem.getExtraMap();
            if (!CollectionUtils.isEmpty(extraMap)) {
                Object goodsType = extraMap.get("goods_type");
                if (Objects.equals(2, goodsType)) {
                    List<WmOrderGiveGoods> goodsList = goodsMap.get(orderItem.getId());
                    if (CollectionUtils.isEmpty(goodsList)) {
                        break;
                    }
                    List<InnerOrderItem> innerOrderItemList = new ArrayList<>();
                    for (WmOrderGiveGoods giveGoods : goodsList) {
                        OrderItem setMealItem = buildSetMealItem(giveGoods, orderItem);
                        setMealList.add(setMealItem);
                        innerOrderItemList.add(mapper.map(setMealItem, InnerOrderItem.class));
                    }
                    String itemInfo = order.getItemInfo();
                    if (!Objects.equals("TL", itemInfo)) {
                        if (StringUtils.isEmpty(itemInfo)) {
                            order.setItemInfo("TL");
                        } else {
                            List<InnerOrderItem> innerOrderItemList1 = JSON.parseArray(itemInfo, InnerOrderItem.class);
                            for (InnerOrderItem innerOrderItem : innerOrderItemList1) {
                                if (Objects.equals(innerOrderItem.getId(), orderItem.getId())) {
                                    innerOrderItem.setItemType(1);
                                }
                            }
                            innerOrderItemList1.addAll(innerOrderItemList);
                            order.setItemInfo(JSON.toJSONString(innerOrderItemList1));
                        }
                    }
                    // 普通商品itemType = 0 套餐商品itemType = 1 套餐子商品itemType = 2
                    orderItem.setItemType(1);
                    updateItemList.add(orderItem);
                }
            }
        }
    }

    private OrderItem buildSetMealItem(WmOrderGiveGoods giveGoods, OrderItem orderItem) {
        OrderItem setMealItem = new OrderItem();
        setMealItem.setId(shardingKeyGenerator.generateSnowflakeNumKey());
        setMealItem.setBizType(5);
        setMealItem.setOrderNo(orderItem.getOrderNo());
        setMealItem.setUserId(orderItem.getUserId());
        setMealItem.setSellerId(orderItem.getSellerId());
        setMealItem.setOwnerId(orderItem.getId());
        setMealItem.setItemType(2);
        setMealItem.setItemId(Objects.nonNull(giveGoods.getEntityId()) ? giveGoods.getEntityId() : "");
        setMealItem.setItemName(Objects.nonNull(giveGoods.getName()) ? giveGoods.getName() : "");
        setMealItem.setNum(new BigDecimal(Objects.nonNull(giveGoods.getNum()) ? giveGoods.getNum() : 0));
        setMealItem.setItemSpec(Objects.nonNull(giveGoods.getSpec()) ? giveGoods.getSpec() : "");
        setMealItem.setItemPrice(giveGoods.getPrice().intValue() * 100);
        setMealItem.setItemSign(Objects.nonNull(giveGoods.getTradeMark()) ? giveGoods.getTradeMark() : "");
        setMealItem.setItemBarcode(Objects.nonNull(giveGoods.getBarcode()) ? giveGoods.getBarcode() : "");
        setMealItem.setItemImage(Objects.nonNull(giveGoods.getImage()) ? giveGoods.getImage() : "");
        setMealItem.setPackAmount(giveGoods.getPackAmount().intValue() * 100);
        setMealItem.setProductNo(Objects.nonNull(giveGoods.getProductNo()) ? giveGoods.getProductNo() : "");
        setMealItem.setFeatures(JSON.toJSONString(giveGoods));
        setMealItem.setIsGift(0);
        setMealItem.setOrderAt(orderItem.getOrderAt());
        setMealItem.setIsTimeDiscount(0);
        setMealItem.setActivityId(0L);
        setMealItem.setfCode("");
        setMealItem.setDiscountAmount(0);
        setMealItem.setMemberPrice(0);
        setMealItem.setItemUnit("");
        setMealItem.setMarketPrice(0);
        setMealItem.setCostPrice(giveGoods.getOriginalPrice().intValue() * 100);
        setMealItem.setStatus(0);
        setMealItem.setGoodsId(0L);
        return setMealItem;
    }

    private void buildOrderAddress(Order order, Map<String, List<OrderAddrDTO>> addrMap) {
        if (!CollectionUtils.isEmpty(addrMap)) {
            List<OrderAddrDTO> list = addrMap.get(order.getOrderNo());
            if (!CollectionUtils.isEmpty(list)) {
                order.setAddrInfo(JSON.toJSONString(list.get(0)));
            }
        }
    }

    private void buildOrderParam(Order order, Map<String, List<OrderItem>> itemMap, List<OrderPayDetails> payDetailsList) {
        convertExtraMap(order);
        convertPayAmount(order);
        convertPayInfo(order);
        convertStatus(order);
        if (Objects.equals(1, order.getPayStatus())) {
            convertPayType(order, payDetailsList);
        }
        convertPerformanceType(order);
        convertOrderType(order);
        convertPerformancePlatform(order);
        convertPerformanceInfo(order);
    }

    private void buildItemBatchingParam(Order order, Map<String, List<OrderItem>> itemMap,
                                        List<OrderItemBatching> itemBatchingList, List<WmOrderAttachGoods> attachGoodsList) {
        if (!CollectionUtils.isEmpty(attachGoodsList)) {
            Map<Long, List<WmOrderAttachGoods>> map = attachGoodsList.stream().collect(
                    Collectors.groupingBy(WmOrderAttachGoods::getOrderGoodsId));
            List<InnerOrderItem> orderItemList = new ArrayList<>();

            List<OrderItem> itemList = itemMap.get(order.getOrderNo());
            if (!CollectionUtils.isEmpty(itemList)) {
                for (OrderItem orderItem : itemList) {
                    List<WmOrderAttachGoods> goodsList = map.get(orderItem.getId());
                    if (CollectionUtils.isEmpty(goodsList)) {
                        orderItemList.add(mapper.map(orderItem, InnerOrderItem.class));
                        continue;
                    }
                    List<InnerOrderItemBatching> batchingList = new ArrayList<>();
                    for (WmOrderAttachGoods batching : goodsList) {
                        OrderItemBatching itemBatching = parseItemBatching(batching, order);
                        batchingList.add(mapper.map(itemBatching, InnerOrderItemBatching.class));
                        itemBatchingList.add(itemBatching);
                    }
                    if (batchingList.size() > 10) {
                        orderItem.setBatchingInfo("TL");
                    } else {
                        orderItem.setBatchingInfo(JSON.toJSONString(batchingList));
                    }
                    orderItemList.add(mapper.map(orderItem, InnerOrderItem.class));
                }
                if (!CollectionUtils.isEmpty(orderItemList)) {
                    order.setItemInfo(JSON.toJSONString(orderItemList));
                }
            }
        }
    }

    private OrderItemBatching parseItemBatching(WmOrderAttachGoods batching, Order order) {
        OrderItemBatching itemBatching = new OrderItemBatching();
        itemBatching.setId(shardingKeyGenerator.generateSnowflakeNumKey());
        itemBatching.setUserId(order.getUserId());
        itemBatching.setOrderNo(order.getOrderNo());
        itemBatching.setSellerId(order.getSellerId());
        itemBatching.setStoreId(order.getStoreId());
        itemBatching.setBatchingId(Objects.nonNull(batching.getMaterialId()) ? batching.getMaterialId().toString() : "");
        itemBatching.setBatchingName(Objects.nonNull(batching.getName()) ? batching.getName() : "");
        itemBatching.setNum(Objects.nonNull(batching.getQty()) ? batching.getQty() : 0);
        itemBatching.setCode(Objects.nonNull(batching.getCode()) ? batching.getCode() : "");
        itemBatching.setPrice(batching.getPrice().multiply(new BigDecimal(100)));
        itemBatching.setOrderItemId(batching.getOrderGoodsId());
        return itemBatching;
    }

    private void convertPayInfo(Order order) {
        if (StringUtils.isEmpty(order.getPayInfo())) {
            Map<String, Object> payInfoMap = new HashMap<>(3);
            payInfoMap.put("walletAmount", 0);
            payInfoMap.put("amount", 0);
            payInfoMap.put("userWallet", 0);
            order.setPayInfo(JSON.toJSONString(payInfoMap));
            return;
        }
        String payInfo = order.getPayInfo();
        Map<String, Object> payInfoMap = JSON.parseObject(payInfo, Map.class);
        Object walletAmountObj = payInfoMap.get("wallet_amount");
        Object useWalletObj = payInfoMap.get("use_wallet");
        Object cashAmountObj = payInfoMap.get("cash_amount");
        Double w = 0.00;
        if (Objects.nonNull(walletAmountObj)) {
            String walletAmount = walletAmountObj.toString();
            if (walletAmount.contains(".")) {
                w = Double.valueOf(walletAmountObj.toString());
            } else {
                w = Double.valueOf(walletAmountObj.toString()) / 100;
            }
        }
        payInfoMap.put("walletAmount", w);
        payInfoMap.put("useWallet", Objects.nonNull(useWalletObj) ? Integer.valueOf(useWalletObj.toString()) : 0);
        payInfoMap.put("cashAmount", Objects.nonNull(cashAmountObj) ? Double.valueOf(cashAmountObj.toString()) / 100 : 0);
        order.setPayInfo(JSON.toJSONString(payInfoMap));

        if (Objects.nonNull(walletAmountObj)) {
            Integer walletAmount;
            String walletAmountStr = payInfoMap.get("wallet_amount").toString();
            if (walletAmountStr.contains(".")) {
                walletAmount = new BigDecimal(walletAmountStr).multiply(new BigDecimal(100)).intValue();
            } else {
                walletAmount = Integer.valueOf(walletAmountStr);
            }
            if (walletAmount > 0) {
                List<String> list = new ArrayList<>(1);
                Map<String, Object> map = new HashMap<>(3);
                map.put("bizId", order.getOrderNo());
                if (Objects.nonNull(payInfoMap.get("change_gift_amount"))
                        && Objects.nonNull(payInfoMap.get("change_recharge_amount"))) {
                    map.put("giftAmount", Double.valueOf(payInfoMap.get("change_gift_amount").toString()) / 100);
                    map.put("rechargeAmount", Double.valueOf(payInfoMap.get("change_recharge_amount").toString()) / 100);
                } else {
                    map.put("giftAmount", 0);
                    map.put("rechargeAmount", Double.valueOf(walletAmount) / 100);
                }
                list.add(JSON.toJSONString(map));
                payInfoMap.put("walletPayDetail", list);
                order.setPayInfo(JSON.toJSONString(payInfoMap));
            }
        }
    }

    private void convertStatus(Order order) {
        if (Objects.equals(1, order.getStatus())) {
            order.setStatus(10);
            return;
        }
        if (Objects.equals(2, order.getStatus())) {
            order.setStatus(20);
            return;
        }
        if (Objects.equals(3, order.getStatus())) {
            order.setStatus(60);
            return;
        }
        if (Objects.equals(5, order.getStatus())) {
            order.setStatus(50);
            return;
        }
        if (Objects.equals(6, order.getStatus()) && Objects.equals(0, order.getPayStatus())) {
            order.setStatus(60);
            return;
        }
        if (Objects.equals(6, order.getStatus()) && Objects.equals(1, order.getPayStatus())) {
            order.setStatus(70);
            return;
        }
        if (Objects.equals(6, order.getStatus()) && Objects.equals(2, order.getPayStatus())) {
            order.setStatus(60);
            return;
        }
        if (Objects.equals(10, order.getStatus())) {
            order.setStatus(30);
            return;
        }
        if (Objects.equals(11, order.getStatus())) {
            order.setStatus(70);
            return;
        }
        if (Objects.equals(12, order.getStatus())) {
            order.setStatus(40);
            return;
        }
        if (Objects.equals(13, order.getStatus())) {
            order.setStatus(30);
            return;
        }
    }

    private void convertPayType(Order order, List<OrderPayDetails> payDetailsList) {
        setPayDetails(order, payDetailsList);
    }

    private void setPayDetails(Order order, List<OrderPayDetails> payDetailsList) {
        Integer payType = order.getPayType();
        String payInfo = order.getPayInfo();
        if (!StringUtils.isEmpty(payInfo)) {
            Map<String, Object> payInfoMap = JSON.parseObject(payInfo);
            Integer useWallet = Objects.nonNull(payInfoMap.get("use_wallet")) ?
                    Integer.valueOf(payInfoMap.get("use_wallet").toString()) : null;
            String amountStr = Objects.nonNull(payInfoMap.get("amount")) ? payInfoMap.get("amount").toString() : "0";
            Integer amount = 0;
            if (amountStr.contains(".")) {
                amount = new BigDecimal(amountStr).multiply(new BigDecimal(100)).intValue();
            }else {
                amount = Integer.valueOf(amountStr);
            }

            Integer walletAmount = 0;
            String walletAmountStr = Objects.nonNull(payInfoMap.get("wallet_amount")) ?
                    payInfoMap.get("wallet_amount").toString() : "0";
            if (walletAmountStr.contains(".")) {
                walletAmount = new BigDecimal(walletAmountStr).multiply(new BigDecimal(100)).intValue();
            }else {
                walletAmount = Integer.valueOf(walletAmountStr);
            }

            // from_system = 1  --> payType = 7 在线支付
            if (Objects.equals(1, order.getFromSystem())) {
                order.setPayType(7);
                OrderPayDetails payDetails = buildPayDetails(7, order, amount);
                payDetailsList.add(payDetails);
                return;
            }
            // 余额 + 三方
            if (walletAmount > 0) {
                // 如果amount = 0 那么就是一种支付方式：余额支付（4），如果大于0，那么就是混合支付 payType = 9 混合支付
                if (amount == 0) {
                    order.setPayType(4);
                    OrderPayDetails payDetails = buildPayDetails(4, order, walletAmount);
                    payDetailsList.add(payDetails);
                    return;
                }
                // 混合支付
                if (amount > 0) {
                    order.setPayType(9);
                    OrderPayDetails payDetails1 = buildPayDetails(4, order, walletAmount);
                    Integer newPayType = mapThirdPay(payType);
                    OrderPayDetails payDetails2 = buildPayDetails(newPayType, order, amount);
                    payDetailsList.add(payDetails1);
                    payDetailsList.add(payDetails2);
                    return;
                }
            }
            // 现金 + 三方支付
            if (Objects.equals(19, order.getSource())) {
                Object cashAmountObj = payInfoMap.get("cash_amount");
                Object thirdAmountObj = payInfoMap.get("third_amount");
                if (Objects.nonNull(cashAmountObj) && Objects.nonNull(thirdAmountObj)) {
                    Integer cashAmount = Integer.valueOf(cashAmountObj.toString());
                    Integer thirdAmount = Integer.valueOf(thirdAmountObj.toString());
                    if (cashAmount > 0 && thirdAmount > 0) {
                        // 混合支付场景 现金 + 三方支付 payType = 99
                        order.setPayType(99);
                        OrderPayDetails cashPay = buildPayDetails(12, order, cashAmount);
                        OrderPayDetails thirdPay = buildPayDetails(mapThirdPay(payType), order, thirdAmount);
                        payDetailsList.add(cashPay);
                        payDetailsList.add(thirdPay);
                        return;
                    }
                }
            }
            // 三方支付
            if (amount > 0) {
                Integer newPayType = mapThirdPay(payType);
                order.setPayType(newPayType);
                OrderPayDetails payDetails = buildPayDetails(newPayType, order, amount);
                payDetailsList.add(payDetails);
                return;
            }
            // 免支付 payType = 16 新餐饮
            if (Objects.equals(0, order.getActualAmount())) {
                order.setPayType(16);
                OrderPayDetails payDetails = buildPayDetails(16, order, 0);
                payDetailsList.add(payDetails);
                return;
            }
            // 未匹配到的支付类型
            OrderPayDetails payDetails = buildPayDetails(mapThirdPay(order.getPayType()), order, amount);
            payDetailsList.add(payDetails);
        }
    }

    private Integer mapThirdPay(Integer payType) {
        if (alipayList.contains(payType)) {
            payType = 2;
            return payType;
        }
        if (wechatList.contains(payType)) {
            payType = 1;
            return payType;
        }
        // 云闪付
        if (Objects.equals(6514, payType)) {
            payType = 15;
            return payType;
        }
        if (Objects.equals(4, payType)) {
            payType = 12;
            return payType;
        }
        if (Objects.equals(10, payType)) {
            payType = 13;
            return payType;
        }
        if (Objects.equals(13, payType)) {
            payType = 10;
            return payType;
        }
        if (Objects.equals(12, payType)) {
            payType = 16;
            return payType;
        }
        return payType;
    }

    private OrderPayDetails buildPayDetails(Integer payType, Order order, Integer amount) {
        OrderPayDetails payDetails = new OrderPayDetails();
        payDetails.setId(shardingKeyGenerator.generateSnowflakeNumKey());
        payDetails.setOrderNo(order.getOrderNo());
        payDetails.setUserId(order.getUserId());
        payDetails.setSellerId(order.getSellerId());
        payDetails.setStoreId(order.getStoreId());
        payDetails.setStoreId(order.getStoreId());
        payDetails.setAmount(amount);
        payDetails.setPayType(payType);
        payDetails.setPayNo(!StringUtils.isEmpty(order.getPayNo()) ? order.getPayNo() : "");
        payDetails.setThirdPayNo(!StringUtils.isEmpty(order.getThirdPayNo()) ? order.getThirdPayNo() : "");
        payDetails.setOrderAt(order.getOrderAt());
        payDetails.setPayAt(Objects.nonNull(order.getPayAt()) ? order.getPayAt() : order.getOrderAt());
        payDetails.setOrderType(order.getOrderType());
        payDetails.setSource(Objects.nonNull(order.getSource()) ? order.getSource() : 0);
        return payDetails;
    }

    private void convertPayAmount(Order order) {
        // 三方支付
        if (!alipayList.contains(order.getPayType()) && !wechatList.contains(order.getPayType())) {
            order.setPayAmount(0);
            return;
        }
        String payInfo = order.getPayInfo();
        if (StringUtils.isEmpty(payInfo)) {
            return;
        }
        Map payInfoMap = JSON.parseObject(payInfo, Map.class);
        Object amountObj = payInfoMap.get("amount");
        Object cashAmountObj = payInfoMap.get("cash_amount");
        Object thirdAmountObj = payInfoMap.get("third_amount");
        // 组合支付 三方 + 现金
        if (Objects.equals(19, order.getSource())) {
            if (Objects.nonNull(cashAmountObj) && Objects.nonNull(thirdAmountObj)) {
                Integer cashAmount = Integer.valueOf(cashAmountObj.toString());
                Integer thirdAmount = Integer.valueOf(thirdAmountObj.toString());
                if (cashAmount > 0 && thirdAmount > 0) {
                    order.setPayAmount(thirdAmount);
                    return;
                }
            }
        }
        // 三方支付 / 三方 + 余额
        if (Objects.nonNull(amountObj)) {
            order.setPayAmount(Integer.valueOf(amountObj.toString()));
            return;
        }
    }

    private void convertPerformanceType(Order order) {
        if (Objects.equals(1, order.getPerformanceType())) {
            order.setPerformanceType(2);
            return;
        }
        if (Objects.equals(2, order.getPerformanceType())) {
            order.setPerformanceType(4);
            return;
        }
        if (Objects.equals(3, order.getPerformanceType())) {
            order.setPerformanceType(6);
            return;
        }
        if (Objects.equals(4, order.getPerformanceType())) {
            order.setPerformanceType(3);
            return;
        }
        if (Objects.equals(5, order.getPerformanceType())) {
            order.setPerformanceType(7);
            return;
        }
        if (Objects.equals(6, order.getPerformanceType())) {
            order.setPerformanceType(8);
            return;
        }
        if (Objects.equals(7, order.getPerformanceType())) {
            order.setPerformanceType(1);
            return;
        }
    }

    private void convertPerformancePlatform(Order order) {
        if (!Objects.equals(1, order.getPerformanceStatus())) {
            return;
        }
        if (!Objects.equals(3, order.getOrderType())) {
            return;
        }
        if (Objects.equals("0", order.getPerformancePlatform())) {
            order.setPerformancePlatform("商家自配");
            return;
        }
        if (Objects.equals("1", order.getPerformancePlatform())) {
            order.setPerformancePlatform("蜂鸟");
            return;
        }
        if (Objects.equals("2", order.getPerformancePlatform())) {
            order.setPerformancePlatform("达达");
            return;
        }
        if (Objects.equals("3", order.getPerformancePlatform())) {
            order.setPerformancePlatform("UU跑腿");
            return;
        }
        if (Objects.equals("4", order.getPerformancePlatform())) {
            order.setPerformancePlatform("顺丰");
            return;
        }
        if (Objects.equals("5", order.getPerformancePlatform())) {
            order.setPerformancePlatform("点我达");
            return;
        }
        if (Objects.equals("6", order.getPerformancePlatform())) {
            order.setPerformancePlatform("餐道");
            return;
        }
        if (Objects.equals("7", order.getPerformancePlatform())) {
            order.setPerformancePlatform("美团");
            return;
        }
    }

    private void convertOrderType(Order order) {
        if (Objects.equals(6, order.getOrderType())) {
            WmKoubeiOrders koubeiOrders = wmKoubeiOrdersDao.selectOne(order.getOrderNo());
            if (koubeiOrders != null) {
                order.setOrderType(Objects.equals(koubeiOrders.getIsToGo(), 1) ? 2 : 1);
                Map<String, Object> extraMap = order.getExtraMap();
                extraMap.put("wmKoubeiOrders", JSON.toJSONString(koubeiOrders));
                order.setExtraMap(extraMap);
            } else {
                order.setOrderType(1);
            }
        }
    }

    private void convertPerformanceInfo(Order order) {
        String performanceInfo = order.getPerformanceInfo();
        if (!StringUtils.isEmpty(performanceInfo)) {
            Map<String, Object> map = JSON.parseObject(performanceInfo, Map.class);
            if (map.containsKey("sent_at")) {
                map.put("sentAt", map.get("sent_at"));
                order.setPerformanceInfo(JSON.toJSONString(map));
            }
        }
    }

    private void convertExtraMap(Order order) {
        Map<String, Object> extraMap = order.getExtraMap();
        if (CollectionUtils.isEmpty(extraMap)) {
            extraMap = new HashMap<>(10);
        }
        extraMap.put("isHistoryOrder", 1);
        extraMap.put("historyOrderType", order.getOrderType());
        extraMap.put("historyPayType", order.getPayType());
        extraMap.put("historyStatus", order.getStatus());
        extraMap.put("historyPlatform", order.getPerformancePlatform());
        extraMap.put("historyPerformanceType", order.getPerformanceType());
        extraMap.put("historyPayAmount", order.getPayAmount());
        extraMap.put("historyBizType", 1);
        if (extraMap.containsKey("sync_erp_error")) {
            extraMap.put("syncError", extraMap.get("sync_erp_error"));
        }
        if (extraMap.containsKey("erp_sync_error_reason")) {
            extraMap.put("syncErrorReason", extraMap.get("erp_sync_error_reason"));
        }
        if (extraMap.containsKey("flavor_card_minus")) {
            extraMap.put("flavorCardMinus", extraMap.get("flavor_card_minus"));
        }
        if (extraMap.containsKey("invoice_status")) {
            extraMap.put("invoiceStatus", extraMap.get("invoice_status"));
        }
        order.setExtraMap(extraMap);
    }

    private void buildPushMessage(List<BatchSyncEsMessage> messageList, List<BatchSyncEsMessage> pushList) {
        if (!CollectionUtils.isEmpty(messageList)) {
            for (BatchSyncEsMessage message : messageList) {
                if (Objects.equals(1, message.getOrderSubType())) {
                    OrderUserRelation relation = ourDao.selectByOrderNo(message.getOrderNo(), message.getUserId());
                    if (relation == null) {
                        pushList.add(message);
                        continue;
                    }
                    if (Objects.equals(0, relation.getIsRoot())) {
                        pushList.add(message);
                    }
                } else {
                    pushList.add(message);
                }
            }
        }
    }

    @Value("${new.sharding.db.size}")
    private int dbSize;

    @Value("${new.sharding.tb.size}")
    private int tbSize;

    @Override
    public void afterPropertiesSet() throws Exception {
        int coreSize = Runtime.getRuntime().availableProcessors();
        workQueue = new ArrayBlockingQueue(512);
        executorService = new ThreadPoolExecutor(12, 20, 1, TimeUnit.MINUTES, workQueue, new NamedThreadFactory("order-data-sync"),
                new ThreadPoolExecutor.AbortPolicy());
    }
}
