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

/**
 * @author: Z.X.F
 * @date: 2023/10/11
 * @className: IntelliJ IDEA
 * @description:
 */

import com.github.dozermapper.core.Mapper;
import com.google.common.collect.Lists;
import com.zm.order.tool.server.constants.CommonConstants;
import com.zm.order.tool.server.constants.ListConst;
import com.zm.order.tool.server.dao.*;
import com.zm.order.tool.server.dto.OrderInfoList;
import com.zm.order.tool.server.history.*;
import com.zm.order.tool.server.hithistory.HintHistoryOrderDao;
import com.zm.order.tool.server.manager.DistributedCacheManager;
import com.zm.order.tool.server.manager.OBHistoryHintManager;
import com.zm.order.tool.server.manager.SearchManager;
import com.zm.order.tool.server.model.*;
import com.zm.order.tool.server.query.*;
import com.zm.order.tool.server.request.history.HistoryOrderRequest;
import com.zm.order.tool.server.response.*;
import com.zm.order.tool.server.service.ExceptionConstants;
import com.zm.order.tool.server.service.HistoryOrderService;
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.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.*;
import java.util.stream.Collectors;

/**
 * @author zhuxiaofeng
 * @packageName: com.zm.order.tool.server.service.impl
 * @className: HistoryOrderServiceImpl
 * @date 2023/10/11 15:17
 */
@Service
@SuppressWarnings("all")
public class HistoryOrderServiceImpl implements HistoryOrderService, InitializingBean {

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

    @Autowired
    private Mapper mapper;

    /**
     * 冷库
     */
    @Autowired
    private HistoryDataOrderDao historyDataOrderDao;
    @Autowired
    private HistoryDataOrderItemDao historyDataOrderItemDao;
    @Autowired
    private HistoryDataOrderDiscountDao historyDataOrderDiscountDao;
    @Autowired
    private HistoryDataOrderIndexDao historyDataOrderIndexDao;
    @Autowired
    private HistoryDataPayDetailsDao historyDataPayDetailsDao;
    @Autowired
    private HistoryDataRefundDao historyRefundDao;
    @Autowired
    private HistoryDataRefundDetailsDao historyRefundDetailsDao;
    @Autowired
    private HistoryDataOrderAddressDao historyDataOrderAddressDao;

    @Autowired
    private HistoryDataItemBatchingDao historyDataItemBatchingDao;

    @Autowired
    private HistoryDataSelfTakeDao historyDataSelfTakeDao;

    /**
     * 业务库
     */
    @Autowired
    private OrderDao orderDao;
    @Autowired
    private OrderItemDao itemDao;
    @Autowired
    private OrderDiscountDao discountDao;
    @Autowired
    private OrderIndexDao indexDao;
    @Autowired
    private OrderPayDetailsDao payDao;
    @Autowired
    private RefundDao refundDao;
    @Autowired
    private OrderRefundDetailsDao refundDetailsDao;
    @Autowired
    private OrderAddrDao addrDao;
    @Autowired
    private OrderItemBatchingDao itemBatchingDao;
    @Autowired
    private PerformanceSelfTakeDao takeDao;

    @Override
    public Result<List<OrderVO>> select(HistoryOrderRequest request) {
        Result<List<OrderVO>> result = new Result<>();
        try {
            if (StringUtils.isEmpty(request.getOrderNo()) && Objects.isNull(request.getUserId())) {
                return Result.failureData("订单号手机号不能都为空");
            }

            OrderInfoList orderInfoList = selectInfo(request);

            List<OrderVO> convert = this.convert(orderInfoList);
            result.setData(convert);
            result.setStatus(true);
        } catch (Throwable e) {
            logger.error("HistoryOrderServiceImpl[select] failed!, cause by:{}", e);
            result.setException(ExceptionConstants.SYSTEM_ERROR);
        }
        return result;
    }

    private OrderInfoList selectInfo(HistoryOrderRequest request) {
        OrderQuery query = mapper.map(request, OrderQuery.class);
        OrderItemQuery itemQuery = mapper.map(request, OrderItemQuery.class);
        OrderDiscountQuery discountQuery = mapper.map(request, OrderDiscountQuery.class);
        OrderPayDetailsQuery payDetailsQuery = mapper.map(request, OrderPayDetailsQuery.class);

        if (Objects.isNull(request.getUserId())) {
            OrderIndex orderNoIndex = indexDao.selectOne(request.getOrderNo());
            if (Objects.isNull(orderNoIndex)) {
                throw new RuntimeException("订单索引不存在");
            }
            query.setUserId(orderNoIndex.getUserId());
            itemQuery.setUserId(orderNoIndex.getUserId());
            discountQuery.setUserId(orderNoIndex.getUserId());
            payDetailsQuery.setUserId(orderNoIndex.getUserId());
        }
        List<Order> orderList = historyDataOrderDao.selectList(query);

        List<OrderItem> itemList = historyDataOrderItemDao.selectList(itemQuery);

        List<OrderDiscount> discountList = historyDataOrderDiscountDao.selectList(discountQuery);

        List<OrderPayDetails> payDetailsList = historyDataPayDetailsDao.selectList(payDetailsQuery);

        List<OrderAddr> orderAddrList = historyDataOrderAddressDao.selectList(query);

        List<Refund> refundList = historyRefundDao.selectListOrder(query);

        List<OrderRefundDetails> orderRefundDetails = historyRefundDetailsDao.selectListOrder(query);

        // List<OrderIndex> indexList = historyDataOrderIndexDao.selectByOrderNoList(orderNoList);

        List<OrderItemBatching> itemBatchings =
            historyDataItemBatchingDao.selectByOrderNoList(Lists.newArrayList(request.getOrderNo()), query.getUserId());

        List<PerformanceSelfTake> takeList = historyDataSelfTakeDao.selectByOrderNoList(Lists.newArrayList(request.getOrderNo()), query.getUserId());

        OrderInfoList list = new OrderInfoList();
        list.setOrderList(orderList);
        list.setItemList(itemList);
        list.setDiscountList(discountList);
        list.setPayDetailsList(payDetailsList);
        list.setOrderAddrList(orderAddrList);
        list.setRefundList(refundList);
        list.setOrderRefundDetails(orderRefundDetails);
        // list.setOrderIndexList(indexList);
        list.setItemBatchingList(itemBatchings);
        list.setSelfTakeList(takeList);
        return list;
    }

    private List<OrderVO> convert(OrderInfoList infoList) {

        List<Order> orderList = infoList.getOrderList();
        List<OrderItem> itemList = infoList.getItemList();
        List<OrderDiscount> discountList = infoList.getDiscountList();
        List<OrderPayDetails> payDetailsList = infoList.getPayDetailsList();
        List<OrderAddr> orderAddrList = infoList.getOrderAddrList();
        List<Refund> refundList = infoList.getRefundList();
        List<OrderRefundDetails> orderRefundDetails = infoList.getOrderRefundDetails();

        List<OrderVO> orderVOS = ConvertUtils.convertList(orderList, OrderVO.class);

        Map<String, List<OrderItem>> itemMap = itemList.stream().collect(Collectors.groupingBy(OrderItem::getOrderNo));
        Map<String, List<OrderDiscount>> discountMap =
            discountList.stream().collect(Collectors.groupingBy(OrderDiscount::getOrderNo));
        Map<String, List<OrderPayDetails>> payMap =
            payDetailsList.stream().collect(Collectors.groupingBy(OrderPayDetails::getOrderNo));
        Map<String, List<OrderAddr>> addrMap =
            orderAddrList.stream().collect(Collectors.groupingBy(OrderAddr::getOrderNo));
        Map<String, List<Refund>> refundMap = refundList.stream().collect(Collectors.groupingBy(Refund::getOrderNo));
        for (OrderVO orderVO : orderVOS) {
            if (itemMap.containsKey(orderVO.getOrderNo())) {
                orderVO.setItemList(ConvertUtils.convertList(itemMap.get(orderVO.getOrderNo()), OrderItemVO.class));
            }
            if (discountMap.containsKey(orderVO.getOrderNo())) {
                orderVO.setDiscountList(
                    ConvertUtils.convertList(discountMap.get(orderVO.getOrderNo()), OrderDiscountVO.class));
            }
            if (payMap.containsKey(orderVO.getOrderNo())) {
                orderVO.setPayDetailsList(
                    ConvertUtils.convertList(payMap.get(orderVO.getOrderNo()), OrderPayDetailsVO.class));
            }
            if (addrMap.containsKey(orderVO.getOrderNo())) {
                orderVO.setOrderAddr(mapper.map(addrMap.get(orderVO.getOrderNo()).get(0), OrderAddrVO.class));
            }
            if (refundMap.containsKey(orderVO.getOrderNo())) {
                orderVO.setRefundList(ConvertUtils.convertList(refundMap.get(orderVO.getOrderNo()), RefundVO.class));
            }
        }
        return orderVOS;
    }

    @Override
    public Result<List<OrderVO>> selectAndInsert(HistoryOrderRequest request) {
        Result<List<OrderVO>> result = new Result<>();
        try {
            if (StringUtils.isEmpty(request.getOrderNo()) && Objects.isNull(request.getUserId())) {
                return Result.failureData("订单号手机号不能都为空");
            }

            OrderInfoList orderInfoList = selectInfo(request);
            checkAndInsert(orderInfoList);
            List<OrderVO> convert = this.convert(orderInfoList);
            result.setData(convert);
            result.setStatus(true);
        } catch (Throwable e) {
            logger.error("HistoryOrderServiceImpl[select] failed!, cause by:{}", e);
            result.setException(ExceptionConstants.SYSTEM_ERROR);
        }
        return result;
    }

    @Override
    public void batchSelectAndInsert(List<String> orderNoList, Integer syncFlag) {
        if (!CollectionUtils.isEmpty(orderNoList)) {
            for (String orderNo : orderNoList) {
                OrderIndex index = indexDao.selectOne(orderNo);
                if (index != null) {
                    HistoryOrderRequest request = new HistoryOrderRequest();
                    request.setUserId(index.getUserId());
                    request.setOrderNo(index.getOrderNo());
                    selectAndInsert(request);
                }
            }
        } else if (syncFlag == 1) {
            for (String orderNo : ListConst.list) {
                OrderIndex index = indexDao.selectOne(orderNo);
                if (index != null) {
                    HistoryOrderRequest request = new HistoryOrderRequest();
                    request.setUserId(index.getUserId());
                    request.setOrderNo(index.getOrderNo());
                    selectAndInsert(request);
                }
            }
        }
    }

    @Transactional(rollbackFor = RuntimeException.class)
    public void checkAndInsert(OrderInfoList infoList) {
        try {
            List<Order> orderList = infoList.getOrderList();
            List<OrderItem> itemList = infoList.getItemList();
            List<OrderDiscount> discountList = infoList.getDiscountList();
            List<OrderPayDetails> payDetailsList = infoList.getPayDetailsList();
            List<OrderAddr> orderAddrList = infoList.getOrderAddrList();
            List<Refund> refundList = infoList.getRefundList();
            List<OrderRefundDetails> orderRefundDetails = infoList.getOrderRefundDetails();
            List<OrderIndex> orderIndexList = infoList.getOrderIndexList();
            List<OrderItemBatching> itemBatchingList = infoList.getItemBatchingList();
            List<PerformanceSelfTake> selfTakeList = infoList.getSelfTakeList();

            if (!CollectionUtils.isEmpty(orderList)) {
                for (Order order : orderList) {
                    if (orderDao.selectByOrderNo(order.getOrderNo(), order.getUserId()) == null) {
                        orderDao.insertList(Lists.newArrayList(order));
                    }
                }
//                if (orderList.size() > CommonConstants.INSERT_LIMIT) {
//                    List<List<Order>> partition = Lists.partition(orderList, CommonConstants.INSERT_LIMIT);
//                    partition.forEach(each -> orderDao.insertList(each));
//                } else {
//                    if (orderDao.selectByOrderNo(orderList.get(0).getOrderNo(), orderList.get(0).getUserId()) == null) {
//                        orderDao.insertList(orderList);
//                    }
//                }
            }
            if (!CollectionUtils.isEmpty(itemList)) {
                for (OrderItem item : itemList) {
                    OrderItem itemDo = itemDao.selectById(item.getId(), item.getUserId());
                    if (itemDo == null) {
                        item.setUpdatedAt(new Date());
                        itemDao.insertList(Lists.newArrayList(item));
                    }
                }
//                if (itemList.size() > CommonConstants.INSERT_LIMIT) {
//                    List<List<OrderItem>> partition = Lists.partition(itemList, CommonConstants.INSERT_LIMIT);
//                    partition.forEach(each -> itemDao.inserts(each));
//                } else {
//                    OrderItem orderItem = itemList.get(0);
//                    List<OrderItem> items = itemDao.selectByOrderNo(orderItem.getOrderNo(), orderItem.getUserId());
//                    if (CollectionUtils.isEmpty(items)) {
//                        itemDao.inserts(itemList);
//                    }
//                }
            }
            if (!CollectionUtils.isEmpty(discountList)) {
                for (OrderDiscount discount : discountList) {
                    OrderDiscount dis = discountDao.selectOne(discount.getId(), discount.getUserId());
                    if (dis == null) {
                        discountDao.inserts(Lists.newArrayList(discount));
                    }
                }
//                if (discountList.size() > CommonConstants.INSERT_LIMIT) {
//                    List<List<OrderDiscount>> partition = Lists.partition(discountList, CommonConstants.INSERT_LIMIT);
//                    partition.forEach(each -> discountDao.inserts(each));
//                } else {
//                    OrderDiscount discount = discountList.get(0);
//                    List<OrderDiscount> discounts =
//                        discountDao.selectByOrderNo(discount.getOrderNo(), discount.getUserId());
//                    if (CollectionUtils.isEmpty(discounts)) {
//                        discountDao.inserts(discountList);
//                    }
//                }
            }
            if (!CollectionUtils.isEmpty(payDetailsList)) {
                for (OrderPayDetails details : payDetailsList) {
                    OrderPayDetails payDetails = payDao.selectOne(details.getId(), details.getUserId());
                    if (payDetails == null) {
                        details.setUpdatedAt(new Date());
                        payDao.inserts(Lists.newArrayList(details));
                    }
                }
//                if (payDetailsList.size() > CommonConstants.INSERT_LIMIT) {
//                    List<List<OrderPayDetails>> partition =
//                        Lists.partition(payDetailsList, CommonConstants.INSERT_LIMIT);
//                    partition.forEach(each -> payDao.insertList(each));
//                } else {
//                    OrderPayDetails details = payDetailsList.get(0);
//                    List<OrderPayDetails> details1 = payDao.selectByOrderNo(details.getOrderNo(), details.getUserId());
//                    if (CollectionUtils.isEmpty(details1)) {
//                        payDao.insertList(payDetailsList);
//                    }
//                }
            }
            if (!CollectionUtils.isEmpty(orderAddrList)) {
                for (OrderAddr addr : orderAddrList) {
                    OrderAddr addr1 = addrDao.selectByOrderNo(addr.getOrderNo(), addr.getUserId());
                    if (addr1 == null) {
                        addrDao.insert(addr);
                    }
                }
//                if (orderAddrList.size() > CommonConstants.INSERT_LIMIT) {
//                    List<List<OrderAddr>> partition = Lists.partition(orderAddrList, CommonConstants.INSERT_LIMIT);
//                    partition.forEach(each -> addrDao.inserts(each));
//                } else {
//                    OrderAddr addr = orderAddrList.get(0);
//                    if (addrDao.selectByOrderNo(addr.getOrderNo(), addr.getUserId()) == null) {
//                        addrDao.inserts(orderAddrList);
//                    }
//                }
            }
            // 退款单
//            if (!CollectionUtils.isEmpty(refundList)) {
//                if (refundList.size() > CommonConstants.INSERT_LIMIT) {
//                    List<List<Refund>> partition = Lists.partition(refundList, CommonConstants.INSERT_LIMIT);
//                    partition.forEach(each -> refundDao.insertList(each));
//                } else {
//                    if (CollectionUtils.isEmpty(refundDao.selectByOrderNo(refundList.get(0).getOrderNo()))) {
//                        refundDao.insertList(refundList);
//                    }
//                }
//            }
            // 退款明细
//            if (!CollectionUtils.isEmpty(orderRefundDetails)) {
//                if (orderRefundDetails.size() > CommonConstants.INSERT_LIMIT) {
//                    List<List<OrderRefundDetails>> partition =
//                        Lists.partition(orderRefundDetails, CommonConstants.INSERT_LIMIT);
//                    partition.forEach(each -> refundDetailsDao.insertList(each));
//                } else {
//                    if (CollectionUtils
//                        .isEmpty(refundDetailsDao.selectByRefundNo(orderRefundDetails.get(0).getRefundNo()))) {
//                        refundDetailsDao.insertList(orderRefundDetails);
//                    }
//                }
//            }
            // if (!CollectionUtils.isEmpty(orderIndexList)) {
            // if (orderIndexList.size() > CommonConstants.INSERT_LIMIT) {
            // List<List<OrderIndex>> partition = Lists.partition(
            // orderIndexList, CommonConstants.INSERT_LIMIT);
            // partition.forEach(each -> indexDao.insertList(each));
            // } else {
            // indexDao.insertList(orderIndexList);
            // }
            // }

            if (!CollectionUtils.isEmpty(itemBatchingList)) {
                if (itemBatchingList.size() > CommonConstants.INSERT_LIMIT) {
                    List<List<OrderItemBatching>> partition =
                        Lists.partition(itemBatchingList, CommonConstants.INSERT_LIMIT);
                    partition.forEach(each -> itemBatchingDao.insertList(each));
                } else {
                    ItemBatchingQuery query = new ItemBatchingQuery();
                    query.setUserId(itemBatchingList.get(0).getUserId());
                    query.setOrderNo(itemBatchingList.get(0).getOrderNo());
                    if (CollectionUtils.isEmpty(itemBatchingDao.selectList(query))) {
                        itemBatchingDao.inserts(itemBatchingList);
                    }
                }
            }
            if (!CollectionUtils.isEmpty(selfTakeList)) {
                for (PerformanceSelfTake selfTake : selfTakeList) {
                    PerformanceSelfTake selfTake1 = takeDao.selectOne(selfTake.getOrderNo(), selfTake.getUserId());
                    if (selfTake1 == null) {
                        takeDao.insert(selfTake);
                    }
                }
//                if (selfTakeList.size() > CommonConstants.INSERT_LIMIT) {
//                    List<List<PerformanceSelfTake>> partition =
//                        Lists.partition(selfTakeList, CommonConstants.INSERT_LIMIT);
//                    partition.forEach(each -> takeDao.insertList(each));
//                } else {
//                    PerformanceSelfTake take = selfTakeList.get(0);
//                    if (takeDao.selectOne(take.getOrderNo(), take.getUserId()) == null) {
//                        takeDao.insertList(selfTakeList);
//                    }
//                }
            }
        } catch (Throwable e) {
            logger.error("checkAndInsert[checkAndInsert] failed!, cause by:{}", e);
            throw new RuntimeException("归档数据新增业务库失败");
        }

    }

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

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

    private BlockingQueue workQueue;

    private ExecutorService executorService;

    @Autowired
    private HintHistoryOrderDao hintHistoryOrderDao;

    @Autowired
    private DistributedCacheManager cacheManager;

    @Override
    public void afterPropertiesSet() throws Exception {
        workQueue = new ArrayBlockingQueue(64);
        executorService = new ThreadPoolExecutor(4, 10, 1, TimeUnit.MINUTES, workQueue,
            new NamedThreadFactory("script-order-data-thread"), new ThreadPoolExecutor.AbortPolicy());
    }

    @Autowired
    private SearchManager searchManager;

    @Autowired
    private OBHistoryHintManager historyHintManager;

    @Override
    public void inHistoryOrder(Long sellerId) {
        try {
            int count = 0;
            OrderQuery query = new OrderQuery();
            query.setStatus(2);
            query.setPageSize(200);
            query.setSellerId(sellerId);
            for (int i = 0; i < dbSize; i++) {
                for (int j = 0; j < tbSize; j++) {
                    int pageNo = 1;
                    Long lastId = 0L;
                    for (;;) {
                        query.setPageNo(pageNo);
                        // 查询
                        List<Order> orderList = historyHintManager.scanOrderList(query, i, j);
                        if (CollectionUtils.isEmpty(orderList)) {
                            break;
                        }
                        executeSync(orderList);

                        count += orderList.size();
                        logger.info("inHistoryOrder, i:{}, j:{}, count:{}条", i, j, count);

                        if (orderList.size() < 200) {
                            break;
                        }
                        Result<String> redisData = cacheManager.get("in_history_order_222_key");
                        if (redisData.isStatus() && Objects.nonNull(redisData.getData())) {
                            return;
                        }
                        pageNo++;
                        lastId = orderList.get(orderList.size() - 1).getId();
                    }
                }
            }
        } catch (Exception e) {
            logger.error("inHistoryOrder cause by:{0}", e);
        }
    }

    private void executeSync(List<Order> orderList) {
        while (workQueue.remainingCapacity() < 20) {
            logger.info("workQueue size:{}", workQueue.size());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        executorService.submit(() -> {
            try {
                for (Order history : orderList) {
                    HistoryOrderRequest request = new HistoryOrderRequest();
                    request.setUserId(history.getUserId());
                    request.setOrderNo(history.getOrderNo());

                    OrderInfoList orderInfoList = selectInfo(request);
                    checkAndInsert(orderInfoList);

                    searchManager.indexOrder(history, null);
                }
            } catch (Exception e) {
                logger.error("[executeSync]failed！cause by:{}", e);
            }
        });
    }

}
