package me.km;

import me.hammerle.snuviscript.code.ISnuviLogger;
import me.hammerle.snuviscript.config.SnuviConfig;
import me.kcm.Hooks;
import me.km.databank.DataBank;
import me.km.events.CustomEventCaller;
import me.km.overrides.ModPlayerList;
import me.km.permissions.ModCommandManager;
import me.km.permissions.Permissions;
import me.km.playerbank.DummyPlayerBank;
import me.km.playerbank.IPlayerBank;
import me.km.playerbank.PlayerBank;
import me.km.playerbank.PlayerManager;
import me.km.plots.ProtectionEvents;
import me.km.plots.WorldPlotMap;
import me.km.scheduler.SnuviScheduler;
import me.km.snuviscript.SnuviLogger;
import me.km.utils.ReflectionUtils;
import net.minecraft.server.dedicated.DedicatedServer;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.common.MinecraftForge;
import me.km.snuviscript.CommandGiveUp;
import me.km.snuviscript.CommandScript;
import me.km.snuviscript.DummyScriptBank;
import me.km.snuviscript.IScriptBank;
import me.km.snuviscript.MinecraftFunctions;
import me.km.snuviscript.ScriptBank;
import me.km.snuviscript.ScriptEvents;
import me.km.snuviscript.Scripts;
import me.km.world.WorldEvents;

@OnlyIn(Dist.DEDICATED_SERVER)
public class Server {
    private static SnuviLogger logger;
    private static ModCommandManager commands;
    private static DedicatedServer server;
    private static SnuviScheduler scheduler;
    private static DataBank databank;
    private static Scripts scripts;
    public static ScriptEvents scriptEvents;
    private static WorldPlotMap plotMap;

    public static void onStart(DedicatedServer serverIn) {
        server = serverIn;
        logger = new SnuviLogger();

        SnuviConfig conf = new SnuviConfig("", "config");
        if(conf.exists()) {
            conf.load();
        }

        boolean debug = conf.getBoolean("debug", false);

        // permissions
        Permissions perms = new Permissions(debug);
        logger.setPlayerLoggingData(server, perms);
        if(debug) {
            logger.print("------------------------------------------------");
            logger.print("Starting server in debug mode");
            logger.print("------------------------------------------------");
        }

        // scheduler
        scheduler = new SnuviScheduler(logger);

        // mod player list hook
        Hooks.setPlayerListFunction(ds -> {
            ds.setPlayerList(new ModPlayerList(ds));
        });

        // scripts
        scripts = new Scripts(logger, scheduler);
        scriptEvents = new ScriptEvents(scripts, server);
        Hooks.setBlockHarvest(scriptEvents);
        Hooks.setCraft(scriptEvents);
        MinecraftForge.EVENT_BUS.register(scriptEvents);

        // command manager
        commands = new ModCommandManager(true, perms, scriptEvents, scripts, scheduler);
        ReflectionUtils.setCommandManager(server, commands);
        commands.registerCommand(new CommandGiveUp(scripts));
        commands.registerCommand(new CommandScript(scripts, server));

        // data base connection
        databank = new DataBank(logger, conf.getString("user", "root"), conf.getString("password", ""));
        if(!databank.openDataBankConnection()) {
            logger.print("------------------------------------------------");
            logger.print("Starting server with dummy databank");
            logger.print("------------------------------------------------");
        }
        databank.startReconnecting(scheduler);

        // protections
        plotMap = new WorldPlotMap();
        scheduler.scheduleTask(() -> plotMap.read(server, logger));
        long time = 20 * 60 * 30; // all 30 minutes
        scheduler.scheduleRepeatingTask(() -> plotMap.save(), time, time);

        // block protections / player manager
        IPlayerBank playerBank;
        if(databank.isDummyDatabank()) {
            playerBank = new DummyPlayerBank();
        } else {
            playerBank = new PlayerBank(databank);
        }
        MinecraftForge.EVENT_BUS.register(new ProtectionEvents(plotMap, perms));

        PlayerManager playerManager = new PlayerManager(logger, playerBank);
        MinecraftForge.EVENT_BUS.register(playerManager);
        CustomEventCaller customEventCaller = new CustomEventCaller(server, scheduler);
        scripts.setCustomEventCaller(customEventCaller);
        MinecraftForge.EVENT_BUS.register(customEventCaller);

        // scripts
        IScriptBank scriptBank;
        if(databank.isDummyDatabank()) {
            scriptBank = new DummyScriptBank();
        } else {
            scriptBank = new ScriptBank(databank, playerManager);
        }
        MinecraftFunctions.registerFunctions(
                scripts.getScriptManager(), scripts, perms, scheduler, server, playerBank,
                customEventCaller, scriptBank, databank, plotMap, commands);

        MinecraftForge.EVENT_BUS.register(new WorldEvents());
        scheduler.scheduleTask(() -> scripts.startScript(null, "startscript"));
    }

    public static void onStop() {
        scripts.startScript("endscript");
        scheduler.stop();
        databank.closeDataBankConnection();
    }

    public static ISnuviLogger getLogger() {
        return logger;
    }
}
