package me.km.snuviscript;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import me.hammerle.snuviscript.code.SnuviUtils;
import me.km.databank.DataBank;
import me.km.playerbank.PlayerManager;

public class ScriptBank implements IScriptBank {
    private final DataBank databank;
    private final PreparedStatement getVar;
    private final PreparedStatement getMapValue;
    private final PreparedStatement getDualMapValue;

    public ScriptBank(DataBank databank, PlayerManager manager) {
        this.databank = databank;
        databank.execute("CREATE TABLE IF NOT EXISTS scriptdata ("
                + "id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, "
                + "player_id INT NOT NULL, "
                + "var VARCHAR(20) NOT NULL, "
                + "value VARCHAR(256) NOT NULL, "
                + "UNIQUE INDEX (player_id,var), "
                + "FOREIGN KEY (player_id) REFERENCES minecraft.players(id) ON DELETE RESTRICT);");

        databank.execute("CREATE TABLE IF NOT EXISTS scriptmaps ("
                + "id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, "
                + "map VARCHAR(255) NOT NULL, "
                + "keyname VARCHAR(255) NOT NULL, "
                + "value VARCHAR(255) NOT NULL, "
                + "INDEX (map), "
                + "UNIQUE INDEX (map,keyname));");

        databank.execute("CREATE TABLE IF NOT EXISTS scriptdualmaps ("
                + "id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, "
                + "map VARCHAR(255) NOT NULL, "
                + "keyname VARCHAR(255) NOT NULL, "
                + "seckeyname VARCHAR(255) NOT NULL, "
                + "value VARCHAR(255) NOT NULL, "
                + "INDEX (map), "
                + "UNIQUE INDEX (map,keyname,seckeyname));");

        getVar = databank.prepareStatement("SELECT value from scriptdata WHERE player_id = ? and var = ?;");
        getMapValue = databank.prepareStatement("SELECT value from scriptmaps WHERE map = ? AND keyname = ?;");
        getDualMapValue = databank.prepareStatement("SELECT value from scriptdualmaps WHERE map = ? AND keyname = ? AND seckeyname = ?;");
    }

    @Override
    public void setVar(String value, String var, int playerId) throws Exception {
        try(PreparedStatement setVar = databank.prepareStatement(
                "INSERT INTO scriptdata (player_id,var,value) SELECT ?, ?, ? ON DUPLICATE KEY UPDATE scriptdata.value=?;")) {
            setVar.setInt(1, playerId);
            setVar.setString(2, var);
            setVar.setString(3, value);
            setVar.setString(4, value);
            setVar.executeUpdate();
        }
    }

    @Override
    public void deleteVar(String var, int playerId) throws Exception {
        try(PreparedStatement deleteVar = databank.prepareStatement(
                "DELETE FROM scriptdata WHERE player_id = ? AND var = ?;")) {
            deleteVar.setInt(1, playerId);
            deleteVar.setString(2, var);
            deleteVar.executeUpdate();
        }
    }

    @Override
    public Object getVar(String var, int playerId, Object error) throws Exception {
        getVar.setInt(1, playerId);
        getVar.setString(2, var);
        try(ResultSet rs = getVar.executeQuery()) {
            if(rs.next()) {
                return SnuviUtils.convert(rs.getString(1));
            }
            return error;
        }
    }

    @Override
    public Object getVar(String var, int playerId) throws Exception {
        return getVar(var, playerId, null);
    }

    @Override
    public void addMapElement(String map, String key, String value) throws Exception {
        try(PreparedStatement addMapElement = databank.prepareStatement(
                "INSERT INTO scriptmaps (map,keyname,value) SELECT ?, ?, ? ON DUPLICATE KEY UPDATE value=?;")) {
            addMapElement.setString(1, map);
            addMapElement.setString(2, key);
            addMapElement.setString(3, value);
            addMapElement.setString(4, value);
            addMapElement.executeUpdate();
        }
    }

    @Override
    public void removeMapElement(String map, String key) throws Exception {
        try(PreparedStatement removeMapElement = databank.prepareStatement(
                "DELETE FROM scriptmaps WHERE map = ? AND keyname = ?;")) {
            removeMapElement.setString(1, map);
            removeMapElement.setString(2, key);
            removeMapElement.executeUpdate();
        }
    }

    @Override
    public void removeMap(String map) throws Exception {
        try(PreparedStatement removeMap = databank.prepareStatement(
                "DELETE FROM scriptmaps WHERE map = ?;")) {
            removeMap.setString(1, map);
            removeMap.executeUpdate();
        }
    }

    @Override
    public Object getMapValue(String map, String key) throws Exception {
        getMapValue.setString(1, map);
        getMapValue.setString(2, key);
        try(ResultSet rs = getMapValue.executeQuery()) {
            if(rs.next()) {
                return SnuviUtils.convert(rs.getString(1));
            }
            return null;
        }
    }

    @Override
    public void addDualMapElement(String map, String key, String key2, String value) throws Exception {
        try(PreparedStatement addDualMapElement = databank.prepareStatement(
                "INSERT INTO scriptdualmaps (map,keyname,seckeyname,value) SELECT ?, ?, ?, ? ON DUPLICATE KEY UPDATE value=?;")) {
            addDualMapElement.setString(1, map);
            addDualMapElement.setString(2, key);
            addDualMapElement.setString(3, key2);
            addDualMapElement.setString(4, value);
            addDualMapElement.setString(5, value);
            addDualMapElement.executeUpdate();
        }
    }

    @Override
    public void removeDualMapElement(String map, String key) throws Exception {
        try(PreparedStatement removeDualMapElement = databank.prepareStatement(
                "DELETE FROM scriptdualmaps WHERE map = ? AND keyname = ?;")) {
            removeDualMapElement.setString(1, map);
            removeDualMapElement.setString(2, key);
            removeDualMapElement.executeUpdate();
        }
    }

    @Override
    public void removeDualMap(String map) throws Exception {
        try(PreparedStatement removeDualMap = databank.prepareStatement(
                "DELETE FROM scriptdualmaps WHERE map = ?;")) {
            removeDualMap.setString(1, map);
            removeDualMap.executeUpdate();
        }
    }

    @Override
    public void removeDualMapElement(String map, String key, String key2) throws Exception {
        try(PreparedStatement removeDualMapElement2 = databank.prepareStatement(
                "DELETE FROM scriptdualmaps WHERE map = ? AND keyname = ? AND seckeyname = ?;")) {
            removeDualMapElement2.setString(1, map);
            removeDualMapElement2.setString(2, key);
            removeDualMapElement2.setString(3, key2);
            removeDualMapElement2.executeUpdate();
        }
    }

    @Override
    public Object getDualMapValue(String map, String key, String key2) throws Exception {
        getDualMapValue.setString(1, map);
        getDualMapValue.setString(2, key);
        getDualMapValue.setString(3, key2);
        try(ResultSet rs = getDualMapValue.executeQuery()) {
            if(rs.next()) {
                return SnuviUtils.convert(rs.getString(1));
            }
            return null;
        }
    }
}
