package ru.redguy.qseller;

import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import me.clip.placeholderapi.PlaceholderAPI;
import net.citizensnpcs.api.event.NPCRightClickEvent;
import net.milkbowl.vault.economy.Economy;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.OfflinePlayer;
import org.bukkit.configuration.serialization.ConfigurationSerialization;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.plugin.RegisteredServiceProvider;
import org.bukkit.plugin.java.JavaPlugin;
import org.ipvp.canvas.MenuFunctionListener;
import org.jetbrains.annotations.NotNull;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

public final class QSeller extends JavaPlugin implements Listener {

    static {
        ConfigurationSerialization.registerClass(SellItem.class, "SellItem");
    }

    private static QSeller instance;

    public static QSeller getInstance() {
        return instance;
    }

    public Economy econ = null;

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

        defConf("db.type","h2");
        defConf("db._typeComment","h2 or mysql");

        defConf("db.h2.file","base.db");

        defConf("db.mysql.host","localhost");
        defConf("db.mysql.port",3306);
        defConf("db.mysql.base","reputation");
        defConf("db.mysql.tablePrefix","seller_");
        defConf("db.mysql.user","admin");
        defConf("db.mysql.pass","StarWarsMonster123");
        defConf("db.mysql.useSSL",false);
        defConf("db.mysql.maximumPoolSize",1);
        defConf("db.mysql.minimumIdle",1);
        defConf("db.mysql.serverTimezone","UTC");
        defConf("db.mysql.maxLifetimeSeconds",30);

        defConf("game.menu.structure",new ArrayList<String>() {{
            add("#########");add("#iiiiiii#");add("#iiiiiii#");add("#iiiiiii#");add("#########");add("####b####");
        }});
        defConf("game.menu.title","Торговец {{level}} ур.");
        defConf("game.menu.npcs",new ArrayList<Integer>() {{
            add(-1);
        }});
        defConf("game.menu.items",new ArrayList<SellItem>() {{
            add(new SellItem(Material.SUGAR_CANE));add(new SellItem(Material.CARROT_ITEM));
            add(new SellItem(Material.POTATO_ITEM));add(new SellItem(Material.MELON_BLOCK));
            add(new SellItem(Material.PUMPKIN));add(new SellItem(Material.NETHER_STALK));
            add(new SellItem(Material.CACTUS));add(new SellItem(Material.STRING));
        }});
        defConf("game.menu.startStacks",10);
        defConf("game.menu.step",15);
        defConf("game.menu.backgroundColor",15);
        defConf("game.menu.maxVillagerLevel",100);
        defConf("game.menu.item.lore",new ArrayList<String>() {{
            add("Нажмите, чтобы продать");
            add("Стак за {{price}}");
            add("Мин. цена {{min_price}}");
            add("Прогресс {{progress_cur}}/{{progress_max}} стаков");
        }});
        defConf("game.menu.info.tittle","Информация");
        defConf("game.menu.info.lore",new ArrayList<String>() {{
            add("Торгуй с умом");
        }});

        defConf("messages.mustBePlayer","Ты должен быть игроком");
        defConf("messages.notAnyWhere","Вы не можете открывать торговлю дистанционно");
        defConf("messages.noPerm","У вас прав нет на это");
        defConf("messages.sold","Вы продали стак и получили {{price}}");
        defConf("messages.notEnoughItems","Для продажи нужем минимум стак!");

        saveConfig();

        if (getServer().getPluginManager().getPlugin("Vault") == null) {
            getLogger().warning("Oh shit, vault not found!");
        }
        RegisteredServiceProvider<Economy> rsp = getServer().getServicesManager().getRegistration(Economy.class);
        if (rsp == null) {
            getLogger().warning("Oh shit, vault economy not found!");
        }
        econ = rsp.getProvider();

        if(this.getString("db.type").equals("mysql")) {
            HikariConfig config = new HikariConfig();
            config.setJdbcUrl("jdbc:mysql://" + getString("db.mysql.host") + ":" + getInt("db.mysql.port") + "/" + getString("db.mysql.base") + "?serverTimezone=" + getString("db.mysql.serverTimezone") + "&allowPublicKeyRetrieval=true&useSSL=" + getBoolean("db.mysql.useSSL"));
            config.setUsername(getString("db.mysql.user"));
            config.setPassword(getString("db.mysql.pass"));
            config.setDriverClassName("com.mysql.cj.jdbc.Driver");
            config.addDataSourceProperty("cachePrepStmts", "true");
            config.addDataSourceProperty("prepStmtCacheSize", "250");
            config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
            config.addDataSourceProperty("maximumPoolSize", getInt("db.mysql.maximumPoolSize"));
            config.addDataSourceProperty("minimumIdle", getInt("db.mysql.minimumIdle"));
            config.setMaxLifetime(getInt("db.mysql.maxLifetimeSeconds")*1000L);

            new MySQLDatabase(new HikariDataSource(config),this.getString("db.mysql.tablePrefix"));
        } else {
            HikariConfig config = new HikariConfig();
            config.setJdbcUrl("jdbc:h2:"+new File(getDataFolder(),getString("db.h2.file")).getAbsolutePath());
            config.setDriverClassName("org.h2.Driver");

            new H2Database(new HikariDataSource(config));
        }

        Bukkit.getPluginManager().registerEvents(new MenuFunctionListener(), this);
        Bukkit.getPluginManager().registerEvents(this,this);

        Bukkit.getServer().getPluginCommand("qseller").setExecutor(new QSellerCommand());
        Bukkit.getServer().getPluginCommand("qseller").setTabCompleter(new QSellerCommand.TabComplete());
    }

    @EventHandler
    public void onNPCClick(NPCRightClickEvent event) {
        if(getConfig().getIntegerList("game.menu.npcs").contains(event.getNPC().getId())) {
            new QSellerMenu().open(event.getClicker());
        }
    }

    @Override
    public void onDisable() {
        Database.getInstance().disconnect();
    }

    public String getString(String name) {
        return getConfig().getString(name);
    }

    public List<String> getStringList(String name) {
        return getConfig().getStringList(name);
    }

    public List<SellItem> getSellItemList(String name) {
        List<?> somethingList = getConfig().getList(name);
        if (somethingList == null) {
            return new ArrayList<>(0);
        }
        List<SellItem> result = new ArrayList<>();
        for (Object object : somethingList) {
            if (object instanceof SellItem) {
                result.add((SellItem) object);
            }
        }
        return result;
    }


    public List<String> getParsedStringList(String name, OfflinePlayer player) {
        return getConfig().getStringList(name).stream().map(str -> PlaceholderAPI.setPlaceholders(player, parseInternalPlaceholders(ChatColor.translateAlternateColorCodes('&',str),player))).collect(Collectors.toList());
    }

    @NotNull
    public String getParsedString(String name) {
        return ChatColor.translateAlternateColorCodes('&',getConfig().getString(name));
    }

    @NotNull
    public String getParsedString(String name, OfflinePlayer player) {
        return PlaceholderAPI.setPlaceholders(player, parseInternalPlaceholders(ChatColor.translateAlternateColorCodes('&',getConfig().getString(name)),player));
    }

    public String parseInternalPlaceholders(String text, OfflinePlayer player) {
        return text.replaceAll("\\{\\{level}}",String.valueOf(Database.getInstance().getVillagerLevel(player.getUniqueId())));
    }

    public int getInt(String name) {
        return getConfig().getInt(name);
    }

    public boolean getBoolean(String name) {
        return getConfig().getBoolean(name);
    }

    private void defConf(String name, Object value) {
        if(!getConfig().isSet(name))
            getConfig().set(name, value);
    }
}
