package fr.luc.gamingcore.database;

import fr.luc.gamingcore.Main;

import java.io.File;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.logging.Level;

/**
 * Gestionnaire de la connexion et de l'initialisation du schéma de base de données SQLite.
 */
public class DatabaseManager {

    private final Main plugin;
    private final File dbFile;
    private Connection connection;

    /**
     * Constructeur du DatabaseManager.
     *
     * @param plugin Instance principale du plugin.
     */
    public DatabaseManager(Main plugin) {
        this.plugin = plugin;
        this.dbFile = new File(plugin.getDataFolder(), "guilds.db");
    }

    /**
     * Initialise le dossier de données, ouvre la connexion SQLite et crée les tables si nécessaires.
     */
    public synchronized void initialize() {
        if (!plugin.getDataFolder().exists()) {
            plugin.getDataFolder().mkdirs();
        }

        try {
            connect();
            createTables();
            plugin.getLogger().info("Base de donnees SQLite des guildes initialisee avec succes !");
        } catch (SQLException e) {
            plugin.getLogger().log(Level.SEVERE, "Erreur fatale lors de l'initialisation de la base SQLite des guildes !", e);
        }
    }

    /**
     * Établit la connexion JDBC vers le fichier SQLite local.
     *
     * @throws SQLException Si la connexion échoue.
     */
    private synchronized void connect() throws SQLException {
        if (connection != null && !connection.isClosed()) {
            return;
        }

        try {
            Class.forName("org.sqlite.JDBC");
        } catch (ClassNotFoundException ignored) {}

        String url = "jdbc:sqlite:" + dbFile.getAbsolutePath();
        this.connection = DriverManager.getConnection(url);
    }

    /**
     * Obtient la connexion active vers la base de données.
     *
     * @return L'instance Connection active.
     * @throws SQLException Si la réouverture de connexion échoue.
     */
    public synchronized Connection getConnection() throws SQLException {
        if (connection == null || connection.isClosed()) {
            connect();
        }
        return connection;
    }

    /**
     * Crée toutes les tables requises pour le système de guilde.
     *
     * @throws SQLException En cas d'erreur d'exécution DDL.
     */
    private void createTables() throws SQLException {
        try (Statement stmt = getConnection().createStatement()) {
            // Table des guildes
            stmt.executeUpdate("CREATE TABLE IF NOT EXISTS guilds (" +
                    "id VARCHAR(36) PRIMARY KEY, " +
                    "name VARCHAR(16) NOT NULL UNIQUE, " +
                    "tag VARCHAR(6), " +
                    "color VARCHAR(7) NOT NULL DEFAULT '#00C9FF', " +
                    "description VARCHAR(128), " +
                    "balance DOUBLE NOT NULL DEFAULT 0.0, " +
                    "home_world VARCHAR(64), " +
                    "home_x DOUBLE NOT NULL DEFAULT 0.0, " +
                    "home_y DOUBLE NOT NULL DEFAULT 0.0, " +
                    "home_z DOUBLE NOT NULL DEFAULT 0.0, " +
                    "home_yaw FLOAT NOT NULL DEFAULT 0.0, " +
                    "home_pitch FLOAT NOT NULL DEFAULT 0.0, " +
                    "created_at BIGINT NOT NULL" +
                    ");");

            // Migration : ajout de la colonne color si elle n'existe pas
            try {
                stmt.executeUpdate("ALTER TABLE guilds ADD COLUMN color VARCHAR(7) DEFAULT '#00C9FF'");
            } catch (SQLException ignored) {
                // La colonne existe déjà
            }

            // Table des rangs de guilde
            stmt.executeUpdate("CREATE TABLE IF NOT EXISTS guild_ranks (" +
                    "id VARCHAR(64) NOT NULL, " +
                    "guild_id VARCHAR(36) NOT NULL, " +
                    "name VARCHAR(32) NOT NULL, " +
                    "priority INTEGER NOT NULL DEFAULT 1, " +
                    "is_default INTEGER NOT NULL DEFAULT 0, " +
                    "permissions TEXT, " +
                    "PRIMARY KEY (id, guild_id), " +
                    "FOREIGN KEY (guild_id) REFERENCES guilds(id) ON DELETE CASCADE" +
                    ");");

            // Table des membres de guilde
            stmt.executeUpdate("CREATE TABLE IF NOT EXISTS guild_members (" +
                    "player_uuid VARCHAR(36) PRIMARY KEY, " +
                    "guild_id VARCHAR(36) NOT NULL, " +
                    "rank_id VARCHAR(64) NOT NULL, " +
                    "joined_at BIGINT NOT NULL, " +
                    "last_online BIGINT NOT NULL, " +
                    "contributed_money DOUBLE NOT NULL DEFAULT 0.0, " +
                    "FOREIGN KEY (guild_id) REFERENCES guilds(id) ON DELETE CASCADE" +
                    ");");

            // Table des claims de territoire
            stmt.executeUpdate("CREATE TABLE IF NOT EXISTS guild_claims (" +
                    "id INTEGER PRIMARY KEY AUTOINCREMENT, " +
                    "guild_id VARCHAR(36) NOT NULL, " +
                    "world VARCHAR(64) NOT NULL, " +
                    "chunk_x INTEGER NOT NULL, " +
                    "chunk_z INTEGER NOT NULL, " +
                    "claimed_at BIGINT NOT NULL, " +
                    "FOREIGN KEY (guild_id) REFERENCES guilds(id) ON DELETE CASCADE" +
                    ");");

            // Table de l'historique d'actions (logs)
            stmt.executeUpdate("CREATE TABLE IF NOT EXISTS guild_logs (" +
                    "id INTEGER PRIMARY KEY AUTOINCREMENT, " +
                    "guild_id VARCHAR(36) NOT NULL, " +
                    "actor_uuid VARCHAR(36), " +
                    "actor_name VARCHAR(32) NOT NULL, " +
                    "action_type VARCHAR(32) NOT NULL, " +
                    "details TEXT NOT NULL, " +
                    "timestamp BIGINT NOT NULL, " +
                    "FOREIGN KEY (guild_id) REFERENCES guilds(id) ON DELETE CASCADE" +
                    ");");
        }
    }

    /**
     * Ferme proprement la connexion à la base de données lors de l'arrêt du plugin.
     */
    public synchronized void close() {
        try {
            if (connection != null && !connection.isClosed()) {
                connection.close();
            }
        } catch (SQLException e) {
            plugin.getLogger().log(Level.WARNING, "Erreur lors de la fermeture de la connexion SQLite", e);
        }
    }
}
