package pers.neige.neigeitems;

import lombok.NonNull;
import lombok.val;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import org.bukkit.plugin.PluginDescriptionFile;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.plugin.java.JavaPluginLoader;
import org.inksnow.ankhinvoke.bukkit.AnkhInvokeBukkit;
import org.inksnow.ankhinvoke.bukkit.injector.JarTransformInjector;
import org.inksnow.cputil.logger.AuroraLoggerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import pers.neige.neigeitems.libs.bot.inker.bukkit.nbt.NbtItemStack;
import pers.neige.neigeitems.libs.bot.inker.bukkit.nbt.internal.annotation.CbVersion;
import pers.neige.neigeitems.scanner.ClassScanner;

import java.io.File;

public class NeigeItems extends JavaPlugin {
    private static final Logger logger;
    private static NeigeItems INSTANCE;

    static {
        AuroraLoggerFactory.instance().nameMapping(it -> "NeigeItems " + it);
        logger = LoggerFactory.getLogger(NeigeItems.class.getSimpleName());
        try {
            logger.info("loading ankh-invoke");
            AnkhInvokeBukkit.forBukkit(NeigeItems.class)
                .reference()
                .appendPackage("pers.neige.neigeitems.ref")
                .build()
                .inject()
                .injector(
                    new JarTransformInjector.Builder()
                        .classLoader(NeigeItems.class.getClassLoader())
                        .transformPackage("pers.neige.neigeitems.libs.bot.inker.bukkit.nbt.")
                        .build()
                )
                .build()
                .referenceRemap()
                .setApplyMapRegistry("neigeitems")
                .build()
                .build();
            logger.info("ankh-invoke loaded");
        } catch (Throwable e) {
            logger.error("failed to load ankh-invoke", e);
        }
    }

    private ClassScanner scanner = null;

    public NeigeItems() {
        super();
        onInit();
    }

    public NeigeItems(
        @NonNull JavaPluginLoader loader,
        @NonNull PluginDescriptionFile description,
        @NonNull File dataFolder,
        @NonNull File file
    ) {
        super(loader, description, dataFolder, file);
        onInit();
    }

    public static NeigeItems getInstance() {
        return INSTANCE;
    }

    private static boolean checkMagicUtils(String className) {
        return checkMagicUtils("pers.neige.neigeitems.libs.bot.inker.bukkit.nbt.neigeitems.utils", className);
    }

    private static boolean checkMagicUtils(String packageName, String className) {
        try {
            Class.forName(packageName + "." + className);
            return true;
        } catch (Throwable error) {
            logger.warn("{} 类未正常加载, 这可能造成不可预知的错误, 请联系作者修复", className);
            logger.warn("class {} did not load properly, which may cause unpredictable errors. Please contact the author for repair.", className, error);
            return false;
        }
    }

    public ClassScanner getScanner() {
        return scanner;
    }

    public void onInit() {
        if (CbVersion.current() == CbVersion.v1_20_R4) {
            logger.warn("1.20.5/1.20.6 是 mojang 拍脑门子更新出来的沟槽的中间版本, NeigeItems 拒绝支持这两个版本。");
            logger.warn("1.20.5/1.20.6 are problematic intermediate versions hastily released by Mojang, which NeigeItems refuses to support.");

            val pluginManager = Bukkit.getPluginManager();
            pluginManager.disablePlugin(this);
        }
        if (CbVersion.v1_13_R1.isSupport() && CbVersion.v1_17_R1.isUpTo()) {
            logger.warn("NeigeItems 已经放弃支持 1.13-1.17 的所有版本。");
            logger.warn("NeigeItems has discontinued support for all Minecraft versions from 1.13 to 1.17.");

            val pluginManager = Bukkit.getPluginManager();
            pluginManager.disablePlugin(this);
        }
        try {
            if (!CbVersion.v1_20_R4.isSupport()) {
                val itemStack = new ItemStack(Material.STONE);
                val nbtItemStack = new NbtItemStack(itemStack);
                val nbt = nbtItemStack.getOrCreateTag();
                nbt.putString("test", "test");
                nbt.getString("test");
            }
        } catch (Throwable error) {
            logger.warn("插件NBT前置库未正常加载依赖, 本插件不支持包括但不限于 Mohist/Catserver/Arclight 等混合服务端, 对于每个大版本, 本插件仅支持最新小版本, 如支持 1.19.4 但不支持 1.19.2, 请选用正确的服务端, 或卸载本插件");
            logger.warn("The plugin's NBT pre-requisite library failed to load. This plugin does not support mixed server platforms including but not limited to Mohist/Catserver/Arclight, etc. For each major version, this plugin only supports the latest minor version. For example, it supports 1.19.4 but not 1.19.2. Please use the correct server platform or uninstall this plugin", error);

            val pluginManager = Bukkit.getPluginManager();
            pluginManager.disablePlugin(this);
            return;
        }

        boolean safe = checkMagicUtils("DamageEventUtils");

        if (!checkMagicUtils("pers.neige.neigeitems.libs.bot.inker.bukkit.nbt", "NbtUtils")) safe = false;
        if (!checkMagicUtils("pers.neige.neigeitems.libs.bot.inker.bukkit.nbt", "NeigeItemsUtils")) safe = false;
        if (!checkMagicUtils("pers.neige.neigeitems.libs.bot.inker.bukkit.nbt", "NbtCraftItemComponent")) safe = false;
        if (!checkMagicUtils("pers.neige.neigeitems.libs.bot.inker.bukkit.nbt", "NbtBukkitItemComponent")) safe = false;
        if (!checkMagicUtils("pers.neige.neigeitems.libs.bot.inker.bukkit.nbt", "NbtBukkitItemComponent$1")) safe = false;
        if (!checkMagicUtils("EnchantmentUtils")) safe = false;
        if (!checkMagicUtils("EntityItemUtils")) safe = false;
        if (!checkMagicUtils("EntityPlayerUtils")) safe = false;
        if (!checkMagicUtils("EntityUtils")) safe = false;
        if (!checkMagicUtils("InventoryUtils")) safe = false;
        if (!checkMagicUtils("MathUtils")) safe = false;
        if (!checkMagicUtils("PacketUtils")) safe = false;
        if (!checkMagicUtils("PaperInventoryUtils")) safe = false;
        if (!checkMagicUtils("ServerUtils")) safe = false;
        if (!checkMagicUtils("SpigotInventoryUtils")) safe = false;
        if (!checkMagicUtils("TranslationUtils")) safe = false;
        if (!checkMagicUtils("WorldUtils")) safe = false;

        if (!safe) {
            val pluginManager = Bukkit.getPluginManager();
            pluginManager.disablePlugin(this);
            return;
        }
        INSTANCE = this;
        scanner = new ClassScanner(this);
    }

    @Override
    public void onLoad() {
        scanner.onLoad();
    }

    @Override
    public void onEnable() {
        this.getServer().getMessenger().registerOutgoingPluginChannel(this, "BungeeCord");
        scanner.onEnable();
    }

    @Override
    public void onDisable() {
        if (scanner != null) {
            scanner.onDisable();
        }
    }
}
