package fr.univ.dblp;

import fr.univ.dblp.analysis.*;
import fr.univ.dblp.export.ResultsPrinter;
import fr.univ.dblp.generators.CopyGenerator;
import fr.univ.dblp.generators.NetworkGenerator;
import fr.univ.dblp.loader.GraphLoader;
import org.graphstream.graph.Graph;

import java.util.Scanner;

/**
 * Point d'entrée principal pour l'analyse du réseau DBLP.
 *
 * Cette classe gère le menu interactif et orchestre l'exécution
 * des différentes analyses du réseau de collaboration scientifique DBLP.
 *
 * @author Hamadou BA
 * @see <a href="https://www-apps.univ-lehavre.fr/forge/bh243413/tp2-ri-mesures-de-reseaux-interaction.git">Dépôt Git</a>
 */
public class Main {

    private static final String DBLP_FILE_PATH = "src/main/resources/snap/com-dblp.ungraph.txt";
    private static Graph dblpGraph = null;
    private static Graph baGraph = null;

    public static void main(String[] args) {
        ResultsPrinter.printHeader("TP: ANALYSE DU RÉSEAU DBLP");
        ResultsPrinter.printInfo("Mesures de réseaux d'interaction - Collaboration scientifique");
        ResultsPrinter.printInfo("Données: DBLP (Digital Bibliography & Library Project)");

        System.out.println();

        // Chargement initial du graphe DBLP
        runQuestion1();

        if (dblpGraph == null) {
            ResultsPrinter.printError("Impossible de charger le graphe DBLP!");
            ResultsPrinter.printError("Vérifiez que le fichier existe: " + DBLP_FILE_PATH);
            return;
        }

        // Affichage du menu interactif
        Scanner scanner = new Scanner(System.in);
        boolean continueRunning = true;

        while (continueRunning) {
            displayMenu();
            System.out.print("\nVotre choix: ");

            String choice = scanner.nextLine().trim();

            switch (choice) {
                case "1":
                    runQuestion1();
                    break;
                case "2":
                    runQuestion2();
                    break;
                case "3":
                    runQuestion3();
                    break;
                case "4":
                    runQuestion4();
                    break;
                case "5":
                    runQuestion5();
                    break;
                case "6":
                    runQuestion6();
                    break;
                case "7":
                    runQuestion7();
                    break;
                case "8":
                    runAllQuestions();
                    break;
                case "0":
                    continueRunning = false;
                    ResultsPrinter.printInfo("Au revoir!");
                    break;
                default:
                    ResultsPrinter.printWarning("Choix invalide! Essayez encore.");
            }

            if (continueRunning && !choice.equals("8")) {
                System.out.println("\nAppuyez sur Entrée pour continuer...");
                scanner.nextLine();
            }
        }

        scanner.close();
    }

    /**
     * Affiche le menu interactif principal.
     *
     * Ce menu permet à l'utilisateur de choisir quelle analyse exécuter
     * parmi les 7 questions du TP ou d'exécuter toutes les analyses en séquence.
     */
    private static void displayMenu() {
        System.out.println("\n" + "=".repeat(80));
        System.out.println("MENU PRINCIPAL");
        System.out.println("=".repeat(80));
        System.out.println("  1. Question 1  - Chargement des données");
        System.out.println("  2. Question 2  - Mesures de base");
        System.out.println("  3. Question 3  - Analyse de connexité");
        System.out.println("  4. Question 4  - Distribution des degrés");
        System.out.println("  5. Question 5  - Distance moyenne");
        System.out.println("  6. Question 6  - Comparaison avec générateurs");
        System.out.println("  7. Question 7  - Générateur par copie (BONUS)");
        System.out.println("  8. TOUT EXÉCUTER (Questions 1-7)");
        System.out.println("  0. Quitter");
        System.out.println("=".repeat(80));
    }

    /**
     * Question 1: Charge les données du réseau DBLP.
     *
     * Cette méthode charge le graphe de collaboration DBLP depuis le fichier
     * de données et affiche les informations de base sur le graphe chargé.
     */
    private static void runQuestion1() {
        ResultsPrinter.printHeader("QUESTION 1: Chargement des données");

        dblpGraph = GraphLoader.loadDBLP(DBLP_FILE_PATH);

        if (dblpGraph != null) {
            ResultsPrinter.printSuccess("Graphe DBLP chargé avec succès!");
            GraphLoader.displayGraphInfo(dblpGraph);

            ResultsPrinter.printInfo("\nNote: La visualisation n'est pas recommandée pour ce graphe");
            ResultsPrinter.printInfo("      (trop de nœuds: visualisation très lente et peu informative)");
        }
    }

    /**
     * Question 2: Calcule et affiche les mesures de base du réseau.
     *
     * Cette méthode calcule le nombre de nœuds, d'arêtes, le degré moyen
     * et le coefficient de clustering du réseau DBLP.
     */
    private static void runQuestion2() {
        if (dblpGraph == null) {
            ResultsPrinter.printError("Chargez d'abord le graphe (Question 1)!");
            return;
        }

        BasicMetrics.analyze(dblpGraph, "DBLP");
    }

    /**
     * Question 3: Analyse la connexité du réseau.
     *
     * Cette méthode vérifie si le réseau est connexe, compte le nombre de
     * composantes connexes et détermine le degré critique pour la connexité.
     */
    private static void runQuestion3() {
        if (dblpGraph == null) {
            ResultsPrinter.printError("Chargez d'abord le graphe (Question 1)!");
            return;
        }

        ConnectivityAnalyzer.analyze(dblpGraph);
    }

    /**
     * Question 4: Analyse la distribution des degrés du réseau.
     *
     * Cette méthode calcule la distribution des degrés, l'exporte pour
     * visualisation avec gnuplot et vérifie si elle suit une loi de puissance.
     */
    private static void runQuestion4() {
        if (dblpGraph == null) {
            ResultsPrinter.printError("Chargez d'abord le graphe (Question 1)!");
            return;
        }

        DegreeAnalyzer.analyze(dblpGraph, "DBLP", "dblp");

        ResultsPrinter.printInfo("\nPour générer les graphiques avec gnuplot:");
        ResultsPrinter.printInfo("  cd gnuplot");
        ResultsPrinter.printInfo("  gnuplot plot_dd_linear.gnu");
        ResultsPrinter.printInfo("  gnuplot plot_dd_loglog.gnu");
        ResultsPrinter.printInfo("  gnuplot plot_dd_powerlaw.gnu");
    }

    /**
     * Question 5: Calcule la distance moyenne du réseau.
     *
     * Cette méthode effectue un échantillonnage de 1000 nœuds et calcule
     * la distance moyenne par parcours BFS. Attention: opération longue (15-25 min).
     */
    private static void runQuestion5() {
        if (dblpGraph == null) {
            ResultsPrinter.printError("Chargez d'abord le graphe (Question 1)!");
            return;
        }

        ResultsPrinter.printWarning("ATTENTION: Cette analyse peut prendre 15-25 minutes!");
        ResultsPrinter.printInfo("(1000 parcours BFS sur un graphe de 317k nœuds)");

        System.out.print("\nContinuer? (o/n): ");
        Scanner scanner = new Scanner(System.in);
        String response = scanner.nextLine().trim().toLowerCase();

        if (response.equals("o") || response.equals("oui") || response.equals("y") || response.equals("yes")) {
            DistanceAnalyzer.analyze(dblpGraph, "DBLP", "dblp");

            ResultsPrinter.printInfo("\nPour générer le graphique avec gnuplot:");
            ResultsPrinter.printInfo("  cd gnuplot && gnuplot plot_distances.gnu");
        } else {
            ResultsPrinter.printInfo("Analyse annulée.");
        }
    }

    /**
     * Question 6: Compare le réseau DBLP avec des générateurs de réseaux.
     *
     * Cette méthode génère un réseau aléatoire (Erdős-Rényi) et un réseau
     * Barabási-Albert, puis compare leurs propriétés avec DBLP. Durée: 30-40 min.
     */
    private static void runQuestion6() {
        if (dblpGraph == null) {
            ResultsPrinter.printError("Chargez d'abord le graphe (Question 1)!");
            return;
        }

        ResultsPrinter.printWarning("ATTENTION: Cette analyse peut prendre 30-40 minutes!");
        ResultsPrinter.printInfo("(Génération et analyse de 2 grands réseaux)");

        System.out.print("\nContinuer? (o/n): ");
        Scanner scanner = new Scanner(System.in);
        String response = scanner.nextLine().trim().toLowerCase();

        if (response.equals("o") || response.equals("oui") || response.equals("y") || response.equals("yes")) {
            NetworkGenerator.analyze(dblpGraph);

            ResultsPrinter.printInfo("\nPour générer le graphique comparatif:");
            ResultsPrinter.printInfo("  cd gnuplot && gnuplot plot_comparison_networks.gnu");
        } else {
            ResultsPrinter.printInfo("Analyse annulée.");
        }
    }

    /**
     * Question 7 (BONUS): Teste le générateur par copie.
     *
     * Cette méthode génère un réseau avec le mécanisme de copie et compare
     * son clustering avec DBLP et Barabási-Albert. Durée: 15-20 min.
     */
    private static void runQuestion7() {
        if (dblpGraph == null) {
            ResultsPrinter.printError("Chargez d'abord le graphe (Question 1)!");
            return;
        }

        // Génération du graphe BA si nécessaire pour la comparaison
        if (baGraph == null) {
            ResultsPrinter.printInfo("Génération du graphe Barabási-Albert pour comparaison...");
            int n = Math.min(dblpGraph.getNodeCount(), 50000);
            double avgDegree = BasicMetrics.getAverageDegree(dblpGraph);
            int edgesPerNode = (int) Math.round(avgDegree / 2.0);
            baGraph = NetworkGenerator.generateBarabasiAlbert(n, Math.max(1, edgesPerNode));
        }

        ResultsPrinter.printWarning("ATTENTION: Cette analyse peut prendre 15-20 minutes!");

        System.out.print("\nContinuer? (o/n): ");
        Scanner scanner = new Scanner(System.in);
        String response = scanner.nextLine().trim().toLowerCase();

        if (response.equals("o") || response.equals("oui") || response.equals("y") || response.equals("yes")) {
            CopyGenerator.analyze(dblpGraph, baGraph);
        } else {
            ResultsPrinter.printInfo("Analyse annulée.");
        }
    }

    /**
     * Exécute toutes les questions en séquence.
     *
     * Cette méthode lance l'exécution automatique de toutes les analyses
     * (Questions 1 à 7) sans interruption. Durée totale: environ 1h30.
     */
    private static void runAllQuestions() {
        ResultsPrinter.printHeader("EXÉCUTION COMPLÈTE - TOUTES LES QUESTIONS");
        ResultsPrinter.printWarning("ATTENTION: L'exécution complète peut prendre 1h30 à 2h!");
        ResultsPrinter.printInfo("Les questions longues (Q5, Q6, Q7) seront exécutées automatiquement.");

        System.out.print("\nVoulez-vous vraiment tout exécuter? (o/n): ");
        Scanner scanner = new Scanner(System.in);
        String response = scanner.nextLine().trim().toLowerCase();

        if (!response.equals("o") && !response.equals("oui") && !response.equals("y") && !response.equals("yes")) {
            ResultsPrinter.printInfo("Exécution annulée.");
            return;
        }

        long globalStart = System.currentTimeMillis();

        // Question 1: Chargement
        if (dblpGraph == null) {
            runQuestion1();
        }

        // Question 2: Mesures de base
        if (dblpGraph != null) {
            runQuestion2();
        }

        // Question 3: Connexité
        if (dblpGraph != null) {
            runQuestion3();
        }

        // Question 4: Distribution des degrés
        if (dblpGraph != null) {
            runQuestion4();
        }

        // Question 5: Distance moyenne
        if (dblpGraph != null) {
            ResultsPrinter.printInfo("\n>>> Démarrage Question 5 (Distance moyenne)...");
            DistanceAnalyzer.analyze(dblpGraph, "DBLP", "dblp");
        }

        // Question 6: Comparaison avec générateurs
        if (dblpGraph != null) {
            ResultsPrinter.printInfo("\n>>> Démarrage Question 6 (Générateurs)...");
            NetworkGenerator.analyze(dblpGraph);
        }

        // Question 7: Générateur par copie (BONUS)
        if (dblpGraph != null) {
            ResultsPrinter.printInfo("\n>>> Démarrage Question 7 (Générateur copie - BONUS)...");
            // Génération du graphe BA si nécessaire
            if (baGraph == null) {
                int n = Math.min(dblpGraph.getNodeCount(), 50000);
                double avgDegree = BasicMetrics.getAverageDegree(dblpGraph);
                int edgesPerNode = (int) Math.round(avgDegree / 2.0);
                baGraph = NetworkGenerator.generateBarabasiAlbert(n, Math.max(1, edgesPerNode));
            }
            CopyGenerator.analyze(dblpGraph, baGraph);
        }

        ResultsPrinter.printHeader("TOUTES LES ANALYSES TERMINÉES!");
        ResultsPrinter.printElapsedTime(globalStart);

        ResultsPrinter.printInfo("\nPROCHAINES ÉTAPES:");
        ResultsPrinter.printInfo("  1. Générez les graphiques avec gnuplot (voir gnuplot/*.gnu)");
        ResultsPrinter.printInfo("  2. Consultez les fichiers de données dans output/data/");
        ResultsPrinter.printInfo("  3. Rédigez le rapport README.md avec les résultats et graphiques");
    }
}
