package tech.easyflow.system.schedule;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import tech.easyflow.common.cache.DistributedScheduledLock;
import tech.easyflow.log.LogRecordProperties;
import tech.easyflow.system.mapper.SysLogMapper;

import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Date;

/**
 * 分批清理超过在线保留期的数据库操作日志。
 */
@Component
@ConditionalOnProperty(
        prefix = "easyflow.log-record.retention",
        name = "enabled",
        havingValue = "true",
        matchIfMissing = true)
public class SysLogCleanupJob {

    private static final Logger LOG = LoggerFactory.getLogger(SysLogCleanupJob.class);

    private final SysLogMapper sysLogMapper;
    private final LogRecordProperties.Retention retention;

    /**
     * 创建操作日志清理任务。
     *
     * @param sysLogMapper 操作日志 Mapper
     * @param properties 操作日志配置
     */
    public SysLogCleanupJob(SysLogMapper sysLogMapper,
                            LogRecordProperties properties) {
        this.sysLogMapper = sysLogMapper;
        this.retention = properties.getRetention();
    }

    /**
     * 每天低峰期在单个集群节点上清理过期操作日志。
     */
    @Scheduled(cron = "${easyflow.log-record.retention.cron:0 30 2 * * *}")
    @DistributedScheduledLock(
            key = "easyflow:schedule:sys-log-cleanup",
            leaseSeconds = 600L)
    public void cleanup() {
        Date cutoff = Date.from(
                Instant.now().minus(retention.getDays(), ChronoUnit.DAYS));
        try {
            int totalDeleted = cleanupExpired(cutoff);
            if (totalDeleted > 0) {
                LOG.info("已清理 {} 条过期操作日志，保留天数={}",
                        totalDeleted, retention.getDays());
            }
        } catch (RuntimeException error) {
            LOG.error("清理过期操作日志失败", error);
            throw error;
        }
    }

    /**
     * 按配置的批次上限清理指定时间之前的日志。
     *
     * @param cutoff 过期时间边界
     * @return 实际删除总行数
     */
    int cleanupExpired(Date cutoff) {
        int totalDeleted = 0;
        int batchSize = retention.getBatchSize();
        for (int batch = 0; batch < retention.getMaxBatches(); batch++) {
            int deleted = sysLogMapper.deleteExpiredBatch(cutoff, batchSize);
            totalDeleted += deleted;
            if (deleted < batchSize) {
                return totalDeleted;
            }
        }
        LOG.warn("操作日志单次清理达到批次上限，后续调度将继续处理，已清理={}",
                totalDeleted);
        return totalDeleted;
    }
}
