package ru.redguy.qseller;

import com.zaxxer.hikari.HikariDataSource;
import org.bukkit.Material;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.UUID;

public abstract class Database {
    protected static Database instance;

    public static Database getInstance() {
        return instance;
    }

    private HikariDataSource ds;
    private final String prefix;

    protected Database(HikariDataSource ds, String tablePrefix) {
        this.ds = ds;
        prefix = tablePrefix;
        dataBaseCheck();
    }

    abstract boolean isTableExists(String name, Connection con) throws SQLException;

    private void dataBaseCheck() {
        try (Connection con = ds.getConnection()) {
            if (!isTableExists("OPTIONS", con)) {
                PreparedStatement ps = con.prepareStatement("CREATE TABLE " + prefix + "options (option_name text not null,option_value text null);");
                ps.execute();
                ps = con.prepareStatement("INSERT INTO " + prefix + "options (option_name, option_value) VALUES ('schema_version', '1');");
                ps.execute();
            }
            PreparedStatement ps = con.prepareStatement("SELECT * FROM " + prefix + "options WHERE option_name = 'schema_version';");
            ResultSet rs = ps.executeQuery();
            rs.next();
            String schema_version = rs.getString("option_value");
            switch (schema_version) {
                case "1": {
                    if (!isTableExists("players", con)) {
                        ps = con.prepareStatement("create table " + prefix + "players (uuid text not null,villager_level int default 1 null);");
                        ps.execute();
                    }
                    if (!isTableExists("items", con)) {
                        ps = con.prepareStatement("create table " + prefix + "items (player text not null,item text not null,sold int default 0 not null);");
                        ps.execute();
                    }
                    break;
                }
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
    }

    public String getPrefix() {
        return prefix;
    }

    public void disconnect() {
        this.ds.close();
    }

    public int getVillagerLevel(UUID uuid) {
        try (Connection con = ds.getConnection()) {
            PreparedStatement ps = con.prepareStatement("SELECT * FROM " + prefix + "players WHERE uuid = ?");
            ps.setString(1, uuid.toString());
            ResultSet rs = ps.executeQuery();
            if (rs.next()) {
                return rs.getInt("villager_level");
            }
            ps = con.prepareStatement("INSERT INTO " + prefix + "players (uuid) VALUES (?)");
            ps.setString(1, uuid.toString());
            ps.execute();
            return getVillagerLevel(uuid);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return -1;
    }

    public int getItemProgress(UUID uuid, Material material) {
        try (Connection con = ds.getConnection()) {
            PreparedStatement ps = con.prepareStatement("SELECT * FROM " + prefix + "items WHERE player = ? AND item = ?");
            ps.setString(1, uuid.toString());
            ps.setString(2, material.name());
            ResultSet rs = ps.executeQuery();
            if (rs.next()) {
                return rs.getInt("sold");
            }
            ps = con.prepareStatement("INSERT INTO " + prefix + "items (player, item) VALUES (?, ?)");
            ps.setString(1, uuid.toString());
            ps.setString(2, material.name());
            ps.execute();
            return getItemProgress(uuid, material);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return 0;
    }

    public void progressItem(UUID uuid, Material material) {
        try (Connection con = ds.getConnection()) {
            PreparedStatement ps = con.prepareStatement("UPDATE " + prefix + "items SET sold = sold+1 WHERE player = ? AND item = ?");
            ps.setString(1, uuid.toString());
            ps.setString(2, material.name());
            ps.execute();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
    }

    public void progressVillager(UUID uuid) {
        try (Connection con = ds.getConnection()) {
            PreparedStatement ps = con.prepareStatement("UPDATE " + prefix + "players SET villager_level = villager_level+1 WHERE uuid = ?");
            ps.setString(1, uuid.toString());
            ps.execute();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
    }
}
