package top.r3944realms.lib39.core.compat;

import net.minecraft.resources.ResourceLocation;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.eventbus.api.IEventBus;
import net.minecraftforge.fml.DistExecutor;
import net.minecraftforge.fml.common.Mod;
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 ForgeCompatManager extends CompatManager {
    /**
     * The Mod event bus.
     */
    protected final IEventBus modEventBus, /**
     * The Game event bus.
     */
    gameEventBus;
    /**
     * The Compats.
     */
    protected final Map<ResourceLocation, IForgeCompat> compats = new HashMap<>();
    /**
     * The Listener configs.
     */
// 存储事件监听器配置
    protected final List<ListenerConfig> listenerConfigs = new ArrayList<>();

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

    @Override
    protected void doRegisterCompat(ResourceLocation id, ICompat compat) {
        if (compat instanceof IForgeCompat) {
            super.doRegisterCompat(id, compat);
            addListenerForCompat(id);
        } else throw new IllegalArgumentException("Can't register compat " + id + " of type " + compat.getClass());
    }

    /**
     * 为所有兼容模块配置事件监听器
     *
     * @param dists the dists
     * @param bus   the bus
     */
    public void addListenerForAll(@Nullable Dist dists, Mod.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(ResourceLocation compatId, @Nullable Dist dists, Mod.EventBusSubscriber.Bus bus) {
        listenerConfigs.add(new ListenerConfig(compatId, dists, bus));
    }

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

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

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

    /**
     * 为已加载的兼容模块配置事件监听器
     *
     * @param dists    the dists
     * @param bus      the bus
     * @param consumer the consumer
     */
    public void addListenerForLoaded(@Nullable Dist dists, Mod.EventBusSubscriber.Bus bus, Consumer<IEventBus> consumer) {
        listenerConfigs.add(new ListenerConfig(null, dists, bus) {
            @Override
            boolean shouldApply(@NotNull IForgeCompat 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<ResourceLocation, IForgeCompat> 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 (IForgeCompat compat : compats.values()) {
            if(!compat.isInitialized()) {
                if (config.shouldApply(compat)) {
                    applyListenerToCompat(compat, config);
                }
            }
        }
    }

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

    /**
     * 将监听器应用到具体的 ICompat 实例
     */
    private void applyListenerToCompat(IForgeCompat compat, ListenerConfig config) {
        try {
            // 根据配置调用对应的 ICompat 方法
            if (config.dists != null) {
                switch (config.dists) {
                    case CLIENT -> DistExecutor.unsafeRunWhenOn(Dist.CLIENT,() -> () -> {
                         if (config.bus == Mod.EventBusSubscriber.Bus.FORGE) {
                             compat.addClientGameListener(gameEventBus);
                         } else {
                             compat.addClientModListener(modEventBus);
                         }
                     });
                    case DEDICATED_SERVER -> DistExecutor.unsafeRunWhenOn(Dist.DEDICATED_SERVER,() -> () -> {
                        if (config.bus == Mod.EventBusSubscriber.Bus.FORGE) {
                            compat.addServerGameListener(gameEventBus);
                        } else {
                            compat.addServerModListener(modEventBus);
                        }
                    });
                }
            } else {
                // 通用监听器
                if (config.bus == Mod.EventBusSubscriber.Bus.FORGE) {
                    compat.addCommonGameListener(gameEventBus);
                } else {
                    compat.addCommonModListener(modEventBus);
                }
            }

            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 @NotNull String getListenerTypeName(@NotNull ListenerConfig config) {
        if (config.dists != null) {
            return config.dists.name().toLowerCase() + " " +
                    (config.bus == Mod.EventBusSubscriber.Bus.FORGE ? "game" : "mod");
        } else {
            return "common " + (config.bus == Mod.EventBusSubscriber.Bus.FORGE ? "game" : "mod");
        }
    }


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

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

        /**
         * Instantiates a new Listener config.
         *
         * @param compatId the compat id
         * @param dists    the dists
         * @param bus      the bus
         */
        ListenerConfig(ResourceLocation compatId, Dist dists, Mod.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 IForgeCompat compat) {
            return compat.isModLoaded();
        }
    }
}