package net.voltexstudios.npcConversations;

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.RemovalCause;
import com.google.common.cache.RemovalListener;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.TextComponent;
import net.voltexstudios.npcConversations.commands.ConversationCommand;
import net.voltexstudios.npcConversations.listener.ChatHandler;
import net.voltexstudios.npcConversations.listener.PlayerListener;
import net.voltexstudios.npcConversations.npc.NPC;
import net.voltexstudios.npcConversations.npc.NPCData;
import net.voltexstudios.npcConversations.npc.NPCService;
import net.voltexstudios.npcConversations.session.ConverstionSession;
import net.voltexstudios.npcConversations.util.OpenAI;
import net.voltexstudios.npcConversations.util.Type;
import org.bukkit.entity.Player;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.java.JavaPlugin;

import java.util.concurrent.TimeUnit;
import java.util.logging.Level;

public final class NPCConversations extends JavaPlugin {

    public static final TextComponent PREFIX = Component.text("§8[§eConversation§8] §7");

    public static Cache<Player, ConverstionSession> CACHE;
    public static Cache<Player, Type> USER_TYPE = CacheBuilder.newBuilder().build();

    private static NPCConversations instance;

    @Override
    public void onEnable() {
        instance = this;

        saveDefaultConfig();

        // Check api key and initialize OpenAI service
        OpenAI.init(getConfig().getString("API-KEY")).exceptionallyAsync(throwable -> {
            getLogger().severe("Error while initializing OpenAI service! Is your API key valid?");

            getServer().getPluginManager().disablePlugin(this);
            return null;
        });

        // Initialize cache
        CACHE = CacheBuilder.newBuilder()
                .expireAfterWrite(getConfig().getInt("conversation-expiration-duration"), TimeUnit.MINUTES)
                .removalListener((RemovalListener<Player, ConverstionSession>) notification -> {
                    if (notification.getKey() == null) return;
                    USER_TYPE.invalidate(notification.getKey());
                    if (notification.getCause() == RemovalCause.EXPIRED) {
                        notification.getKey().sendMessage(
                                PREFIX.append(Component.text("§cYour conversation has expired due to inactivity."))
                        );
                    }
                }).build();

        new NPCService(NPCData.loadNPCData());

        registerlisteners();
        registerCommands();

        getLogger().log(Level.INFO, "Plugin enabled!");
    }

    @Override
    public void onDisable() {
        getLogger().log(Level.INFO, "Plugin disabled!");
    }

    private void registerCommands() {
        getCommand("conversation").setExecutor(new ConversationCommand());
    }

    private void registerlisteners() {
        PluginManager pm = getServer().getPluginManager();

        pm.registerEvents(new PlayerListener(), this);
        pm.registerEvents(new ChatHandler(), this);
    }

    public static void startConversation(Player player, NPC npc, Type type) {
        if (CACHE.asMap().containsKey(player)) {
            CACHE.invalidate(player);

            player.sendMessage(
                    PREFIX.append(Component.text("§cYou are already in a conversation. Exiting the current conversation to start a new one."))
            );

            return;
        }

        ConverstionSession session = new ConverstionSession(npc, player);

        USER_TYPE.put(player, type);
        CACHE.put(player, session);

        player.sendMessage(
                PREFIX.append(Component.text("§aYou have started a conversation with " + npc.getName() + "."))
        );
    }

    public static NPCConversations getInstance() {
        return instance;
    }
}
