/*
 *   This file is a part of the SteamWar software.
 *
 *   Copyright (C) 2025 SteamWar.de-Serverteam
 *
 *   This program is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU Affero General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 *   GNU Affero General Public License for more details.
 *
 *   You should have received a copy of the GNU Affero General Public License
 *   along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

package de.steamwar.core;

import com.comphenix.tinyprotocol.TinyProtocol;
import de.steamwar.Reflection;
import de.steamwar.command.SWCommandUtils;
import de.steamwar.command.SWTypeMapperCreator;
import de.steamwar.command.TabCompletionCache;
import de.steamwar.command.TypeMapper;
import de.steamwar.core.authlib.SteamwarGameProfileRepository;
import de.steamwar.linkage.AbstractLinker;
import de.steamwar.linkage.SpigotLinker;
import de.steamwar.message.Message;
import de.steamwar.network.NetworkReceiver;
import de.steamwar.sql.SchematicNode;
import de.steamwar.sql.SteamwarUser;
import de.steamwar.sql.internal.Statement;
import lombok.Getter;
import lombok.Setter;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.plugin.java.JavaPlugin;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Collection;
import java.util.logging.Level;

public class Core extends JavaPlugin {

    public static final Message MESSAGE = new Message("SpigotCore", Core.class.getClassLoader());

    @Deprecated
    public static int getVersion() {
        return Reflection.MAJOR_VERSION;
    }

    @Getter
    @Setter
    private static JavaPlugin instance;

    @Getter
    private static String serverName = "";

    public static void setServerName(String serverName) {
        if (Core.serverName.isEmpty()) {
            Core.serverName = serverName;
        }
    }

    private ErrorHandler errorHandler;
    private CrashDetector crashDetector;

    @Override
    public void onLoad() {
        setInstance(this);
        serverName = System.getProperty("serverName", "");
    }

    @Override
    public void onEnable() {
        new PlayerVersion();

        errorHandler = new ErrorHandler();
        crashDetector = new CrashDetector();

        SWCommandUtils.init((SWTypeMapperCreator<TypeMapper<Object>, CommandSender, Object>) (mapper, tabCompleter) -> new TypeMapper<Object>() {
            @Override
            public Object map(CommandSender commandSender, String[] previousArguments, String s) {
                return mapper.apply(s);
            }

            @Override
            public Collection<String> tabCompletes(CommandSender sender, String[] previousArguments, String s) {
                return tabCompleter.apply(sender, s);
            }
        });

        SpigotLinker spigotLinker = new SpigotLinker(this, MESSAGE);
        try {
            spigotLinker.link();
        } catch (AbstractLinker.LinkException e) {
            e.printStackTrace();
            Bukkit.shutdown();
            return;
        }

        if (!Statement.productionDatabase()) {
            getServer().getPluginManager().registerEvents(new LocaleChangeWrapper(), this);
        }

        getServer().getMessenger().registerIncomingPluginChannel(this, "sw:bridge", new NetworkReceiver());
        getServer().getMessenger().registerOutgoingPluginChannel(this, "sw:bridge");

        SteamwarGameProfileRepository.impl.inject();

        TinyProtocol.init();
        CheckpointUtils.signalHandler();

        Bukkit.getScheduler().runTaskTimer(this, TabCompletionCache::invalidateOldEntries, 20, 20);
        Bukkit.getScheduler().runTaskTimer(Core.getInstance(), SteamwarUser::clear, 72000, 72000);
        Bukkit.getScheduler().runTaskTimer(Core.getInstance(), SchematicNode::clear, 20L * 30, 20L * 30);

        try {
            getLogger().log(Level.INFO, "Running on: " + new BufferedReader(new InputStreamReader(Runtime.getRuntime().exec("hostname").getInputStream())).readLine());
        } catch (IOException e) {
            throw new SecurityException("Could not load Hostname", e);
        }
    }

    @Override
    public void onDisable() {
        TinyProtocol.instance.close();
        errorHandler.unregister();
        if (crashDetector.onMainThread()) Statement.closeAll();
    }
}
