package net.viper.bceconomy;

import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;

import java.sql.*;
import java.util.UUID;
import java.util.logging.Logger;

/**
 * Verwaltet die MySQL-Verbindung zur bc_accounts Tabelle.
 * Kein Cache – jeder Zugriff ist ein direkter DB-Query.
 * Kompatibel mit der Tabelle die StatusAPI / SurvivalPlus anlegt.
 */
public class BCDatabase {

    private static final String TABLE        = "bc_accounts";
    private static final String TABLE_NAMES  = "bc_player_names";

    private final Logger log;
    private HikariDataSource dataSource;

    public BCDatabase(Logger log, String host, int port, String database,
                      String user, String password) {
        this.log = log;

        HikariConfig cfg = new HikariConfig();
        cfg.setJdbcUrl("jdbc:mysql://" + host + ":" + port + "/" + database
                + "?useSSL=false&autoReconnect=true"
                + "&characterEncoding=UTF-8&useUnicode=true"
                + "&allowPublicKeyRetrieval=true");
        cfg.setUsername(user);
        cfg.setPassword(password);
        cfg.setMaximumPoolSize(5);
        cfg.setMinimumIdle(1);
        cfg.setConnectionTimeout(10_000);
        cfg.setIdleTimeout(600_000);
        cfg.setMaxLifetime(1_800_000);
        cfg.setPoolName("BCEconomy");
        cfg.addDataSourceProperty("cachePrepStmts",        "true");
        cfg.addDataSourceProperty("prepStmtCacheSize",     "250");
        cfg.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");

        try {
            dataSource = new HikariDataSource(cfg);
        } catch (Exception e) {
            log.severe("[BCEconomy] MySQL-Verbindung fehlgeschlagen: " + e.getMessage());
            return;
        }

        createTables();
        log.info("[BCEconomy] MySQL verbunden – Tabellen bereit.");
    }

    private void createTables() {
        // bc_accounts – kompatibel mit SurvivalPlus-Struktur (id + player_name + balance)
        // Wir legen sie nur an wenn sie noch nicht existieren.
        String createAccounts =
                "CREATE TABLE IF NOT EXISTS `" + TABLE + "` (" +
                "  `id`          INT(10)      NOT NULL AUTO_INCREMENT," +
                "  `player_name` VARCHAR(50)  NOT NULL," +
                "  `balance`     DOUBLE(30,2) NOT NULL DEFAULT 0.00," +
                "  PRIMARY KEY (`id`)," +
                "  UNIQUE KEY `player_name` (`player_name`)" +
                ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;";

        String createNames =
                "CREATE TABLE IF NOT EXISTS `" + TABLE_NAMES + "` (" +
                "  `uuid`    VARCHAR(36) NOT NULL PRIMARY KEY," +
                "  `name`    VARCHAR(16) NOT NULL," +
                "  `updated` BIGINT      NOT NULL" +
                ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;";

        try (Connection con = dataSource.getConnection()) {
            try (PreparedStatement ps = con.prepareStatement(createAccounts)) {
                ps.executeUpdate();
            }
            try (PreparedStatement ps = con.prepareStatement(createNames)) {
                ps.executeUpdate();
            }
        } catch (SQLException e) {
            log.severe("[BCEconomy] Tabellen-Setup fehlgeschlagen: " + e.getMessage());
        }
    }

    public boolean isConnected() {
        return dataSource != null && !dataSource.isClosed();
    }

    public void close() {
        if (isConnected()) dataSource.close();
    }

    // ────────────────────────────────────────────────
    //  Balance – direkt aus DB (kein Cache)
    // ────────────────────────────────────────────────

    /**
     * Liest Balance direkt aus der DB.
     * @return Balance oder -1 wenn kein Konto vorhanden.
     */
    public double loadBalance(UUID uuid) {
        if (!isConnected()) return -1;
        try (Connection con = dataSource.getConnection();
             PreparedStatement ps = con.prepareStatement(
                     "SELECT `balance` FROM `" + TABLE + "` WHERE `player_name` = ?")) {
            ps.setString(1, uuid.toString());
            try (ResultSet rs = ps.executeQuery()) {
                if (rs.next()) return rs.getDouble("balance");
            }
        } catch (SQLException e) {
            log.warning("[BCEconomy] loadBalance fehlgeschlagen für " + uuid + ": " + e.getMessage());
        }
        return -1;
    }

    /**
     * Schreibt Balance direkt in die DB (INSERT oder UPDATE).
     */
    public void saveBalance(UUID uuid, double balance) {
        if (!isConnected()) return;
        try (Connection con = dataSource.getConnection();
             PreparedStatement ps = con.prepareStatement(
                     "INSERT INTO `" + TABLE + "` (`player_name`, `balance`) VALUES (?, ?) " +
                     "ON DUPLICATE KEY UPDATE `balance` = VALUES(`balance`)")) {
            ps.setString(1, uuid.toString());
            ps.setDouble(2, balance);
            ps.executeUpdate();
        } catch (SQLException e) {
            log.warning("[BCEconomy] saveBalance fehlgeschlagen für " + uuid + ": " + e.getMessage());
        }
    }

    /**
     * Legt ein neues Konto mit Startguthaben an, falls noch keines existiert.
     */
    public void createAccountIfAbsent(UUID uuid, double startBalance) {
        if (!isConnected()) return;
        try (Connection con = dataSource.getConnection();
             PreparedStatement ps = con.prepareStatement(
                     "INSERT IGNORE INTO `" + TABLE + "` (`player_name`, `balance`) VALUES (?, ?)")) {
            ps.setString(1, uuid.toString());
            ps.setDouble(2, startBalance);
            ps.executeUpdate();
        } catch (SQLException e) {
            log.warning("[BCEconomy] createAccount fehlgeschlagen für " + uuid + ": " + e.getMessage());
        }
    }

    public boolean hasAccount(UUID uuid) {
        return loadBalance(uuid) >= 0;
    }

    // ────────────────────────────────────────────────
    //  Name-Mapping (für Offline-Spieler Lookup)
    // ────────────────────────────────────────────────

    public void saveNameMapping(UUID uuid, String name) {
        if (!isConnected()) return;
        try (Connection con = dataSource.getConnection();
             PreparedStatement ps = con.prepareStatement(
                     "INSERT INTO `" + TABLE_NAMES + "` (`uuid`, `name`, `updated`) VALUES (?, ?, ?) " +
                     "ON DUPLICATE KEY UPDATE `name` = VALUES(`name`), `updated` = VALUES(`updated`)")) {
            ps.setString(1, uuid.toString());
            ps.setString(2, name);
            ps.setLong(3, System.currentTimeMillis());
            ps.executeUpdate();
        } catch (SQLException e) {
            log.warning("[BCEconomy] saveNameMapping fehlgeschlagen: " + e.getMessage());
        }
    }

    public UUID resolveUUIDByName(String name) {
        if (!isConnected()) return null;
        // 1. Eigene bc_player_names Tabelle
        try (Connection con = dataSource.getConnection();
             PreparedStatement ps = con.prepareStatement(
                     "SELECT `uuid` FROM `" + TABLE_NAMES + "` WHERE `name` = ? LIMIT 1")) {
            ps.setString(1, name);
            try (ResultSet rs = ps.executeQuery()) {
                if (rs.next()) {
                    return UUID.fromString(rs.getString("uuid"));
                }
            }
        } catch (SQLException | IllegalArgumentException e) {
            // ignorieren
        }
        // 2. CMI_users Fallback
        try (Connection con = dataSource.getConnection();
             PreparedStatement ps = con.prepareStatement(
                     "SELECT `player_uuid` FROM `CMI_users` WHERE `username` = ? LIMIT 1")) {
            ps.setString(1, name);
            try (ResultSet rs = ps.executeQuery()) {
                if (rs.next()) {
                    String raw = rs.getString("player_uuid");
                    if (raw != null && !raw.isEmpty()) return UUID.fromString(raw);
                }
            }
        } catch (SQLException | IllegalArgumentException e) {
            // CMI nicht installiert – kein Problem
        }
        return null;
    }
}
