package me.qwq.doghouse.component;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.reflections.Reflections;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.ResolvableType;
import org.springframework.stereotype.Component;
import jakarta.annotation.PostConstruct;
import me.qwq.doghouse.enums.PostTypeEnum;
import me.qwq.doghouse.interfaces.IPostTypeConfig;
import me.qwq.doghouse.service.ThemeService;
import me.qwq.doghouse.service.post.AbstractPostService;
import me.qwq.doghouse.util.SpringContextHolder;

/**
 * 提供通过 PostType 获取一些配置的能力
 */
@Component
public class PostTypeComponent {
    
    @Autowired
    Reflections reflections;
    
    @Autowired
    ThemeService themeService;

    @SuppressWarnings("rawtypes")
    Set<Class<? extends IPostTypeConfig>> postTypeConfigClassCache = new HashSet<>();
    
    @SuppressWarnings("rawtypes")
    Set<Class<? extends AbstractPostService>> abstractPostServiceClassCache = new HashSet<>();
    
    Map<PostTypeEnum, IPostTypeConfig<?>> postTypeConfigCache = new HashMap<>(); 
    
    Map<PostTypeEnum, AbstractPostService<?, ?>> abstractPostServiceCache = new HashMap<>(); 
    
    @PostConstruct
    void init() {
        postTypeConfigClassCache =
                reflections.getSubTypesOf(IPostTypeConfig.class);
        abstractPostServiceClassCache = 
                reflections.getSubTypesOf(AbstractPostService.class);
    }
    
    /**
     * 获取指定模式的 Post 配置
     * @param <T>
     * @param postType
     * @return
     */
    @SuppressWarnings("unchecked")
    public <T extends IPostTypeConfig<T>> T getPostTypeConfig(PostTypeEnum postType) {
        return (T) postTypeConfigCache.computeIfAbsent(postType, key -> {
            for (@SuppressWarnings("rawtypes") Class<? extends IPostTypeConfig> clazz : postTypeConfigClassCache) {
                T instance = (T) SpringContextHolder.getBean(clazz);
                if (instance.getPostType() == key) {
                    return instance;
                }
            }
            return null;
        });
    }
    
    /**
     * 获取指定模式的 PostService.
     * <p>注意在和 AbstractPostService 有关泛型的类内调用时不要指定其返回为泛型, 而是使用
        AbstractPostService&lt;?, ?> 作为返回类型, 避免强制转换为泛型。除非很确定返回类型
        就是类内指定的泛型类型
     * @param <C>
     * @param <T>
     * @param postType
     * @return
     */
    @SuppressWarnings("unchecked")
    public <C extends IPostTypeConfig<C>, T extends AbstractPostService<T, C>> T getPostTypeService(PostTypeEnum postType) {
        return (T) abstractPostServiceCache.computeIfAbsent(postType, key -> {
            for (@SuppressWarnings("rawtypes") Class<? extends AbstractPostService> clazz : abstractPostServiceClassCache) {
                T instance = (T) SpringContextHolder.getBean(clazz);
                ResolvableType type = ResolvableType.forClass(clazz).as(AbstractPostService.class);
                ResolvableType iPageConfigType = type.getGeneric(1);
                Class<C> iPageConfigClass = (Class<C>) iPageConfigType.resolve();
                C pageConfig = SpringContextHolder.getBean(iPageConfigClass);
                if (pageConfig.getPostType() == key) {
                    return instance;
                }
            }
            return null;
        });
    }
    
    /**
     * 获取指定模式的模板路径
     * @param postType
     * @param fileNameSegment
     * @return
     */
    public String getTemplatePath(PostTypeEnum postType, String fileNameSegment) {
        return themeService.getCurrentTheme().getTemplateString(
                getPostTypeConfig(postType).getTemplatePrefix(),
                fileNameSegment);
    }
    
    /**
     * 检查指定模式是否打开
     * @param postType
     * @return
     */
    public boolean checkModeEnable(PostTypeEnum postType) {
        return getPostTypeConfig(postType).getEnabled();
    }

}
