import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;


// Cette classe est celle qui gère la connexion à la base de données Niveaux.db
public class NiveauxDataConnect {
    //Création d'une variable de connexion à la base de données
    private static final String url = "jdbc:sqlite:Niveaux.db";
    private static boolean tablesCreees = false; // Variable pour vérifier si les tables ont été créées
    private static NiveauxDataConnect instance; // Instance unique de la classe NiveauDataConnect
    private static Connection maConnexion; //  Objet connexion à partager



    // ------------- Constructeur de la classe ------------------------
    // Il initialise la connexion à la base de données
    // Il crée la table niveau si elle n'existe pas déjà
    // Il insérer les niveaux dans la table niveau directement
    // Pour éviter à le faire à chaque fois que le jeu est lancé
    // NB : Le fichier de la base de donnée est dans le .jar
    // Il est nécessaire de l'initialiser afin de pouvoir le lire et écrire dessus
    // Car dans la .jar il est en lecture seule
    // Il faut donc le copier dans un endroit où il peut être modifié, par exemple dans le dossier du projet
    // Mon constructeur est en privé car personne ne doit pouvoir faire new NiveauDataConnect
    // ----------------------------------------------------------------
    private  NiveauxDataConnect() throws ClassNotFoundException, SQLException {
        // Initialisation de la connexion à la base de données
        maConnexion = getConnection();
        if (maConnexion != null) {
            System.out.println("Instance du singleton créée et connexion prête.");
        } else {
            System.out.println("Connexion échouée !");
        }
    }

    //--------------------------------------------------------------------------
    // Point d'accès global pour obtenir l'instance du singleton
    // On utilise synchronized pour éviter les problèmes si deux threads appellent
    // la méthode au démarrage en même temps
    //--------------------------------------------------------------------------
    public static synchronized NiveauxDataConnect getInstance(){
        try{
            if(instance == null){
            instance = new NiveauxDataConnect();
            }
            return instance;
        }catch(Exception e){
            e.printStackTrace();
        }
        return instance;
    }



    // -------------------------------------------------------------------------
    // Méthode de connexion à la base de données Niveaux.db
    // -------------------------------------------------------------------------
    public static Connection getConnection() throws SQLException{
        // On vérifie si ma connexion, singleton existe déjà et à déjà une valeur
        // Ou si elle a été fermé
        if(maConnexion == null || maConnexion.isClosed()){
        // On vérifiera si la BDD est déjà créé et possède déjà des données à l'intérieur
        // On devra ainsi l'extraire depuis le .jar 
            boolean baseExiste = bddInit.init();
            try{
                maConnexion = DriverManager.getConnection(url);
                System.out.println("Connexion à la base de données réussie !");
                if(!baseExiste){
                    // Vérifier si les tables ont déjà été créées pour éviter de les recréer à chaque connexion
                    if (!tablesCreees) {
                        // Créer la table niveau si elle n'existe pas déjà
                        CreerTableNiveaux(maConnexion);
                        tablesCreees = true; // Marquer les tables comme créées
                        // Insérer les niveaux dans la table niveau
                        insererNiveau(maConnexion);
                    }
                }
                
                return maConnexion;
            }catch(Exception e){
                e.printStackTrace();
            }
        }
            
            return maConnexion;
    }


    // -------------------------------------------------------------------------
    // Méthode pour créer la table Niveaux si elle n'existe pas déjà
    // -------------------------------------------------------------------------
    private static void CreerTableNiveaux(Connection conn) {
    
        String sql = "CREATE TABLE IF NOT EXISTS niveau( "
           + "id INTEGER PRIMARY KEY AUTOINCREMENT, "
           + "nom TEXT NOT NULL, " /*nom du niveau*/
           + "vitesse_ligne INTEGER NOT NULL, " /*vitesse de la ligne*/
           + "nb_segments INTEGER NOT NULL, "  /*nombre de segments à faire passer au joueur pour réussir le niveau*/
           + "image TEXT NOT NULL, " /*image du niveau*/
           + "multiplicateur_score INTEGER, " /*multiplier le score en fonction du niveau*/
           + "couleur_cercle TEXT NOT NULL " /*Couleur du cercle en fonctiond du niveau */
           +");" ;  

        try (Statement stmt = conn.createStatement()) {
            stmt.execute(sql);
            stmt.close();
        } catch (SQLException e) {
            System.err.println("Erreur lors de la création de la table Niveaux : " + e.getMessage());
            System.out.println("Connexion échouée !");
            e.printStackTrace();
        }

    }


    // -------------------------------------------------------------------------
    // Méthode pour insérer les niveaux dans la base de données
    // Les niveaux sont connus à l'avance et sont insérés directement
    // dans la base de données pour éviter de les insérer à chaque fois que 
    // le jeu est lancé
    // Pour corser le jeu, on utilisera l'id du niveau qui nous servira de difficulté
    // --------------------------------Niveau 1 -------------------------------- 
    // nom = "Facile", vitesse_ligne = 5, nb_segments = 50, image = "images\ciel.jpeg", multiplicateur_score = 1, couleur_cercle = "bleu"
    // --------------------------------Niveau 2 -------------------------------- 
    // nom = "intermédaire", vitesse_ligne = 7, nb_segments = 100, image = "images\montagnes.jpg", multiplicateur_score = 2, couleur_cercle = "gris"
    // --------------------------------Niveau 3 -------------------------------- 
    // nom = "Difficile", vitesse_ligne = 9, nb_segments = 100, image = "images\volcan.jpg", multiplicateur_score = 3, couleur_cercle = "marron"
    // --------------------------------Niveau 4 -------------------------------- 
    // nom = "Ultime", vitesse_ligne = 10, nb_segments = 150, image = "images\espace.jpg", multiplicateur_score = 4, couleur_cercle = "violet"
    // -------------------------------------------------------------------------
    public static void insererNiveau(Connection conn) {
        String query1 = "INSERT INTO niveau(nom, vitesse_ligne, nb_segments, image, multiplicateur_score, couleur_cercle) " 
                        + "VALUES('Facile', 5, 50, 'images/ciel.jpeg', 1, '#0000FF');";
                
        String query2 = "INSERT INTO niveau(nom, vitesse_ligne, nb_segments, image, multiplicateur_score, couleur_cercle) "
                        + "VALUES('Intermédiaire', 7, 100, 'images/montagnes.jpg', 2, '#808080');";
        String query3 = "INSERT INTO niveau(nom, vitesse_ligne, nb_segments, image, multiplicateur_score, couleur_cercle) "
                        + "VALUES('Difficile', 9, 100, 'images/volcan.jpg', 3, '#8B4513');";
        String query4 = "INSERT INTO niveau(nom, vitesse_ligne, nb_segments, image, multiplicateur_score, couleur_cercle) "
                        + "VALUES('Ultime', 10, 150, 'images/espace.jpg', 4, '#9400D3');";

        try (Statement stmt = conn.createStatement()) {
            stmt.execute(query1);
            stmt.execute(query2);
            stmt.execute(query3);
            stmt.execute(query4);
            tablesCreees = true ;
            stmt.close();
        } catch (SQLException e) {
            System.err.println("Erreur lors de l'insertion des niveaux : " + e.getMessage());
        }
    }

    // -------------------------------------------------------------------------
    // Méthode pour récupérer les niveaux depuis la base de données
    // Elle retourne un niveau en fonction de son id
    // -------------------------------------------------------------------------    
    public static Niveau recupererNiveau(Connection conn, int id) {
        Niveau niveauRecup = null;
        String sql = "SELECT * FROM niveau WHERE id = ?;";
        
        try (PreparedStatement pstmt = conn.prepareStatement(sql)){
            pstmt.setInt(1, id); // On remplace le 1er ? par l'id

            try(ResultSet rs = pstmt.executeQuery()) { 
                while (rs.next()) {
                    int id1 = rs.getInt("id");
                    String nom = rs.getString("nom");
                    int vitesse_ligne = rs.getInt("vitesse_ligne");
                    int nb_segments = rs.getInt("nb_segments");
                    String image = rs.getString("image");
                    int multiplicateur_score = rs.getInt("multiplicateur_score");
                    String couleur_cercle = rs.getString("couleur_cercle");
                    niveauRecup = new Niveau(id1, nom, vitesse_ligne, nb_segments, image, multiplicateur_score, couleur_cercle);
                }
            }

        } catch (SQLException e) {
            System.err.println("Erreur lors de la récupération des niveaux : " + e.getMessage());
        }
        return niveauRecup;
    }


}
