package linea;

import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;


public class DatabaseConnection {

    private static final Path DB_PATH = resolveDbPath();
    private static final String DB_URL = "jdbc:sqlite:" + DB_PATH;
    private Connection conn;

    private static Path resolveDbPath() {
        Path cwd = Paths.get("").toAbsolutePath().normalize();
        Path inProjetDev = cwd.resolve("Projet-Dev").resolve("Jeu.db");
        if (Files.exists(cwd.resolve("Projet-Dev"))) {
            return inProjetDev;
        }
        return cwd.resolve("Jeu.db");
    }

    public void connect() {
        try {
            Path parent = DB_PATH.getParent();
            if (parent != null) {
                Files.createDirectories(parent);
            }
            conn = DriverManager.getConnection(DB_URL);
            System.out.println("Connexion à la DB OK: " + DB_PATH);
        } catch (SQLException e) {
            System.err.println("Erreur de connexion DB: " + e.getMessage());
        } catch (Exception e) {
            System.err.println("Erreur accès fichier DB: " + e.getMessage());
        }
    }

    public void disconnect() {
        if (conn == null) {
            return;
        }
        try {
            if (!conn.isClosed()) {
                conn.close();
                System.out.println("Déconnexion DB OK");
            }
        } catch (SQLException e) {
            System.err.println("Erreur à la fermeture DB: " + e.getMessage());
        }
    }

    public void createTables() {
        if (conn == null) {
            System.err.println("DB non connectée, impossible de créer les tables.");
            return;
        }

        String createCompte = """
                    CREATE TABLE IF NOT EXISTS Compte (
                        id_compte INTEGER PRIMARY KEY AUTOINCREMENT,
                        pseudo TEXT NOT NULL
                    );
                """;

        String createScore = """
                    CREATE TABLE IF NOT EXISTS Score (
                        id_score INTEGER PRIMARY KEY AUTOINCREMENT,
                        valeur_score INTEGER,
                        nb_mort INTEGER,
                        temps_jeu INTEGER,
                        id_compte INTEGER,
                        FOREIGN KEY(id_compte) REFERENCES Compte(id_compte)
                    );
                """;

        String createProgressionCampagne = """
                    CREATE TABLE IF NOT EXISTS ProgressionCampagne (
                        id_compte INTEGER PRIMARY KEY,
                        niveau_debloque_max INTEGER NOT NULL DEFAULT 1,
                        FOREIGN KEY(id_compte) REFERENCES Compte(id_compte)
                    );
                """;

        try (Statement stmt = conn.createStatement()) {
            stmt.executeUpdate(createCompte);
            stmt.executeUpdate(createScore);
            stmt.executeUpdate("DROP TABLE IF EXISTS Niveau");
            stmt.executeUpdate(createProgressionCampagne);
            System.out.println("Tables créées / existantes OK");
        } catch (SQLException e) {
            System.err.println("Erreur création tables : " + e.getMessage());
        }
    }

    public void sauvegarderScore(int valeur, int idCompte, int nbMort, int tempsJeuSec) {
        if (conn == null || idCompte <= 0) return;
        String sql = "INSERT INTO Score (valeur_score, nb_mort, temps_jeu, id_compte) VALUES (?, ?, ?, ?)";
        try (PreparedStatement ps = conn.prepareStatement(sql)) {
            ps.setInt(1, valeur);
            ps.setInt(2, nbMort);
            ps.setInt(3, tempsJeuSec);
            ps.setInt(4, idCompte);
            ps.executeUpdate();
        } catch (SQLException e) {
            System.err.println("Erreur sauvegarde score : " + e.getMessage());
        }
    }

    public int getMeilleurScoreParCompte(int idCompte) {
        if (conn == null || idCompte <= 0) return 0;
        String sql = "SELECT MAX(valeur_score) FROM Score WHERE id_compte = ?";
        try (PreparedStatement ps = conn.prepareStatement(sql)) {
            ps.setInt(1, idCompte);
            try (ResultSet rs = ps.executeQuery()) {
                if (rs.next()) return rs.getInt(1);
            }
        } catch (SQLException e) {
            System.err.println("Erreur lecture meilleur score : " + e.getMessage());
        }
        return 0;
    }

    public int creerCompte(String pseudo) {
        if (conn == null || pseudo == null || pseudo.isBlank()) return -1;
        String sql = "INSERT INTO Compte (pseudo) VALUES (?)";
        try (PreparedStatement ps = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) {
            ps.setString(1, pseudo.trim());
            ps.executeUpdate();
            try (ResultSet rs = ps.getGeneratedKeys()) {
                if (rs.next()) {
                    int idCompte = rs.getInt(1);
                    initialiserProgressionCampagne(idCompte);
                    return idCompte;
                }
            }
        } catch (SQLException e) {
            System.err.println("Erreur création compte : " + e.getMessage());
        }
        return -1;
    }

    public int getIdParPseudo(String pseudo) {
        if (conn == null || pseudo == null || pseudo.isBlank()) return -1;
        String sql = "SELECT id_compte FROM Compte WHERE pseudo = ? LIMIT 1";
        try (PreparedStatement ps = conn.prepareStatement(sql)) {
            ps.setString(1, pseudo.trim());
            try (ResultSet rs = ps.executeQuery()) {
                if (rs.next()) return rs.getInt(1);
            }
        } catch (SQLException e) {
            System.err.println("Erreur lecture compte : " + e.getMessage());
        }
        return -1;
    }

    public void supprimerCompte(int idCompte) {
        if (conn == null || idCompte <= 0) return;
        try (PreparedStatement ps0 = conn.prepareStatement("DELETE FROM ProgressionCampagne WHERE id_compte = ?");
             PreparedStatement ps1 = conn.prepareStatement("DELETE FROM Score WHERE id_compte = ?");
             PreparedStatement ps2 = conn.prepareStatement("DELETE FROM Compte WHERE id_compte = ?")) {
            ps0.setInt(1, idCompte);
            ps0.executeUpdate();
            ps1.setInt(1, idCompte);
            ps1.executeUpdate();
            ps2.setInt(1, idCompte);
            ps2.executeUpdate();
        } catch (SQLException e) {
            System.err.println("Erreur suppression compte : " + e.getMessage());
        }
    }

    public List<String> getPseudos() {
        List<String> pseudos = new ArrayList<>();
        if (conn == null) return pseudos;
        String sql = "SELECT pseudo FROM Compte ORDER BY pseudo";
        try (Statement stmt = conn.createStatement();
             ResultSet rs = stmt.executeQuery(sql)) {
            while (rs.next()) {
                pseudos.add(rs.getString("pseudo"));
            }
        } catch (SQLException e) {
            System.err.println("Erreur lecture comptes : " + e.getMessage());
        }
        return pseudos;
    }

    private void initialiserProgressionCampagne(int idCompte) {
        if (conn == null || idCompte <= 0) return;
        String sql = "INSERT OR IGNORE INTO ProgressionCampagne (id_compte, niveau_debloque_max) VALUES (?, 1)";
        try (PreparedStatement ps = conn.prepareStatement(sql)) {
            ps.setInt(1, idCompte);
            ps.executeUpdate();
        } catch (SQLException e) {
            System.err.println("Erreur init progression campagne : " + e.getMessage());
        }
    }

    public int getNiveauDebloqueCampagne(int idCompte) {
        if (conn == null || idCompte <= 0) return 1;

        initialiserProgressionCampagne(idCompte);
        String sql = "SELECT niveau_debloque_max FROM ProgressionCampagne WHERE id_compte = ?";
        try (PreparedStatement ps = conn.prepareStatement(sql)) {
            ps.setInt(1, idCompte);
            try (ResultSet rs = ps.executeQuery()) {
                if (rs.next()) {
                    int niveau = rs.getInt("niveau_debloque_max");
                    if (niveau < 1) return 1;
                    return Math.min(100, niveau);
                }
            }
        } catch (SQLException e) {
            System.err.println("Erreur lecture progression campagne : " + e.getMessage());
        }
        return 1;
    }

    public void debloquerNiveauCampagne(int idCompte, int niveauTermine) {
        if (conn == null || idCompte <= 0) return;

        int niveauCible = Math.min(100, Math.max(1, niveauTermine + 1));
        initialiserProgressionCampagne(idCompte);

        String sql = "UPDATE ProgressionCampagne SET niveau_debloque_max = MAX(niveau_debloque_max, ?) WHERE id_compte = ?";
        try (PreparedStatement ps = conn.prepareStatement(sql)) {
            ps.setInt(1, niveauCible);
            ps.setInt(2, idCompte);
            ps.executeUpdate();
        } catch (SQLException e) {
            System.err.println("Erreur mise à jour progression campagne : " + e.getMessage());
        }
    }

    public String getStatsParCompte(int idCompte) {
        if (conn == null || idCompte <= 0) {
            return "Aucune statistique disponible.";
        }

        String sql = "SELECT COALESCE(SUM(nb_mort),0) AS morts, "
                + "COALESCE(SUM(temps_jeu),0) AS temps, "
                + "COALESCE(MAX(valeur_score),0) AS meilleur "
                + "FROM Score WHERE id_compte = ?";
        try (PreparedStatement ps = conn.prepareStatement(sql)) {
            ps.setInt(1, idCompte);
            try (ResultSet rs = ps.executeQuery()) {
                if (rs.next()) {
                    int morts = rs.getInt("morts");
                    int temps = rs.getInt("temps");
                    int meilleur = rs.getInt("meilleur");
                    return "Nombre de morts : " + morts
                            + "\nTemps de jeu total : " + temps + " s"
                            + "\nMeilleur score : " + meilleur;
                }
            }
        } catch (SQLException e) {
            return "Erreur lecture stats : " + e.getMessage();
        }
        return "Aucune statistique disponible.";
    }

    public String getStatsCampagneParCompte(int idCompte) {
        if (conn == null || idCompte <= 0) {
            return "Campagne : non disponible.";
        }

        int niveauMax = getNiveauDebloqueCampagne(idCompte);
        int niveauxTermines = Math.max(0, niveauMax - 1);

        return "Campagne\n"
            + "Niveau max atteint : " + niveauMax
                + "\nNiveaux terminés : " + niveauxTermines;
    }
}

