package top.r3944realms.lib39.core.compat;

import net.minecraft.resources.Identifier;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import top.r3944realms.lib39.Lib39;

import java.util.*;
import java.util.stream.Collectors;

/**
 * The type Compat manager.
 *
 * @param <C> the type parameter
 */
@SuppressWarnings("unused")
public abstract class CompatManager<C extends ICompat> implements ICompatManager<C> {
    /**
     * Gets id.
     *
     * @return the id
     */
    @Override
    public Identifier getId() {
        return id;
    }

    /**
     * The Logger.
     */
    protected final Logger logger;
    /**
     * The Id.
     */
    protected final Identifier id;

    /**
     * The Initialized.
     */
    protected boolean initialized = false;
    /**
     * The Pending tasks.
     */
    protected final List<Runnable> pendingTasks = new ArrayList<>();

    /**
     * Initialize.
     */
    @Override
    public void initialize() {
        initializeAllCompat();
        onLoadComplete();
    }

    /**
     * Instantiates a new Compat manager.
     *
     * @param id the id
     */
    public CompatManager(@NotNull Identifier id) {
        this.id = id;
        this.logger = LoggerFactory.getLogger(id.toString());
    }

    /**
     * Register compat.
     *
     * @param id     the id
     * @param compat the compat
     */
    @Override
    public void registerCompat(Identifier id, C compat) {
        if (initialized) {
            // 已初始化，直接注册
            doRegisterCompat(id, compat);
        } else {
            // 未初始化，缓存起来
            pendingTasks.add(() -> doRegisterCompat(id, compat));
            logger.debug("Cached compat registration for: {}", id);
        }
    }

    /**
     * Do register compat.
     *
     * @param id     the id
     * @param compat the compat
     */
    protected void doRegisterCompat(Identifier id, C compat) {
        if (getCompatMap().containsKey(id)) {
            logger.warn("Compat with id {} is already registered!", id);
            return;
        }
        getCompatMap().put(id, compat);
        logger.debug("Registered compat: {}", id);
    }

    /**
     * Register compat.
     *
     * @param namespace the namespace
     * @param path      the path
     * @param compat    the compat
     */
    @Override
    public void registerCompat(String namespace, String path, C compat) {
        registerCompat(Lib39.rl(namespace, path), compat);
    }


    // ===================== 初始化和管理 =====================

    /**
     * 初始化所有兼容模块并应用事件监听器
     */
    protected synchronized void initializeAllCompat() {
        logger.info("Initializing {} compatibility modules", getCompatMap().size());

        // 先处理所有缓存的注册
        pendingTasks.forEach(Runnable::run);
        pendingTasks.clear();

        // 初始化所有兼容模块
        for (Map.Entry<Identifier, C> entry : getCompatMap().entrySet()) {
            if (!entry.getValue().isInitialized() && entry.getValue().isModLoaded()) {
                try {
                    entry.getValue().initialize();
                    entry.getValue().setInitialize(true);
                    logger.info("Initialized compat: {}", entry.getKey());
                } catch (Exception e) {
                    logger.error("Failed to initialize compat: {}", entry.getKey(), e);
                }
            }
        }
        initialized = true;
    }

    /**
     * Gets compat.
     *
     * @param id the id
     * @return the compat
     */
    @Override
    public Optional<C> getCompat(Identifier id) {
        return Optional.ofNullable(getCompatMap().get(id));
    }

    /**
     * Has compat boolean.
     *
     * @param id the id
     * @return the boolean
     */
    @Override
    public boolean hasCompat(Identifier id) {
        return getCompatMap().containsKey(id);
    }

    /**
     * Unregister compat.
     *
     * @param id the id
     */
    @Override
    public void unregisterCompat(Identifier id) {
        C removed = getCompatMap().remove(id);
        if (removed != null) {
            logger.debug("Unregistered compat: {}", id);
        }
    }

    /**
     * Gets loaded compats.
     *
     * @return the loaded compats
     */
    public List<C> getLoadedCompats() {
        return getCompatMap().values().stream()
                .filter(C::isModLoaded)
                .collect(Collectors.toList());
    }

    /**
     * On load complete.
     */
    public void onLoadComplete() {
        logger.info("Calling onLoadComplete for {} compatibility modules", getCompatMap().size());
        for (Map.Entry<Identifier, C> entry : getCompatMap().entrySet()) {
            try {
                entry.getValue().onLoadComplete();
            } catch (Exception e) {
                logger.error("Error in onLoadComplete for compat: {}", entry.getKey(), e);
            }
        }
    }
}