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

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import com.zm.order.tool.server.manager.DistributedCacheManager;
import com.zm.order.tool.server.model.Order;
import com.zm.order.tool.server.model.OrderExt;
import com.zm.order.tool.server.query.OrderQuery;
import com.zm.order.tool.server.tb.TbOrderDao;
import com.zm.order.tool.server.tempdb.OrderExtDao;
import com.zm.order.tool.server.utils.DateUtils;
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.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.*;

/**
 * <p>
 *
 * </p>
 *
 * @author nianchang
 * @date 2023/12/08 1:55 下午
 */
@Service
@SuppressWarnings("all")
public class OrderScanExtServiceImpl implements InitializingBean {

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

    private BlockingQueue workQueue;

    private ExecutorService executorService;

    @Autowired
    private OrderExtDao extDao;

    @Autowired
    private TbOrderDao tbOrderDao;

    @Autowired
    private DistributedCacheManager cacheManager;

    private Map<String, Object> extMap = new ConcurrentHashMap<>();

    @Override
    public void afterPropertiesSet() throws Exception {
        int coreSize = Runtime.getRuntime().availableProcessors();
        workQueue = new ArrayBlockingQueue(32);

        executorService = new ThreadPoolExecutor(8, 10, 1, TimeUnit.MINUTES,
                workQueue, new NamedThreadFactory("order-routing"),
                new ThreadPoolExecutor.AbortPolicy());
    }

    public void scan() {
        try {
            Date sTime = null;
            Date dTime = null;
            String start = "2024-05-01";
            int count = 0;
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            OrderQuery query = new OrderQuery();
            query.setSize(20000);
            for (;;) {
                Calendar c = getCalendar(start);
                sTime = DateUtils.getStartDate(c.getTime());
                dTime = DateUtils.getEndDate(c.getTime());

                start = sdf.format(c.getTime());

                logger.info("[scan_order_time]:{}", sdf.format(c.getTime()));

                if (new Date().before(sTime)) {
                    logger.info("[orderExtMap]extMap:{}", JSON.toJSONString(extMap));
                    return;
                }

                query.setOrderAtStart(sTime);
                query.setOrderAtEnd(dTime);

                Long lastId = null;
                for (;;) {
                    query.setLastId(lastId);
                    List<Long> idList = tbOrderDao.selectId(query);
                    if (CollectionUtils.isEmpty(idList)) {
                        break;
                    }
                    List<Order> data = new ArrayList<>(20000);
                    List<List<Long>> partition = Lists.partition(idList, 5000);
                    for (List<Long> batch : partition) {
                        data.addAll(tbOrderDao.selectById(batch));
                    }

                    exec(data);

                    count += idList.size();
                    logger.info("[order_scan_ext]count:{}, lastId:{}, start:{}, end:{}", count, lastId, sTime.getTime(),
                        dTime.getTime());

                    if (idList.size() < 20000) {
                        break;
                    }
                    Result<String> redisData = cacheManager.get("scan_order_ext_key_2");
                    if (redisData.isStatus() && Objects.nonNull(redisData.getData())) {
                        return;
                    }
                    lastId = idList.get(idList.size() - 1);
                }
            }
        } catch (Exception e) {
            logger.error("[order_scan]cause by:{}", e);
        } finally {
            logger.info("[orderExtMap]extMap:{}", JSON.toJSONString(extMap));
            List<OrderExt> list = new ArrayList<>();
            if (!CollectionUtils.isEmpty(extMap)) {
                extMap.forEach((k ,v) -> {
                    list.add(new OrderExt(k, "orders"));
                });
            }
            extDao.insertList(list);
        }
    }

    private Calendar getCalendar(String start) {
        SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd");
        Date parse = null;
        try {
            parse = sf.parse(start);
        } catch (ParseException ex) {
            ex.printStackTrace();
        }
        Calendar c = Calendar.getInstance();
        c.setTime(parse);
        c.add(Calendar.DAY_OF_MONTH, 1);
        return c;
    }
    
    private void exec(List<Order> orderList) {
        while (workQueue.remainingCapacity() < 10) {
            logger.info("workQueue size:{}", workQueue.size());
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        executorService.submit(() -> {
            try {
                if (!CollectionUtils.isEmpty(orderList)) {
                    for (Order order : orderList) {
                        extMap.putAll(order.getExtraMap());
                    }
                }
            } catch (Exception e) {
                logger.error("[execute]failed！cause by:{}", e);
            }
        });
    }
}
