package top.r3944realms.lib39.core.compat;

import net.minecraft.resources.Identifier;
import net.neoforged.api.distmarker.Dist;
import net.neoforged.bus.api.IEventBus;
import net.neoforged.fml.common.EventBusSubscriber;
import net.neoforged.fml.loading.FMLEnvironment;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;

/**
 * The type Compat manager.
 */
@SuppressWarnings("unused")
public abstract class NeoForgeCompatManager extends CompatManager<INeoForgeCompat> {
    /**
     * The Mod event bus.
     */
    protected final IEventBus modEventBus,
    /**
     * The Game event bus.
     */
    gameEventBus;
    /**
     * The Compats.
     */
    protected final Map<Identifier, INeoForgeCompat> compats = new HashMap<>();
    /**
     * <pre>
     * 存储事件监听器配置
     * The Listener configs.
     * </pre>
     */
    protected final List<ListenerConfig> listenerConfigs = new ArrayList<>();

    @Override
    public Map<Identifier, INeoForgeCompat> getCompatMap() {
        return compats;
    }

    /**
     * Instantiates a new Forge compat manager.
     *
     * @param id           the id
     * @param modEventBus  the mod event bus
     * @param gameEventBus the game event bus
     */
    public NeoForgeCompatManager(Identifier id, IEventBus modEventBus, IEventBus gameEventBus) {
        super(id);
        this.modEventBus = modEventBus;
        this.gameEventBus = gameEventBus;
    }

    @Override
    protected void doRegisterCompat(Identifier id, INeoForgeCompat compat) {
        super.doRegisterCompat(id, compat);
        addListenerForCompat(id);
    }

    /**
     * 为所有兼容模块配置事件监听器
     *
     * @param dists the dists
     * @param bus   the bus
     */
    public void addListenerForAll(@Nullable Dist dists, EventBusSubscriber.Bus bus) {
        listenerConfigs.add(new ListenerConfig(null, dists, bus));
    }

    /**
     * 为特定兼容模块配置事件监听器
     *
     * @param compatId the compat id
     * @param dists    the dists
     * @param bus      the bus
     */
    public void addListenerForCompat(Identifier compatId, @Nullable Dist dists, EventBusSubscriber.Bus bus) {
        listenerConfigs.add(new ListenerConfig(compatId, dists, bus));
    }

    /**
     * 为特定兼容模块配置事件监听器
     *
     * @param compatId the compat id
     */
    public void addListenerForCompat(Identifier compatId) {
        addListenerForCompat(compatId, null, EventBusSubscriber.Bus.GAME);
        addListenerForCompat(compatId, null, EventBusSubscriber.Bus.MOD);

        addListenerForCompat(compatId, Dist.CLIENT, EventBusSubscriber.Bus.GAME);
        addListenerForCompat(compatId, Dist.CLIENT, EventBusSubscriber.Bus.MOD);

        addListenerForCompat(compatId, Dist.DEDICATED_SERVER, EventBusSubscriber.Bus.GAME);
        addListenerForCompat(compatId, Dist.DEDICATED_SERVER, EventBusSubscriber.Bus.MOD);
    }

    /**
     * 为已加载的兼容模块配置事件监听器
     *
     * @param dists    the dists
     * @param bus      the bus
     * @param consumer the consumer
     */
    public void addListenerForLoaded(@Nullable Dist dists, EventBusSubscriber.Bus bus, Consumer<IEventBus> consumer) {
        listenerConfigs.add(new ListenerConfig(null, dists, bus) {
            @Override
            boolean shouldApply(@NotNull INeoForgeCompat compat) {
                return super.shouldApply(compat);
            }
        });
    }

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

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

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

        // 初始化所有兼容模块
        for (Map.Entry<Identifier, INeoForgeCompat> entry : compats.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;
        // 2. 然后应用所有事件监听器
        applyAllEventListeners();
    }

    /**
     * 应用所有配置的事件监听器到对应的 ICompat 实例
     */
    private void applyAllEventListeners() {
        logger.info("Applying {} event listener configurations", listenerConfigs.size());

        for (ListenerConfig config : listenerConfigs) {
            if (config.compatId == null) {
                // 应用到所有兼容模块
                applyListenerToAllCompats(config);
            } else {
                // 应用到特定兼容模块
                applyListenerToCompat(config.compatId, config);
            }
        }
    }

    /**
     * 将监听器应用到所有兼容模块
     */
    private void applyListenerToAllCompats(ListenerConfig config) {
        for (INeoForgeCompat compat : compats.values()) {
            if(!compat.isInitialized()) {
                if (config.shouldApply(compat)) {
                    applyListenerToCompat(compat, config);
                }
            }
        }
    }

    /**
     * 将监听器应用到特定兼容模块
     */
    private void applyListenerToCompat(Identifier compatId, ListenerConfig config) {
        INeoForgeCompat compat = compats.get(compatId);
        if (compat != null && config.shouldApply(compat)) {
            applyListenerToCompat(compat, config);
        }
    }

    /**
     * 将监听器应用到具体的 ICompat 实例
     */
    private void applyListenerToCompat(INeoForgeCompat compat, ListenerConfig config) {
        try {
            // 根据配置调用对应的 ICompat 方法
            if (config.dists != null) {
                // 不再使用 DistExecutor，改为在运行时判断环境
                Dist currentDist = FMLEnvironment.dist;

                if (config.dists == Dist.CLIENT && currentDist == Dist.CLIENT) {
                    applyClientListener(compat, config);
                } else if (config.dists == Dist.DEDICATED_SERVER && currentDist == Dist.DEDICATED_SERVER) {
                    applyServerListener(compat, config);
                }
                // 如果环境不匹配，什么都不做
            } else {
                // 通用监听器（两边都执行）
                applyCommonListener(compat, config);
            }

            logger.debug("Applied {} listener to compat: {}",
                    getListenerTypeName(config), compat.id());

        } catch (Exception e) {
            logger.error("Failed to apply listener to compat: {}", compat.id(), e);
        }
    }

    private void applyClientListener(INeoForgeCompat compat, @NotNull ListenerConfig config) {
        if (config.bus == EventBusSubscriber.Bus.GAME) {
            compat.addClientGameListener(gameEventBus);
        } else {
            compat.addClientModListener(modEventBus);
        }
    }

    private void applyServerListener(INeoForgeCompat compat, @NotNull ListenerConfig config) {
        if (config.bus == EventBusSubscriber.Bus.GAME) {
            compat.addServerGameListener(gameEventBus);
        } else {
            compat.addServerModListener(modEventBus);
        }
    }

    private void applyCommonListener(INeoForgeCompat compat, @NotNull ListenerConfig config) {
        if (config.bus == EventBusSubscriber.Bus.GAME) {
            compat.addCommonGameListener(gameEventBus);
        } else {
            compat.addCommonModListener(modEventBus);
        }
    }

    /**
     * 获取监听器类型名称（用于日志）
     */
    private @NotNull String getListenerTypeName(@NotNull ListenerConfig config) {
        if (config.dists != null) {
            return config.dists.name().toLowerCase() + " " +
                    (config.bus == EventBusSubscriber.Bus.GAME ? "game" : "mod");
        } else {
            return "common " + (config.bus == EventBusSubscriber.Bus.GAME ? "game" : "mod");
        }
    }


    /**
     * Add listener for compat.
     *
     * @param compatId the compat id
     * @param bus      the bus
     */
    public void addListenerForCompat(Identifier compatId, EventBusSubscriber.Bus bus) {
        addListenerForCompat(compatId, null, bus);
    }

    /**
     * The type Listener config.
     */
    protected static class ListenerConfig {
        /**
         * The Compat id.
         */
        final Identifier compatId;
        /**
         * The Dists.
         */
        final Dist dists;
        /**
         * The Bus.
         */
        final EventBusSubscriber.Bus bus;

        /**
         * Instantiates a new Listener config.
         *
         * @param compatId the compat id
         * @param dists    the dists
         * @param bus      the bus
         */
        ListenerConfig(Identifier compatId, Dist dists, EventBusSubscriber.Bus bus) {
            this.compatId = compatId;
            this.dists = dists;
            this.bus = bus;
        }

        /**
         * Should apply boolean.
         *
         * @param compat the compat
         * @return the boolean
         */
        boolean shouldApply(@NotNull INeoForgeCompat compat) {
            return compat.isModLoaded();
        }
    }
}