package ui;

import db.TrainingDAO;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.chart.*;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.stage.Stage;
import model.PersonMapping;

import java.util.*;
import java.util.stream.Collectors;

/**
 * Zeigt Bewertungen pro Schulungstyp:
 * - normale Nutzer: nur eigene
 * - Admins: Tabs pro Person
 * Mit Refresh-Button.
 */
public class EvaluationUI extends BorderPane {

    private final TabPane tabs = new TabPane();
    private final Button btnRefresh = new Button("Aktualisieren");

    public EvaluationUI() {
        // outer layout
        VBox content = new VBox(10);
        content.setPadding(new Insets(15));

        Label heading = new Label("Meine Evaluationen nach Schulungstyp");
        heading.setStyle("-fx-font-size: 18; -fx-font-weight: bold;");

        // --- Refresh button ---
        btnRefresh.setOnAction(e -> {
            content.getChildren().remove(tabs); // clear old
            loadEvaluations();                  // reload data
            content.getChildren().add(tabs);    // re-add updated tabs
        });

        // --- Online Evaluation button ---
        Button btnOnlineEval = new Button("Online-Evaluation starten");
        btnOnlineEval.setStyle("-fx-background-color: #324B8C; -fx-text-fill: white; -fx-font-weight: bold;");
        btnOnlineEval.setOnAction(e -> {
            try {
                java.awt.Desktop.getDesktop().browse(new java.net.URI("https://mrbs.ph-freiburg.de/evaluation.php"));
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        });

        HBox header = new HBox(15, heading, btnRefresh, btnOnlineEval);
        header.setAlignment(Pos.CENTER_LEFT);
        header.setPadding(new Insets(0, 0, 10, 0));


        // add heading and tabs container
        content.getChildren().addAll(header, tabs);

        // put everything into scroll pane
        ScrollPane scroll = new ScrollPane(content);
        scroll.setFitToWidth(true);
        scroll.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER);
        scroll.setVbarPolicy(ScrollPane.ScrollBarPolicy.AS_NEEDED);

        setCenter(scroll);

        // finally load data
        loadEvaluations();
    }



    private void loadEvaluations() {
        tabs.getTabs().clear();

        String login = System.getProperty("user.name");
        boolean isAdmin = PersonMapping.isAdmin(login);

        TrainingDAO dao = new TrainingDAO();
        List<Map<String, Object>> all = dao.getAllTrainings();

        // --- Gruppieren nach Person (damit Admin Tabs bekommt) ---
        Map<String, List<Map<String, Object>>> byPerson = all.stream()
                .filter(r -> r.get("durchfuehrende_person") != null)
                .collect(Collectors.groupingBy(r -> r.get("durchfuehrende_person").toString()));

        if (!isAdmin) {
            // nur eigener Datensatz
            String loginNorm = PersonMapping.normalizeLogin(login);
            List<Map<String, Object>> mine = byPerson.entrySet().stream()
                    .filter(e -> loginNorm.equalsIgnoreCase(PersonMapping.normalizeLogin(e.getKey())))
                    .flatMap(e -> e.getValue().stream())
                    .toList();

            Tab ownTab = new Tab(PersonMapping.toName(loginNorm));
            ownTab.setClosable(false);
            ownTab.setContent(createEvaluationContent(mine));
            tabs.getTabs().add(ownTab);
        } else {
            // Admin: Tab pro Person mit Daten
            for (Map.Entry<String, List<Map<String, Object>>> entry : byPerson.entrySet()) {
                String kuerzel = entry.getKey();
                List<Map<String, Object>> rows = entry.getValue();
                String name = PersonMapping.toName(kuerzel);
                Tab t = new Tab(name != null && !name.isBlank() ? name : kuerzel);
                t.setClosable(false);
                t.setContent(createEvaluationContent(rows));
                tabs.getTabs().add(t);
            }

            if (!tabs.getTabs().isEmpty()) {
                tabs.getSelectionModel().select(0);
            }
        }
    }

    // --- Einzelansicht pro Person ---
    private VBox createEvaluationContent(List<Map<String, Object>> rows) {
        VBox box = new VBox(10);
        box.setPadding(new Insets(10));

        if (rows == null || rows.isEmpty()) {
            Label none = new Label("Keine Schulungen vorhanden.");
            none.setStyle("-fx-text-fill: gray; -fx-font-style: italic;");
            box.getChildren().add(none);
            return box;
        }

        Map<String, List<Double>> evalByType = new TreeMap<>();
        Set<String> typesWithNoEval = new TreeSet<>();

        for (Map<String, Object> row : rows) {
            String type = Objects.toString(row.get("inhaltstyp"), "—");
            Object e = row.get("evaluation");
            if (e != null) {
                try {
                	double val = Double.parseDouble(String.valueOf(e));
                	if (val >= 1.0 && val <= 6.0)
                	    evalByType.computeIfAbsent(type, k -> new ArrayList<>()).add(val);

                } catch (NumberFormatException ignore) {}
            } else {
                typesWithNoEval.add(type);
            }
        }

        Set<String> allTypes = new TreeSet<>();
        allTypes.addAll(evalByType.keySet());
        allTypes.addAll(typesWithNoEval);

        for (String type : allTypes) {
        	List<Double> vals = evalByType.get(type);
            Label title = new Label(type);
            title.setStyle("-fx-font-size: 14; -fx-font-weight: bold;");

            if (vals == null || vals.isEmpty()) {
                Label none = new Label("Keine Bewertungen");
                none.setStyle("-fx-text-fill: gray;");
                box.getChildren().addAll(title, none);
                continue;
            }

            double avg = vals.stream().mapToDouble(Double::doubleValue).average().orElse(0);
            Label summary = new Label(String.format(Locale.US,
                    "Ø %.2f (%d Bewertung%s)", avg, vals.size(), vals.size() == 1 ? "" : "en"));
            summary.setStyle("-fx-font-size: 12;");

            box.getChildren().addAll(title, summary);

            if (vals.size() >= 2) {
                // filter only the rows that belong to this training type
                List<Map<String, Object>> rowsForType = rows.stream()
                        .filter(r -> type.equals(Objects.toString(r.get("inhaltstyp"), "")))
                        .collect(Collectors.toList());

                LineChart<Number, Number> chart = createTinyChart(rowsForType);

                Label today = new Label("→ heute");
                
                today.setStyle("-fx-font-size: 10; -fx-text-fill: #666;");
                today.setPadding(new Insets(-5, 0, 5, 0));
                today.setMaxWidth(Double.MAX_VALUE);

                HBox h = new HBox(today);
                h.setAlignment(Pos.CENTER_RIGHT);
                
                box.getChildren().addAll(chart, h);

            }


        }

        return box;
    }

    private LineChart<Number, Number> createTinyChart(List<Map<String, Object>> rows) {
        // Nur valide Bewertungen behalten (1..6) – Liste bleibt 1:1 zu vals ausgerichtet
    	// --- Sort chronologically: oldest → newest ---
    	List<Map<String, Object>> evalRows = rows.stream()
    	    .filter(r -> {
    	        Object e = r.get("evaluation");
    	        try {
    	            double v = (e == null) ? -1 : Double.parseDouble(e.toString());
    	            return v >= 1.0 && v <= 6.0;
    	        } catch (Exception ex) {
    	            return false;
    	        }
    	    })
    	    .sorted(Comparator.comparing(r -> Objects.toString(r.get("datum"), ""))) // sort by date ascending
    	    .toList();

    	List<Double> vals = evalRows.stream()
    	    .map(r -> Double.parseDouble(r.get("evaluation").toString()))
    	    .toList();



        NumberAxis xAxis = new NumberAxis(1, Math.max(1, vals.size()), 1);
        xAxis.setTickLabelsVisible(false);
        xAxis.setTickMarkVisible(false);
        xAxis.setMinorTickVisible(false);
        xAxis.setOpacity(0);
        xAxis.setVisible(false);

        // 1 oben (gut) → 6 unten (schlecht), ohne gespiegelten Text
        NumberAxis yAxis = new NumberAxis(6, 1, -1);
        yAxis.setAutoRanging(false);
        yAxis.setTickLabelsVisible(true);
        yAxis.setTickLabelFill(javafx.scene.paint.Color.GRAY);
        yAxis.setMinorTickVisible(false);
        yAxis.setTickMarkVisible(true);
        yAxis.setLabel(null);

        LineChart<Number, Number> chart = new LineChart<>(xAxis, yAxis);
        chart.setCreateSymbols(true);    // wir setzen eigene Symbole, aber das kann an bleiben
        chart.setLegendVisible(false);
        chart.setHorizontalGridLinesVisible(true);
        chart.setVerticalGridLinesVisible(false);
        chart.setAlternativeColumnFillVisible(false);
        chart.setAlternativeRowFillVisible(false);
        chart.setAnimated(false);
        chart.setPrefHeight(100);
        chart.setMinHeight(80);
        chart.setMaxHeight(120);
        chart.setStyle("-fx-background-color: transparent; -fx-border-color: #ccc;");

        // --- Rohwerte (mit eigenen Symbol-Nodes + Tooltip) ---
        XYChart.Series<Number, Number> seriesRaw = new XYChart.Series<>();
        for (int i = 0; i < vals.size(); i++) {
            double y = vals.get(i);
            XYChart.Data<Number, Number> data = new XYChart.Data<>(i + 1, y);

            StackPane symbol = new StackPane();
            symbol.getStyleClass().add("chart-line-symbol");
            symbol.setPrefSize(8, 8);
            symbol.setMouseTransparent(false);

            Map<String, Object> row = evalRows.get(i);
            String title = Objects.toString(row.get("titel"), "—");
            String date  = Objects.toString(row.get("datum"), "—");
            String inhalt = Objects.toString(row.get("inhaltstyp"), "—");
            String modus  = Objects.toString(row.get("modus"), "—");
            String eval   = String.format(Locale.US, "%.2f", y);

            Tooltip.install(symbol, new Tooltip(title + "\n" + date + "\nBewertung: " + eval));

            // --- On click: show small popup window with details ---
            symbol.setOnMouseClicked(evt -> {
                Stage popup = new Stage();
                popup.initModality(javafx.stage.Modality.APPLICATION_MODAL);
                popup.setTitle("Details zur Schulung");

                VBox box = new VBox(8);
                box.setPadding(new Insets(15));
                box.getChildren().addAll(
                    new Label("Titel: " + title),
                    new Label("Datum: " + date),
                    new Label("Inhaltstyp: " + inhalt),
                    new Label("Modus: " + modus),
                    new Label("Bewertung: " + eval)
                );

                Scene scene = new Scene(box);
                popup.setScene(scene);
                popup.setWidth(300);
                popup.setHeight(200);
                popup.showAndWait();
            });

            data.setNode(symbol);
            seriesRaw.getData().add(data);
        }


        // --- Laufender Durchschnitt (ohne Symbole) ---
        XYChart.Series<Number, Number> seriesAvg = new XYChart.Series<>();
        double sum = 0;
        for (int i = 0; i < vals.size(); i++) {
            sum += vals.get(i);
            double avg = sum / (i + 1);
            XYChart.Data<Number, Number> d = new XYChart.Data<>(i + 1, avg);
            d.setNode(null);
            seriesAvg.getData().add(d);
        }

     // --- Global average line (horizontal across entire chart) ---
        double globalAvg = vals.stream().mapToDouble(Double::doubleValue).average().orElse(0);

        XYChart.Series<Number, Number> seriesGlobal = new XYChart.Series<>();
        seriesGlobal.getData().add(new XYChart.Data<>(1, globalAvg));
        seriesGlobal.getData().add(new XYChart.Data<>(vals.size(), globalAvg));

        
        chart.getData().addAll(seriesRaw, seriesAvg, seriesGlobal);      
        
     // Style: blue (raw), orange (running avg), gray dashed (global avg)
        var rawLine = chart.lookup(".chart-series-line.series0");
        if (rawLine != null)
            rawLine.setStyle("-fx-stroke: #2a7fff; -fx-stroke-width: 2px;");

        var avgLine = chart.lookup(".chart-series-line.series1");
        if (avgLine != null)
            avgLine.setStyle("-fx-stroke: #ff7f27; -fx-stroke-width: 1.5px; -fx-stroke-dash-array: 4 4;");

        var globalLine = chart.lookup(".chart-series-line.series2");
        if (globalLine != null)
            globalLine.setStyle("-fx-stroke: #999999; -fx-stroke-width: 1.2px; -fx-stroke-dash-array: 8 6;");

       
        
        return chart;
    }






}
