package org.example;

import org.apache.commons.math3.analysis.function.Log;
import org.example.entity.BellmanFordResult;
import org.example.entity.PathResult;
import org.graphstream.algorithm.BellmanFord;
import org.graphstream.graph.Graph;
import org.graphstream.graph.Node;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.atomic.AtomicBoolean;

import static org.example.Graph.*;
import java.util.concurrent.*;
public class MainTest {

    public static void main(String[] args) {

        System.setProperty("org.graphstream.ui", "swing");
        System.out.println("Exemple prec havre");
        System.out.println("==============================");
        Graph graph = getTheFileFromPath("./static/graphe_lehavre.dgs");
        graph.edges().forEach(edge -> {
            double cost = getCostOfTheArete(edge); // ta méthode qui renvoie le coût
            edge.setAttribute("weight", cost);
        });
        System.out.println(graph.getNodeCount());
        System.out.println(graph.getEdgeCount());
        Node startNode = graph.getNode("33317746");
        Node endNode = graph.getNode("144477138");
        BellmanComparator(graph,startNode,endNode);

        List<List<Double>> resultHavre = new ArrayList<>(Collections.emptyList());
        for (int i = 0; i < 10; i++) {
            graph.edges().forEach(edge -> {
                double cost = getCostOfTheArete(edge);
                edge.setAttribute("weight", cost);
            });
            resultHavre.add(BellmanComparator(graph,getRandomNode(graph),getRandomNode(graph)));

        }
        String filename = String.format("DataResultatGraphHavre.dat");
        saveHistogram(filename, resultHavre);


        File[] dgsFiles = new File("./static/").listFiles((dir, name) -> name.endsWith(".dgs"));
        assert dgsFiles != null;
        for (File file : dgsFiles){
            System.out.println(file.getName());
            System.out.println("==============================");
            List<List<Double>> result = new ArrayList<>(Collections.emptyList());
            for (int i = 0; i < 5; i++) {


                Graph graphFile = getTheFileFromPath(file.getPath());
                graphFile.edges().forEach(edge -> {
                    double cost = getCostOfTheArete(edge);
                    edge.setAttribute("weight", cost);
                });
                result.add(BellmanComparator(graphFile,getRandomNode(graphFile),getRandomNode(graphFile)));

            }
            filename = String.format("DataResultatGraph"+file.getName()+".dat");
            saveHistogram(filename, result);
        }


    }

    public static void saveHistogram(String filename, List<List<Double>> histogram) {
        try (FileWriter writer = new FileWriter(filename)) {
            for (List<Double> durations : histogram) {
                // On écrit GraphStreamDuration puis MineDuration séparés par un espace
                writer.write(durations.get(0) + " " + durations.get(1) + "\n");
            }
            System.out.println("Histogramme enregistré dans " + filename);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static Node getRandomNode(Graph graph){
        return graph.getNode(ThreadLocalRandom.current().nextInt(0, graph.getNodeCount()));


    }

    public static ArrayList<Double> BellmanComparator(Graph graph, Node startNode, Node endNode) {
        ArrayList<Double> results = new ArrayList<>();

        if (graph != null) {
            ExecutorService executor = Executors.newSingleThreadExecutor();
            try {

                Future<Double> futureGS = executor.submit(() -> {
                    long startGS = System.nanoTime();
                    BellmanFord bf = new BellmanFord();
                    bf.init(graph);
                    bf.setSource(startNode.getId());
                    bf.compute();
                    long endGS = System.nanoTime();
                    double cost = bf.getShortestPathValue(endNode);
                    System.out.println("GraphStream Bellman-Ford = " + (endGS - startGS) / 1_000_000.0 + " ms");
                    results.add((double) (endGS - startGS));
                    return cost;
                });

                try {
                    futureGS.get(90, TimeUnit.SECONDS);
                } catch (TimeoutException e) {
                    System.out.println("⚠ GraphStream Bellman-Ford > 1min30 : résultat fixé à 1min30");
                    results.add(90.0 * 1_000);
                }

                Future<Float> futureMine = executor.submit(() -> {
                    long startMine = System.nanoTime();
                    BellmanFordResult result = BellmanFord(graph, startNode);
                    PathResult pathResult = getPath(result, endNode);
                    long endMine = System.nanoTime();
                    System.out.println("Mon Bellman-Ford = " + (endMine - startMine) / 1_000_000.0 + " ms");
                    results.add((double) (endMine - startMine));
                    return pathResult.cost();
                });

                try {
                    futureMine.get(90, TimeUnit.SECONDS);
                } catch (TimeoutException e) {
                    System.out.println("⚠ Mon Bellman-Ford > 1min30 : résultat fixé à 1min30");
                    results.add(90.0 * 1_000);
                }

            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        return results;
    }

}
