package com.clx.performance.job;

import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.clx.performance.constant.RedisConstants;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

@Slf4j
@Component
public class OrderNoGenerateJob implements InitializingBean {


    @Autowired
    private ThreadPoolExecutor executor;


    @Resource
    private RedisTemplate<String, Object> jsonTemplate;


    /**
     * 每天早上2点生成第二天的订单号  cron = "0 0 2 * * ?"
     *
     * 提前生成订单号
     */
    @XxlJob("generateOrderNo")
    public void generateOrderNo()throws InterruptedException {
        LocalDateTime today = LocalDateTime.now();
        //检验今天的订单池有没有，没有就生成一套
        String todayKey = RedisConstants.CARRIER_ORDER_NUM_POOL_KEY.replace("{date}", today.format(DateTimeFormatter.BASIC_ISO_DATE));
        Integer orderNum = (Integer) jsonTemplate.opsForList().leftPop(todayKey);
        if(null == orderNum){
            log.warn("开始生成订单池: key->{}", todayKey);
            saveUniqueOrderNumList(todayKey, generateOrderNumList());
            log.warn("生成订单池完成: key->{}", todayKey);
            jsonTemplate.expire(todayKey, 1, TimeUnit.DAYS);
        }
        LocalDateTime tomorrow = today.plusDays(1);
        //检验明天的订单池，没有就生成一套
        String tomorrowKey = RedisConstants.CARRIER_ORDER_NUM_POOL_KEY.replace("{date}", tomorrow.format(DateTimeFormatter.BASIC_ISO_DATE));
        orderNum = (Integer) jsonTemplate.opsForList().leftPop(tomorrowKey);
        if(null == orderNum){
            log.warn("开始生成订单池: key->{}", tomorrowKey);
            saveUniqueOrderNumList(tomorrowKey, generateOrderNumList());
            log.warn("生成订单池完成: key->{}", tomorrowKey);
            jsonTemplate.expire(tomorrowKey, 2, TimeUnit.DAYS);
        }

    }




    /**
     * 保存到Redis
     * @author
     * @param key
     * @param data
     */
    private void saveUniqueOrderNumList(String key, List data)  {

        if(StringUtils.isBlank(key)){
            log.info(key, "key不能为空");
            return;
        }

        if(CollectionUtils.isEmpty(data)){
            log.info(key, "data不能为空");
            return;
        }

        for (int i = 0, j = 0; i < data.size(); i += 10000){
            if(i >= data.size()){
                i = data.size() -1;
            }
            j = i + 10000;
            if(j > data.size()){
                j = data.size();
            }
            try {
                jsonTemplate.opsForList().leftPushAll(key, data.subList(i, j));
            } catch (Exception e){
                e.printStackTrace();
                continue;
            }
        }
    }


    /**
     * 生成乱序的6位的订单编号
     * @author
     * @return 乱序的6位订单编号从100000到999999
     */
    private List<Integer> generateOrderNumList(){
        List<Integer> orderNumList = new ArrayList<>();
        for (Integer i = 100000; i < 999999; ++i){
            orderNumList.add(i);
        }
        shuffleSort(orderNumList);
        return orderNumList;
    }

    /**
     * 交换
     * @author
     * @param data
     * @param i
     * @param j
     */
    private static void swap(List<Integer> data, int i, int j) {
        if (i == j) {
            return;
        }
        Integer temp = data.get(i);
        data.set(i, data.get(j));
        data.set(j, temp);
    }

    /**
     * 洗牌
     * @author
     * @param data
     */
    private static void shuffleSort(List<Integer> data) {
        for (int i = 0; i < data.size() - 1; i++) {
            int j = ThreadLocalRandom.current().nextInt(data.size());
            swap(data, i, j);
        }
    }


   /**
     * 初始化
     * @throws Exception
     */

    @Override
    public void afterPropertiesSet() throws Exception {
        //初始化redis中的订单池
        executor.execute(new Runnable() {
            @Override
            public void run() {
                try {
                    generateOrderNo();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
    }



}
