package com.wuban.tron.explore;

import com.wuban.tron.explore.constant.Constant;
import com.wuban.tron.explore.fetch.Engine;
import com.wuban.tron.explore.service.CensusService;
import com.wuban.tron.explore.service.LastBlockService;
import com.wuban.tron.explore.service.TransactionService;
import com.wuban.tron.explore.util.DateUtil;
import com.wuban.tron.explore.util.SpringContextUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.Date;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 *  <core>区块服务引导项</core>
 *
 * @author sky
 * @date 2020/11/04
 */
@Slf4j
@Component
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class Bootstrapper {

    private final SpringContextUtil springContextUtil;

    private final LastBlockService lastBlockService;

    private final TransactionService transactionService;

    private final CensusService censusService;

    /**
     * 定时任务 - 业务线程池
     */
    private ScheduledThreadPoolExecutor executorService;

    private void init() {
        this.executorService = new ScheduledThreadPoolExecutor(1, new ThreadFactory() {
            private final AtomicInteger threadNumber = new AtomicInteger(1);

            @Override
            public Thread newThread(final Runnable r) {
                final Thread t = new Thread(r, "schedule-business" + this.threadNumber.getAndIncrement());
                if (t.isDaemon()) {
                    t.setDaemon(false);
                }
                if (t.getPriority() != Thread.NORM_PRIORITY) {
                    t.setPriority(Thread.NORM_PRIORITY);
                }
                return t;
            }
        });
    }

    @PostConstruct
    public synchronized void start() {
        this.init();
        this.startEngine();

        // 区块同步到redis
        this.executorService.scheduleWithFixedDelay(() -> this.lastBlockService.sync(), 0, 1, TimeUnit.SECONDS);

        // 账户总数统计
        this.executorService.scheduleWithFixedDelay(() -> this.censusService.updateTotalAccount(), 0, 5, TimeUnit.SECONDS);

        // 抓取最新区块高度
        this.executorService.scheduleWithFixedDelay(() -> this.lastBlockService.refresh(), 0, 1, TimeUnit.SECONDS);

        // 每秒交易tps峰值统计
        //this.executorService.scheduleWithFixedDelay(() -> this.transactionService.transTpsCount(0,0), 5, 1, TimeUnit.SECONDS);

        // 统计前一天区块、交易数据
        this.executorService.scheduleWithFixedDelay(() -> this.transactionService.censusBlockByLastDay(), getInitialDelay(), 24 * 60 * 60, TimeUnit.SECONDS);
    }

    private long getInitialDelay() {
        Date nextDate = DateUtil.addDays(new Date(), 1);
        String date = DateUtil.getFormatDate(nextDate, DateUtil.PATTERN_YMD) + " 00:00:03";
        long seconds = (DateUtil.getDateFromDateStr(date, DateUtil.PATTERN_YMD_HMS) - System.currentTimeMillis())/1000;
        return seconds;
    }

    private synchronized void startEngine() {
        Engine engine = new Engine(Constant.EXCUTOR_NAME_BLOCK);
        engine.start();
    }

}