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

import com.alibaba.fastjson.JSON;
import com.zm.order.tool.server.constants.BakingSellerList;
import com.zm.order.tool.server.dao.OrderDao;
import com.zm.order.tool.server.manager.CommonManager;
import com.zm.order.tool.server.manager.RedisManager;
import com.zm.order.tool.server.model.InnerOrderDiscount;
import com.zm.order.tool.server.model.Order;
import com.zm.order.tool.server.model.OrderDiscount;
import com.zm.order.tool.server.query.OrderQuery;
import com.zm.order.tool.server.service.BakingService;
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 org.springframework.util.StringUtils;

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

/**
 * @author nianchang
 * @ClassName BakingServiceImpl
 * @date 2021/11/16 11:13 上午
 */
@Service
@SuppressWarnings("all")
public class BakingServiceImpl implements BakingService, InitializingBean {

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

    private ExecutorService executorService;

    private BlockingQueue workQueue;

    @Autowired
    private CommonManager commonManager;

    @Autowired
    private RedisManager redisManager;

    @Autowired
    private OrderDao orderDao;

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

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

    @Override
    public Result fieldConvert() {
        int count = 0;
        try {
            for (Long sellerId : BakingSellerList.sellerIdList) {
                OrderQuery orderQuery = new OrderQuery();
                orderQuery.setSellerId(sellerId);
                orderQuery.setSize(300);

                for (int i = 0; i < dbSize; 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);
                            long endAt = System.currentTimeMillis() - startAt;
                            if (endAt >= 500) {
                                logger.info("query_time:{}ms", endAt);
                            }
                            //
                            execute0(orderList, i, j);
                            count += orderIdList.size();
                            logger.info("fieldConvert:{}条", count);
                            if (orderIdList.size() < 300) {
                                break;
                            }
                            lastId = orderIdList.get(orderIdList.size() - 1);
                            logger.info("fieldConvert_lastId:{},i:{},j:{}", lastId, i, j);
                            Result<String> redisData = redisManager.get("field_convert_key");
                            if (redisData.isStatus() && Objects.nonNull(redisData.getData())) {
                                return Result.successNullData();
                            }
                        }
                    }
                }
            }
        } catch (Exception e) {
            logger.error("[cateringTransfer]failed！cause by:{}", e);
            return Result.failureData(ExceptionConstants.SYSTEM_ERROR);
        }
        return Result.successNullData();
    }

    @Override
    public Result cateringFieldConvert() {
        int count = 0;
        try {
            OrderQuery orderQuery = new OrderQuery();
            orderQuery.setSize(300);

            for (int i = 0; i < dbSize; 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);
                        long endAt = System.currentTimeMillis() - startAt;
                        if (endAt >= 500) {
                            logger.info("query_time:{}ms", endAt);
                        }
                        //
                        execute1(orderList, i, j);
                        count += orderIdList.size();
                        logger.info("cateringFieldConvert:{}条", count);
                        if (orderIdList.size() < 300) {
                            break;
                        }
                        lastId = orderIdList.get(orderIdList.size() - 1);
                        logger.info("cateringFieldConvert_lastId:{},i:{},j:{}", lastId, i, j);
                        Result<String> redisData = redisManager.get("catering_field_convert_key");
                        if (redisData.isStatus() && Objects.nonNull(redisData.getData())) {
                            return Result.successNullData();
                        }
                    }
                }
            }
        } catch (Exception e) {
            logger.error("[cateringFieldConvert]failed！cause by:{}", e);
            return Result.failureData(ExceptionConstants.SYSTEM_ERROR);
        }
        return Result.successNullData();
    }

    private void execute1(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 {

            } catch (Exception e) {
                logger.error("[execute1]failed！cause by:{},", e);
            }
        });
    }

    private void execute0(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<String> orderNoList = orderList.stream().map(Order::getOrderNo).collect(Collectors.toList());

                // 转换discountType
                List<OrderDiscount> discountList = commonManager.scanOrderDiscount(orderNoList, i, j);
                Map<String, List<OrderDiscount>> discountMap = null;
                if (!CollectionUtils.isEmpty(discountList)) {
                    for (OrderDiscount discount : discountList) {
                        discount.setDiscountType(mapDiscountType(discount.getDiscountType()));
                    }
                    discountMap = discountList.stream().collect(Collectors.groupingBy(OrderDiscount::getOrderNo));
                }

                for (Order order : orderList) {
                    order.setSource(mapSource(order.getSource()));
                    order.setPerformanceType(mapPerformanceType(order.getPerformanceType()));
                    order.setPerformancePlatform(mapPlatForm(order.getPerformancePlatform()));
                    order.setDiscountInfo(getDiscountInfo(discountMap, order));
                }

                commonManager.batchUpdateOrder(orderList, i, j);
                if (!CollectionUtils.isEmpty(discountList)) {
                    commonManager.updateDiscountType(discountList, i, j);
                }
            } catch (Exception e) {
                logger.error("[execute0]failed！cause by:{},", e);
            }
        });
    }

    private String getDiscountInfo(Map<String, List<OrderDiscount>> discountMap, Order order) {
        if (!CollectionUtils.isEmpty(discountMap)) {
            List<OrderDiscount> orderDiscounts = discountMap.get(order.getOrderNo());
            if (!CollectionUtils.isEmpty(orderDiscounts)) {
                return JSON.toJSONString(ConvertUtils.convertList(orderDiscounts, InnerOrderDiscount.class));
            }
        }
        return null;
    }

    private Integer mapSource(Integer source) {
        if (Objects.isNull(source)) {
            return source;
        }
        if (Objects.equals(2, source)) {
            return 30;
        }
        return source;
    }
    
    private Integer mapPerformanceType(Integer performanceType) {
        if (Objects.isNull(performanceType)) {
            return performanceType;
        }
        
        return performanceType;
    }

    private Integer mapDiscountType(Integer discountType) {
        if (Objects.isNull(discountType)) {
            return discountType;
        }
        if (Objects.equals(8, discountType)) {
            return 3;
        }
        if (Objects.equals(18, discountType)) {
            return 6;
        }
        if (Objects.equals(1, discountType)) {
            return 10;
        }
        if (Objects.equals(20, discountType)) {
            return 12;
        }
        if (Objects.equals(22, discountType)) {
            return 13;
        }
        if (Objects.equals(19, discountType)) {
            return 21;
        }
        if (Objects.equals(21, discountType)) {
            return 24;
        }
        if (Objects.equals(23, discountType)) {
            return 38;
        }
        if (Objects.equals(11, discountType)) {
            return 5;
        }
        if (Objects.equals(24, discountType)) {
            return 34;
        }
        return discountType;
    }

    private String mapPlatForm(String platForm) {
        if (StringUtils.isEmpty(platForm)) {
            return platForm;
        }

        return platForm;
    }

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

}
