package com.kazigk.sagiri;

import com.kazigk.sagiri.services.*;
import com.mongodb.MongoClient;
import com.mongodb.MongoClientOptions;
import com.mongodb.MongoClientURI;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import org.bson.Document;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sx.blah.discord.api.ClientBuilder;
import sx.blah.discord.api.IDiscordClient;
import sx.blah.discord.util.DiscordException;

import java.io.File;
import java.util.ArrayList;

public class Sagiri {
    private static Logger logger;
    private static Config config;
    private static IDiscordClient client;
    private static ArrayList<PluginBubble> plugins;
    private static CommandDispatcher commandDispatcher;

    private static MongoClient mongoClient;
    private static MongoDatabase mongoDatabase;

    public static void main(String[] args) throws Exception {
        logger = LoggerFactory.getLogger(Sagiri.class);
        logger.info("Sagiri is starting.");

        config = new Config();
        config.copyDefaults();
        config.save();

        if(!config.json().has("token") || config.json().getString("token").equals("")) {
            logger.error("Bot token must be set. Please set bot token in configuration file.");
            return;
        }

        ClientBuilder builder = new ClientBuilder();
        builder.withToken(config.json().getString("token"));
        client = builder.build();

        commandDispatcher = new CommandDispatcher(config.json().getString("command_character").charAt(0));
        commandDispatcher.register(new HelpService(), new SagiriCommand("help"));
        commandDispatcher.register(new PluginListService(), new SagiriCommand("plugins"));
        client.getDispatcher().registerListener(commandDispatcher);

        try {
            mongoConnect();
            logger.info("Successfully connected to MongoDB database!");
        } catch(Exception e) {
            e.printStackTrace();
            logger.error("Error occurred while connecting to database ;c");
            return;
        }

        loadPlugins();

        Runtime.getRuntime().addShutdownHook(new ShutdownHook());

        try {
            client.login();
        } catch(DiscordException e) {
            e.printStackTrace();
            logger.error("Login failed. Please check your token.");
        }
    }

    private static void loadPlugins() throws Exception {
        logger.info("Loading plugins.");
        plugins = new ArrayList<>();

        File pluginsDirectory = new File("plugins");
        pluginsDirectory.mkdir();

        for(File file : pluginsDirectory.listFiles()) {
            if(!file.getName().endsWith(".jar")) continue;

            try {
                PluginBubble bubble = new PluginBubble(file);

                try {
                    bubble.getPlugin().start();
                    plugins.add(bubble);
                    logger.info(String.format("Started plugin: %s", bubble.getName()));
                } catch (Exception e) {
                    e.printStackTrace();
                    logger.error(String.format("Unexpected happened while starting plugin: %s", bubble.getName()));
                }
            } catch(Exception e) {
                e.printStackTrace();
                logger.error(String.format("Unexpected happened while loading plugin: %s", file.getName()));
            }
        }
    }

    private static void mongoConnect() {
        MongoClientURI uri = new MongoClientURI(
                config.json().getString("mongo_uri"),
                MongoClientOptions.builder().serverSelectionTimeout(3000)
        );
        mongoClient = new MongoClient(uri);
        mongoDatabase = mongoClient.getDatabase(uri.getDatabase());
        mongoDatabase.runCommand(new Document("ping", 1));
    }

    public static IDiscordClient getClient() {
        return client;
    }

    public static CommandDispatcher getCommandDispatcher() {
        return commandDispatcher;
    }

    public static ArrayList<PluginBubble> getPlugins() {
        return plugins;
    }

    public static MongoCollection getCollection(String suffix) {
        String className = Thread.currentThread().getStackTrace()[2].getClassName();

        for(PluginBubble bubble : getPlugins()) {
            String packageName = bubble.getPlugin().getClass().getPackage().getName();

            if(className.startsWith(packageName)) {
                return mongoDatabase.getCollection(
                        String.format("%s_%s", packageName, suffix)
                );
            }
        }

        return null;
    }
}