package com.njcn.gather.systemmonitor.disk.schedule;

import com.njcn.gather.systemmonitor.disk.event.DiskMonitorPolicyChangedEvent;
import com.njcn.gather.systemmonitor.disk.service.IDiskMonitorJobService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;

import javax.annotation.PreDestroy;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 磁盘监控启动与定时调度管理。
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class DiskMonitorScheduleManager implements ApplicationRunner {

    private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    private final IDiskMonitorJobService diskMonitorJobService;
    private final AtomicInteger threadIndex = new AtomicInteger(1);
    private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(createThreadFactory());
    private ScheduledFuture<?> scheduledFuture;

    @Override
    public void run(ApplicationArguments args) {
        try {
            diskMonitorJobService.executeAppStartMonitor();
        } catch (Exception exception) {
            log.error("应用启动后执行磁盘监控失败", exception);
        }
        refreshSchedule();
    }

    @EventListener(DiskMonitorPolicyChangedEvent.class)
    public void onPolicyChanged() {
        refreshSchedule();
    }

    public synchronized void refreshSchedule() {
        if (scheduledFuture != null) {
            scheduledFuture.cancel(false);
            scheduledFuture = null;
        }
        LocalDateTime nextRunTime = diskMonitorJobService.getNextDailyRunTime();
        if (nextRunTime == null) {
            log.info("磁盘监控每日调度未启用或未配置执行时间，跳过注册");
            return;
        }
        long delayMs = Math.max(Duration.between(LocalDateTime.now(), nextRunTime).toMillis(), 0L);
        scheduledFuture = scheduler.schedule(this::executeDailyTask, delayMs, TimeUnit.MILLISECONDS);
        log.info("磁盘监控每日调度已注册，下次执行时间：{}", nextRunTime.format(DATE_TIME_FORMATTER));
    }

    private void executeDailyTask() {
        try {
            diskMonitorJobService.executeDailyScheduleMonitor();
        } catch (Exception exception) {
            log.error("每日磁盘监控执行失败", exception);
        } finally {
            refreshSchedule();
        }
    }

    private ThreadFactory createThreadFactory() {
        return runnable -> {
            Thread thread = new Thread(runnable);
            thread.setName("disk-monitor-schedule-" + threadIndex.getAndIncrement());
            thread.setDaemon(true);
            return thread;
        };
    }

    @PreDestroy
    public synchronized void destroy() {
        if (scheduledFuture != null) {
            scheduledFuture.cancel(false);
        }
        scheduler.shutdown();
    }
}
