package com.shanebeestudios.skbee;

import ch.njol.skript.test.runner.TestMode;
import ch.njol.skript.util.Version;
import com.github.shanebeee.skr.scheduling.TaskUtils;
import com.shanebeestudios.skbee.api.bound.Bound;
import com.shanebeestudios.skbee.api.bound.BoundConfig;
import com.shanebeestudios.skbee.api.command.SkBeeCommand;
import com.shanebeestudios.skbee.api.structure.StructureManager;
import com.shanebeestudios.skbee.api.util.Util;
import com.shanebeestudios.skbee.api.util.update.UpdateChecker;
import com.shanebeestudios.skbee.api.worldgen.BeeWorldConfig;
import com.shanebeestudios.skbee.api.wrapper.LazyLocation;
import com.shanebeestudios.skbee.config.Config;
import com.shanebeestudios.skbee.config.SkBeeMetrics;
import com.shanebeestudios.vf.api.VirtualFurnaceAPI;
import org.bukkit.Bukkit;
import org.bukkit.configuration.serialization.ConfigurationSerialization;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.plugin.java.JavaPlugin;

/**
 * Main class for SkBee
 */
public class SkBee extends JavaPlugin {

    static {
        ConfigurationSerialization.registerClass(Bound.class, "Bound");
        ConfigurationSerialization.registerClass(LazyLocation.class, "LazyLocation");
    }

    private static SkBee instance;
    private boolean properlyEnabled = true;
    private Config config;
    BoundConfig boundConfig = null;
    VirtualFurnaceAPI virtualFurnaceAPI;
    BeeWorldConfig beeWorldConfig;
    StructureManager structureManager = null;
    private AddonLoader addonLoader = null;

    /**
     * @hidden must be public for Bukkit but let's hide from docs
     */
    public SkBee() {
    }

    /**
     * @hidden
     */
    @Override
    public void onEnable() {
        // Let's get this party started...
        long start = System.currentTimeMillis();
        instance = this;
        Version skBeeVersion = new Version(this.getPluginMeta().getVersion());
        this.config = new Config(this);
        TaskUtils.initialize(this, Util.IS_RUNNING_FOLIA || this.config.settings_use_paper_schedulers);

        this.addonLoader = new AddonLoader(this);
        // Check if SkriptAddon can actually load
        this.properlyEnabled = this.addonLoader.canLoadPlugin();

        SkBeeCommand.registerCommand(this);
        SkBeeMetrics.loadMetrics(this, this.properlyEnabled, skBeeVersion);

        // Beta check + notice
        if (skBeeVersion.toString().contains("-")) {
            Util.log("&eThis is a BETA build, things may not work as expected, please report any bugs on GitHub");
            Util.log("&ehttps://github.com/ShaneBeee/SkBee/issues");
        }

        new UpdateChecker(this);
        Util.log("&aSuccessfully enabled v%s&7 in &b%.2f seconds", skBeeVersion.toString(), (float) (System.currentTimeMillis() - start) / 1000);

        // Load custom worlds if enabled in config
        if (this.properlyEnabled && this.beeWorldConfig != null) {
            this.beeWorldConfig.loadCustomWorlds();
        }

        if (!this.properlyEnabled) {
            // Let admins know the plugin didn't load
            setupJoinListener();
        }
        // Looks like we made it after all
    }

    /**
     * @hidden
     */
    @Override
    public void onDisable() {
        if (this.properlyEnabled) {
            // Cancel tasks on stop to prevent async issues
            TaskUtils.cancelTasks();
        }
        if (this.virtualFurnaceAPI != null) {
            this.virtualFurnaceAPI.disableAPI();
        }
        // Only save bounds if not in test mode
        if (!TestMode.ENABLED && this.boundConfig != null) {
            this.boundConfig.saveAllBoundsOnShutdown();
        }
        // Clear debugs in case of some kind of reload
        Util.clearDebugs();
    }

    private void setupJoinListener() {
        Bukkit.getPluginManager().registerEvents(new Listener() {
            @EventHandler
            private void onJoin(PlayerJoinEvent event) {
                Player player = event.getPlayer();
                if (!player.hasPermission("skbee.admin")) return;

                TaskUtils.getEntityScheduler(player).runTaskLater(() ->
                    Util.sendMiniPrefixed(player, "<#F54927>Failed to load addon, see console for further details."),
                    10);
            }
        }, this);
    }

    /**
     * Get an instance of this plugin
     *
     * @return Instance of this plugin
     */
    public static SkBee getPlugin() {
        return instance;
    }

    /**
     * Get an instance of this plugin's {@link Config}
     *
     * @return Instance of this plugin's config
     */
    public Config getPluginConfig() {
        return this.config;
    }

    /**
     * Get an instance of the {@link BoundConfig}
     *
     * @return Instance of bound config
     */
    public BoundConfig getBoundConfig() {
        return this.boundConfig;
    }

    /**
     * Get an instance of the {@link BeeWorldConfig}
     *
     * @return Instance of BeeWorld config
     * @hidden
     */
    public BeeWorldConfig getBeeWorldConfig() {
        return beeWorldConfig;
    }

    /**
     * Get an instance of the {@link VirtualFurnaceAPI}
     *
     * @return Instance of the Virtual Furnace API
     */
    public VirtualFurnaceAPI getVirtualFurnaceAPI() {
        return virtualFurnaceAPI;
    }

    /**
     * Get an instance of the {@link StructureManager}
     *
     * @return Instance of the Structure Bee Manager
     */
    public StructureManager getStructureManager() {
        return structureManager;
    }

    /**
     * @hidden
     */
    public AddonLoader getAddonLoader() {
        return addonLoader;
    }

    /**
     * Check if SkBee's debugger is enabled
     *
     * @return True if debugger enabled
     */
    public static boolean isDebug() {
        Config config = SkBee.instance.config;
        if (config != null) {
            return config.settings_debug;
        }
        return false;
    }

}
