package link.at17.mid.tushare.cache;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Set;

import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.redisson.api.RedissonClient;
import org.reflections.Reflections;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.cache.CacheProperties;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.cache.CacheKeyPrefix;
import org.springframework.stereotype.Component;

import jakarta.annotation.PostConstruct;
import link.at17.mid.tushare.task.TaskConstants;
import lombok.extern.slf4j.Slf4j;

/**
 * 定时清除缓存任务
 * @author Doghole
 * @since 2024-01-30
 */
@Component
@Slf4j
public class CacheEvictionJob implements Job {

    @Autowired
    RedissonClient redis;
    
    @Autowired
    CacheProperties cacheProperties;
    
    @Autowired
    Reflections reflections;
    
    static CacheKeyPrefix prefix;
    
    static final CacheEvictionTask DAILY_ANNO = new CacheEvictionTask() {
        @Override
        public Class<? extends Annotation> annotationType() {
            return CacheEvictionTask.class;
        }
        @Override
        public CacheEvictionSpan value() {
            return CacheEvictionSpan.DAILY;
        }
    };
    
    @PostConstruct
    void onPostConstruct() {
        prefix = CacheKeyPrefix.prefixed(
                cacheProperties.getRedis().getKeyPrefix());
    }
    
	public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
		String triggerName = jobExecutionContext.getTrigger().getKey().getName();
		
		Set<Method> methods = null;
        
		if (TaskConstants.CACHE_DAILY_EVICTION_TRIGGER.equals(triggerName)) {
		    methods = reflections.getMethodsAnnotatedWith(DAILY_ANNO);
		}
		
		if (methods != null) {
            for (Method method : methods) {
                Cacheable cacheable = method.getAnnotation(Cacheable.class);
                if (cacheable == null) {
                    continue;
                }
                
                String[] values = cacheable.value();
                if (values.length == 0) {
                    values = cacheable.cacheNames();
                }
                for (String cacheName : values) {
                    
                    String redisCacheName = prefix.compute(cacheName) + "*";
                    redis.getKeys().getKeysByPattern(redisCacheName).forEach(name -> {
                        redis.getBucket(name).deleteAsync();
                        log.debug("Scheduler clear cacheName {}", name);
                    });
                }
            }
		}
	}
	
}
