// File: ui/TrainingEditDialog.java
package ui;

import db.TrainingDAO;
import javafx.geometry.Insets;
import javafx.scene.control.*;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import model.PersonMapping;

import java.time.LocalDate;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Map;

/**
 * Modaler Bearbeitungsdialog für einen Trainings-Datensatz.
 * Rechteprüfung erfolgt VOR dem Öffnen im aufrufenden UI.
 */
public class TrainingEditDialog extends Dialog<Boolean> {

    private static final DateTimeFormatter TF = DateTimeFormatter.ofPattern("HH:mm");

    private final DatePicker dpDatum = new DatePicker();
    private final TimeSpinner spZeit = new TimeSpinner();
    private final TextField tfDauer = new TextField();
    private final ComboBox<String> cbModus = new ComboBox<>();
    private final TextField tfTeilnAnz = new TextField();
    private final ComboBox<String> cbTeilnTyp = new ComboBox<>();
    private final ComboBox<String> cbPerson = new ComboBox<>();
    private final ComboBox<String> tfAusgefallen = new ComboBox<>();
    private final TextField tfTitel = new TextField();
    private final ComboBox<String> cbInhalt = new ComboBox<>();
    private final ComboBox<String> cbVeranst = new ComboBox<>();
    private final TextArea taKommentar = new TextArea();
    private final TextField tfEvaluation = new TextField();

    public TrainingEditDialog(Map<String, Object> row,
                              List<String> modi,
                              List<String> teilnTypen,
                              List<String> veranstaltungstypen,
                              List<String> inhaltstypen,
                              List<String> personen) {
        setTitle("Datensatz bearbeiten");
        getDialogPane().getButtonTypes().addAll(ButtonType.OK, ButtonType.CANCEL);
        ButtonType deleteType = new ButtonType("Löschen", ButtonBar.ButtonData.LEFT);
        getDialogPane().getButtonTypes().add(deleteType);

        // Dropdown-Optionen
        cbModus.getItems().setAll(modi);
        cbTeilnTyp.getItems().setAll(teilnTypen);
        cbVeranst.getItems().setAll(veranstaltungstypen);
        cbInhalt.getItems().setAll(inhaltstypen);
        cbPerson.getItems().setAll(PersonMapping.getAllNames());
        
     // Standardwerte für "Ausgefallen Grund"
        tfAusgefallen.getItems().setAll(model.DataModels.getAusgefallenGruende());
        
        
        tfAusgefallen.setEditable(false); // kein Freitext
        tfAusgefallen.setPromptText("— bitte auswählen —");
        tfAusgefallen.setButtonCell(new ListCell<>() {
            @Override protected void updateItem(String item, boolean empty) {
                super.updateItem(item, empty);
                setText(empty || item == null || item.isBlank() ? "optional" : item);
            }
        });


        // nur Zahlen
        tfDauer.textProperty().addListener((o, ov, nv) -> {
            if (!nv.matches("\\d*")) tfDauer.setText(nv.replaceAll("[^\\d]", ""));
        });
        tfTeilnAnz.textProperty().addListener((o, ov, nv) -> {
            if (!nv.matches("\\d*")) tfTeilnAnz.setText(nv.replaceAll("[^\\d]", ""));
        });

        // Prefill
        dpDatum.setValue(parseDate(row.get("datum")));
        spZeit.getValueFactory().setValue(parseTime(row.get("startzeit")));
        tfDauer.setText(nz(row.get("dauer_minuten")));
        cbModus.setValue(nz(row.get("modus")));
        tfTeilnAnz.setText(nz(row.get("teilnehmende_anzahl")));
        cbTeilnTyp.setValue(nz(row.get("teilnehmende_typ")));
        cbPerson.setValue(PersonMapping.toName(nz(row.get("durchfuehrende_person"))));
        tfAusgefallen.setValue(nz(row.get("ausgefallen_grund")));
        tfTitel.setText(nz(row.get("titel")));
        cbInhalt.setValue(nz(row.get("inhaltstyp")));
        cbVeranst.setValue(nz(row.get("veranstaltungstyp")));
        taKommentar.setText(nz(row.get("kommentar")));
        taKommentar.setPrefRowCount(3);
        taKommentar.setWrapText(true);
        tfEvaluation.setText(nz(row.get("evaluation")));
        tfEvaluation.textProperty().addListener((o, ov, nv) -> {
            if (!nv.matches("\\d*(\\.\\d*)?")) tfEvaluation.setText(nv.replaceAll("[^\\d.]", ""));
        });


        // Layout
        GridPane g = new GridPane();
        g.setHgap(10);
        g.setVgap(8);
        g.setPadding(new Insets(12));

        int r = 0;
        g.add(new Label("Datum"), 0, r); g.add(dpDatum, 1, r++);
        g.add(new Label("Startzeit"), 0, r); g.add(spZeit, 1, r++);
        g.add(new Label("Dauer (Min)"), 0, r); g.add(tfDauer, 1, r++);
        g.add(new Label("Modus"), 0, r); g.add(cbModus, 1, r++);
        g.add(new Label("Teilnehmende Anzahl"), 0, r); g.add(tfTeilnAnz, 1, r++);
        g.add(new Label("Teilnehmende Typ"), 0, r); g.add(cbTeilnTyp, 1, r++);
        g.add(new Label("Durchführende Person"), 0, r); g.add(cbPerson, 1, r++);
        g.add(new Label("Ausgefallen Grund"), 0, r); g.add(tfAusgefallen, 1, r++);
        g.add(new Label("Titel"), 0, r); g.add(tfTitel, 1, r++);
        g.add(new Label("Inhaltstyp"), 0, r); g.add(cbInhalt, 1, r++);
        g.add(new Label("Veranstaltungstyp"), 0, r); g.add(cbVeranst, 1, r++);
     // --- Bewertung (1–6) mit optionaler Live-Evaluation ---
        g.add(new Label("Bewertung (1–6)"), 0, r);

        HBox evalBox = new HBox(10);
        evalBox.setPadding(new Insets(0));

        tfEvaluation.setPromptText("1–6");
        tfEvaluation.setEditable(true);
        tfEvaluation.setPrefWidth(80);

        Button liveEvalButton = new Button("Live-Evaluation starten");
        liveEvalButton.setStyle("-fx-font-size: 12;");

        LocalDate datum = parseDate(row.get("datum"));
        if (datum != null && datum.equals(LocalDate.now())) {
            // Nur anzeigen, wenn Schulung heute ist
            liveEvalButton.setVisible(true);
            liveEvalButton.setManaged(true);
        } else {
            liveEvalButton.setVisible(false);
            liveEvalButton.setManaged(false);
        }

        liveEvalButton.setOnAction(e -> {
            EvaluationPopupUI popup = new EvaluationPopupUI();
            double avg = popup.showAndWait();
            if (avg > 0) {
                tfEvaluation.setText(String.valueOf(avg));
            }
        });

        evalBox.getChildren().addAll(tfEvaluation, liveEvalButton);
        g.add(evalBox, 1, r++);

        g.add(new Label("Kommentar"), 0, r); g.add(taKommentar, 1, r++);

        getDialogPane().setContent(g);
        
     // --- Sichtbarkeit Bewertung nur für eigene oder Admin ---
        String login = System.getProperty("user.name");
        String loginKuerzel = PersonMapping.normalizeLogin(login);
        String personKuerzel = PersonMapping.normalizeLogin(nz(row.get("durchfuehrende_person")));
        boolean isOwn = loginKuerzel != null && loginKuerzel.equalsIgnoreCase(personKuerzel);

        if (!isOwn && !PersonMapping.isAdmin(login)) {
            // Completely remove both label and field from layout
            g.getChildren().removeIf(node -> GridPane.getColumnIndex(node) != null && GridPane.getColumnIndex(node) == 1 && node == tfEvaluation);
            g.getChildren().removeIf(node -> node instanceof Label && ((Label) node).getText().contains("Bewertung"));
        }

        
     // --- Delete-Handler ---
        final Button deleteBtn = (Button) getDialogPane().lookupButton(deleteType);
        deleteBtn.addEventFilter(javafx.event.ActionEvent.ACTION, ev -> {
            final int id = Integer.parseInt(String.valueOf(row.get("id")));
            Alert confirm = new Alert(Alert.AlertType.CONFIRMATION,
                    "Datensatz wirklich löschen?\n(ID: " + id + ")",
                    ButtonType.YES, ButtonType.NO);
            confirm.setHeaderText("Löschbestätigung");
            confirm.showAndWait().ifPresent(bt -> {
                if (bt == ButtonType.YES) {
                    try {
                    	new TrainingDAO().deleteTraining(id);
                    	// UI-Markierung: Zeile visuell „gelöscht“
                    	row.put("_deleted", Boolean.TRUE);
                    	setResult(Boolean.TRUE);
                    } catch (Exception ex) {
                        new Alert(Alert.AlertType.ERROR,
                                "Fehler beim Löschen: " + ex.getMessage()).showAndWait();
                    }
                }
                
            });
            ev.consume(); // Dialog offen lassen / Ergebnis bereits gesetzt
        });


        // OK-Handler (validieren + speichern)
        final Button okBtn = (Button) getDialogPane().lookupButton(ButtonType.OK);
        okBtn.addEventFilter(javafx.event.ActionEvent.ACTION, ev -> {
            if (!validateRequired()) {
                new Alert(Alert.AlertType.WARNING, "Pflichtfelder fehlen oder ungültig.").showAndWait();
                ev.consume();
                return;
            }
            
            Double evaluation = parseDoubleOrNull(tfEvaluation.getText());
            if (evaluation != null && (evaluation < 1.0 || evaluation > 6.0)) {
                new Alert(Alert.AlertType.WARNING, "Bewertung muss zwischen 1.0 und 6.0 liegen.").showAndWait();
                ev.consume();
                return;
            }

            
            try {
                final int id = Integer.parseInt(String.valueOf(row.get("id")));

                // ggf. Inhalt für Führung erzwingen
                String veranst = cbVeranst.getValue();
                String inhalt = cbInhalt.getValue();
                if ("fuehrung".equals(veranst)) {
                    inhalt = "bibliotheksnutzung";
                }              

                // bisherigen planned-Wert lesen
                int plannedOld = 0;
                Object pv = row.get("geplant");
                if (pv instanceof Number n) {
                    plannedOld = n.intValue();
                } else if (pv != null) {
                    try { plannedOld = Integer.parseInt(String.valueOf(pv)); } catch (Exception ignore) {}
                }

                // Teilnehmerzahl: jede eingetragene Zahl (auch "0") -> nicht mehr geplant
                String tnText = tfTeilnAnz.getText();
                boolean anyTnEntered = tnText != null && !tnText.trim().isEmpty();
                Integer tn = parseIntOrNull(tnText);
                int plannedNew = anyTnEntered ? 0 : plannedOld;
                String personKuerzelNew = PersonMapping.toKuerzel(cbPerson.getValue());


                new TrainingDAO().updateTraining(
                	    id,
                	    dpDatum.getValue(),
                	    spZeit.getValueFactory().getValue(),
                	    parseIntOrNull(tfDauer.getText()),
                	    cbModus.getValue(),
                	    tn,
                	    cbTeilnTyp.getValue(),
                	    personKuerzelNew,
                	    tfAusgefallen.getValue(),
                	    tfTitel.getText(),
                	    inhalt,
                	    veranst,
                	    taKommentar.getText(),
                	    plannedNew,
                	    evaluation
                	);

                	// update in-memory map for table
                	row.put("datum", dpDatum.getValue() != null ? dpDatum.getValue().toString() : null);
                	row.put("startzeit", spZeit.getValueFactory().getValue() != null
                	        ? spZeit.getValueFactory().getValue().format(TF)
                	        : null);
                	row.put("dauer_minuten", tfDauer.getText());
                	row.put("modus", cbModus.getValue());
                	row.put("teilnehmende_anzahl", tfTeilnAnz.getText());
                	row.put("teilnehmende_typ", cbTeilnTyp.getValue());
                	row.put("durchfuehrende_person", PersonMapping.toKuerzel(cbPerson.getValue()));
                	row.put("ausgefallen_grund", tfAusgefallen.getValue());
                	row.put("titel", tfTitel.getText());
                	row.put("inhaltstyp", cbInhalt.getValue());
                	row.put("veranstaltungstyp", cbVeranst.getValue());
                	row.put("kommentar", taKommentar.getText());
                	row.put("geplant", plannedNew);       
                	row.put("evaluation", tfEvaluation.getText());
                	setResult(Boolean.TRUE);

            } catch (Exception ex) {
                new Alert(Alert.AlertType.ERROR, "Fehler beim Speichern: " + ex.getMessage()).showAndWait();
                ev.consume();
            }
        });
       
        setResultConverter(dialogButton -> {
            if (dialogButton == ButtonType.OK) {
                return Boolean.TRUE;
            } else {
                return null;
            }
        });
    
    }

    // --- Helpers ---

    private boolean validateRequired() {
        if (dpDatum.getValue() == null) return false;
        if (cbModus.getValue() == null || cbModus.getValue().isBlank()) return false;
        if (cbTeilnTyp.getValue() == null || cbTeilnTyp.getValue().isBlank()) return false;
        if (cbVeranst.getValue() == null || cbVeranst.getValue().isBlank()) return false;
        if (cbInhalt.getValue() == null || cbInhalt.getValue().isBlank()) return false;
        // Startzeit muss HH:mm sein
        try {
            LocalTime.parse(spZeit.getEditor().getText(), TF);
        } catch (Exception e) {
            return false;
        }
        return true;
    }

    private static String nz(Object o) {
        return o == null ? "" : String.valueOf(o);
    }

    private static LocalDate parseDate(Object o) {
        try { return LocalDate.parse(String.valueOf(o)); } catch (Exception e) { return null; }
    }

    private static LocalTime parseTime(Object o) {
        try { return LocalTime.parse(String.valueOf(o), TF); } catch (Exception e) { return LocalTime.of(10, 0); }
    }

    private static Integer parseIntOrNull(String s) {
        if (s == null || s.isBlank()) return null;
        return Integer.parseInt(s);
    }
    
    private static Double parseDoubleOrNull(String s) {
        if (s == null || s.isBlank()) return null;
        try { return Double.parseDouble(s); } catch (Exception e) { return null; }
    }

    
}
