package moe.kyokobot.backend;

import com.mewna.catnip.Catnip;
import io.micronaut.runtime.Micronaut;
import io.vertx.core.Vertx;
import io.vertx.core.VertxOptions;
import moe.kyokobot.shared.Banner;
import moe.kyokobot.shared.Settings;
import moe.kyokobot.shared.util.JsonUtil;
import moe.kyokobot.shared.util.Signer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;

public class Main {
    private static final Logger logger = LoggerFactory.getLogger(Main.class);
    private static String config;
    private static Signer signer;
    private static Catnip catnip;

    static {
        System.setProperty("vertx.logger-delegate-factory-class-name", "io.vertx.core.logging.SLF4JLogDelegateFactory");
        String config = System.getenv("KYOKO_CONFIG");
        if (config == null) config = System.getProperty("kyoko.config", "config.json");
        Main.config = config;
    }

    public static void main(String[] args) {
        Banner.show(logger, "Kyoko backend service");

        loadSettings();
        catnip = configureCatnip();

        Micronaut.run(Main.class);
    }

    private static Catnip configureCatnip() {
        var token = Settings.instance().apiKeys().get("discord");
        var vertx = Vertx.vertx(new VertxOptions().setEventLoopPoolSize(1));

        return Catnip.catnip(token, vertx);
    }

    private static void loadSettings() {
        Settings settings;
        var cfg = Path.of(config);
        var keyFile = Path.of("keyfile.bin");

        if (!Files.exists(cfg)) {
            logger.error("No configuration file found, run kyokobot.jar to generate a new one!");
        }

        if (Files.exists(keyFile)) {
            try {
                signer = new Signer(Files.readAllBytes(keyFile));
            } catch (IOException e) {
                logger.error("Cannot read keyfile!", e);
                System.exit(1);
            }
        } else {
            try {
                logger.info("Generating new keyfile...");
                var key = new byte[256];
                SecureRandom.getInstanceStrong().nextBytes(key);
                Files.write(keyFile, key);
                signer = new Signer(key);
            } catch (NoSuchAlgorithmException | IOException e) {
                logger.error("Error generating keyfile", e);
                System.exit(1);
            }
        }

        try (var fis = Files.newInputStream(cfg)) {
            settings = JsonUtil.fromJSON(fis, Settings.class);
            Settings.instance(settings);
        } catch (IOException e) {
            logger.error("Cannot read configuration file!", e);
            System.exit(1);
            return;
        }

        if (settings.apiKeys() == null || !settings.apiKeys().containsKey("discord")) {
            logger.error("No token specified! Please add a \"discord\" key with the token as value into \"api-keys\" " +
                    "entry in the configuration file");
            System.exit(1);
            return;
        }

        if (settings.apiKeys() == null || !settings.apiKeys().containsKey("discord_client")) {
            logger.error("No client secret specified! Please add a \"discord_client\" key with the token as value " +
                    "into \"api-keys\" entry in the configuration file");
            System.exit(1);
        }
    }

    public static Catnip getCatnip() {
        return catnip;
    }

    public static Signer getSigner() {
        return signer;
    }
}