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

import db.TrainingDAO;
import db.TrainingTypeDAO;
import javafx.beans.value.ChangeListener;
import javafx.geometry.Insets;
import javafx.scene.control.*;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import model.PersonMapping;
import util.Config;

import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.List;

/**
 * Tab 1: Formular zur Erfassung einer neuen Schulung oder Führung.
 * Inhalt aus der bisherigen TrainingFormUI übernommen.
 */
public class TrainingFormUIEnterEvent extends BorderPane {

    private final ComboBox<String> veranstaltungstypBox = new ComboBox<>();
    private final ComboBox<String> inhaltstypBox = new ComboBox<>();
    private final TextField titelField = new TextField();
    private final DatePicker dateField = new DatePicker();
    private final TimeSpinner startzeitSpinner = new TimeSpinner();

    private final TextField dauerField = new TextField();
    private final ComboBox<String> modusBox = new ComboBox<>();
    private final TextField teilnehmerAnzahlField = new TextField();
    private final ComboBox<String> teilnehmerTypBox = new ComboBox<>();
    //private final TextField durchfuehrendePersonField = new TextField();
    private final ComboBox<String> durchfuehrendePersonBox = new ComboBox<>();
    private final ComboBox<String> ausgefallenBox = new ComboBox<>();
    private final TextArea kommentarField = new TextArea();

    private final TextField evaluationField = new TextField();
    
    private final Button speichernButton = new Button("Speichern");
    private final Button resetButton = new Button("Zurücksetzen");

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

    public TrainingFormUIEnterEvent() {
        setPadding(new Insets(15));

        Label heading = new Label("Neue Schulung anlegen");
        heading.setStyle("-fx-font-size: 18; -fx-font-weight: bold;");

        Label hint = new Label("Hinweis: Bereits geplante Veranstaltungen bitte im Tab 'Daten' bearbeiten.");
        hint.setStyle("-fx-font-size: 12; -fx-text-fill: #555555; -fx-font-style: italic;");

        VBox headingBox = new VBox(4, heading, hint);
        setTop(headingBox);

        GridPane grid = new GridPane();
        grid.setPadding(new Insets(15, 0, 0, 0));
        grid.setVgap(8);
        grid.setHgap(10);

        int row = 0;
        grid.add(new Label("Veranstaltungstyp:"), 0, row); grid.add(veranstaltungstypBox, 1, row++);
        grid.add(new Label("Inhaltstyp:"), 0, row); grid.add(inhaltstypBox, 1, row++);
        grid.add(new Label("Titel Veranstaltung:"), 0, row); grid.add(titelField, 1, row++);
        grid.add(new Label("Datum:"), 0, row); grid.add(dateField, 1, row++);
        grid.add(new Label("Startzeit:"), 0, row); grid.add(startzeitSpinner, 1, row++);
        grid.add(new Label("Dauer (Min):"), 0, row); grid.add(dauerField, 1, row++);
        grid.add(new Label("Modus:"), 0, row); grid.add(modusBox, 1, row++);
        grid.add(new Label("Teilnehmende:"), 0, row); grid.add(teilnehmerAnzahlField, 1, row++);
        grid.add(new Label("Ausgefallen (Grund):"), 0, row); grid.add(ausgefallenBox, 1, row++);
        grid.add(new Label("Typ Teilnehmende:"), 0, row); grid.add(teilnehmerTypBox, 1, row++);
        //grid.add(new Label("Durchführende Person:"), 0, row); grid.add(durchfuehrendePersonField, 1, row++);
        grid.add(new Label("Durchführende Person:"), 0, row);
        grid.add(durchfuehrendePersonBox, 1, row++);
     // --- Evaluation (direkte Eingabe ODER Live-Evaluation starten) ---
        grid.add(new Label("Bewertung (1–6):"), 0, row);

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

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

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

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

        evalBox.getChildren().addAll(evaluationField, liveEvalButton);
        grid.add(evalBox, 1, row++);

        grid.add(new Label("Kommentar:"), 0, row); grid.add(kommentarField, 1, row++);
        grid.add(new HBox(10, speichernButton, resetButton), 1, ++row);
        

        veranstaltungstypBox.getItems().setAll(model.DataModels.getVeranstaltungstypen());
        modusBox.getItems().setAll(model.DataModels.getModi());
        teilnehmerTypBox.getItems().setAll(model.DataModels.getTeilnehmendeTypen());
        ausgefallenBox.getItems().setAll(model.DataModels.getAusgefallenGruende());
     // Durchführende Personen: vordefinierte Namen + frei editierbar
        durchfuehrendePersonBox.getItems().setAll(PersonMapping.getAllNames());
        durchfuehrendePersonBox.setEditable(true);
     // --- Durchführende Person: Dropdown + Standardwert ---
        List<String> bekanntePersonen = new java.util.ArrayList<>(model.PersonMapping.getAllNames());
        durchfuehrendePersonBox.getItems().setAll(bekanntePersonen);
        durchfuehrendePersonBox.setEditable(true);
        durchfuehrendePersonBox.setPromptText("Name oder Kürzel eingeben");

        String currentUser = System.getProperty("user.name");
        String displayName = model.PersonMapping.toName(currentUser);
        durchfuehrendePersonBox.setValue(displayName);



        fillInhaltstypBoxFromDatabase();

        kommentarField.setPrefRowCount(3);
        kommentarField.setWrapText(true);

        teilnehmerAnzahlField.textProperty().addListener((obs, oldVal, newVal) -> {
            Integer parsed = parseIntSafe(newVal);
            int anzahl = parsed == null ? 0 : parsed;
            if (anzahl <= 0) {
                ausgefallenBox.setDisable(false);
            } else {
                ausgefallenBox.setValue("");
                ausgefallenBox.setDisable(true);
            }
            validateFields();
        });

        ausgefallenBox.valueProperty().addListener((obs, oldVal, newVal) -> {
            if (newVal != null && !newVal.isBlank()) {
                teilnehmerAnzahlField.setText("0");
                teilnehmerAnzahlField.setDisable(true);
            } else {
                teilnehmerAnzahlField.setDisable(false);
            }
            validateFields();
        });

        String username = System.getProperty("user.name");
        durchfuehrendePersonBox.getItems().setAll(model.PersonMapping.getAllNames());
        durchfuehrendePersonBox.setEditable(true);
        durchfuehrendePersonBox.setPromptText("Name oder Kürzel eingeben");
        durchfuehrendePersonBox.setValue(model.PersonMapping.toName(username));


        veranstaltungstypBox.setOnAction(e -> updateFieldsForVeranstaltungstyp());
        inhaltstypBox.setOnAction(e -> updateTitleFromInhaltstyp());

        applyIntegerFilter(dauerField);
        applyIntegerFilter(teilnehmerAnzahlField);
        applyDecimalFilter(evaluationField);


        ChangeListener<Object> validationListener = (obs, o, n) -> validateFields();
        veranstaltungstypBox.valueProperty().addListener(validationListener);
        inhaltstypBox.valueProperty().addListener(validationListener);
        titelField.textProperty().addListener(validationListener);
        dateField.valueProperty().addListener(validationListener);
        dauerField.textProperty().addListener(validationListener);
        modusBox.valueProperty().addListener(validationListener);
        teilnehmerAnzahlField.textProperty().addListener(validationListener);
        teilnehmerTypBox.valueProperty().addListener(validationListener);
        startzeitSpinner.valueProperty().addListener(validationListener);
        startzeitSpinner.getEditor().textProperty().addListener(validationListener);

        speichernButton.setOnAction(e -> saveTraining());
        speichernButton.setDisable(true);

        setCenter(new ScrollPane(grid));
    }

    private void fillInhaltstypBoxFromDatabase() {
        TrainingTypeDAO dao = new TrainingTypeDAO(Config.getDbPath());
        List<String> types = dao.getAllTrainingTypes();
        inhaltstypBox.getItems().setAll(types);
    }
    
    private static class TypeRule {
        final String forcedInhalt;
        final boolean inhaltLocked;

        final LocalDate forcedDate;
        final boolean dateLocked;

        final Integer forcedDauer;
        final boolean dauerLocked;

        final String forcedModus;
        final boolean modusLocked;

        final LocalTime forcedStart;
        final boolean startLocked;

        TypeRule(String forcedInhalt, boolean inhaltLocked,
                 LocalDate forcedDate, boolean dateLocked,
                 Integer forcedDauer, boolean dauerLocked,
                 String forcedModus, boolean modusLocked,
                 LocalTime forcedStart, boolean startLocked) {

            this.forcedInhalt = forcedInhalt;
            this.inhaltLocked = inhaltLocked;

            this.forcedDate = forcedDate;
            this.dateLocked = dateLocked;

            this.forcedDauer = forcedDauer;
            this.dauerLocked = dauerLocked;

            this.forcedModus = forcedModus;
            this.modusLocked = modusLocked;

            this.forcedStart = forcedStart;
            this.startLocked = startLocked;
        }
    }
    
    private static final java.util.Map<String, TypeRule> RULES = java.util.Map.of(
    	    "fuehrung",
    	        new TypeRule(
    	            "Bibliotheksnutzung", true,      // forcedInhalt + locked
    	            null, false,                     // date unchanged
    	            45, true,                        // Dauer
    	            "praesenz", true,                // Modus
    	            null, false                      // Startzeit unchanged
    	        ),

    	    "schulung",
    	        new TypeRule(
    	            null, false,                     // Inhalt unchanged
    	            null, false,                     // Date unchanged
    	            null, false,                     // Dauer unchanged
    	            null, false,                     // Modus unchanged
    	            null, false                      // Startzeit unchanged
    	        ),

    	    "coffeelecture",
    	        new TypeRule(
    	            null, false,                     // identical to schulung
    	            null, false,
    	            null, false,
    	            null, false,
    	            null, false
    	        ),

    	    "selbstlerneinheit",
    	        new TypeRule(
    	            null, false,                     // Inhalt permitted
    	            java.time.LocalDate.now(), true, // date forced to today + locked
    	            0, true,                         // Dauer = 0 + locked
    	            "online", true,                  // Modus = online + locked
    	            java.time.LocalTime.of(0, 0), true // Start = 00:00 + locked
    	        )
    	);
    
    private void applyTypeRule(String typ) {
        TypeRule r = RULES.get(typ);
        if (r == null) return;

        // Inhalt
        if (r.forcedInhalt != null) inhaltstypBox.setValue(r.forcedInhalt);
        inhaltstypBox.setDisable(r.inhaltLocked);

        // Date
        if (r.forcedDate != null) dateField.setValue(r.forcedDate);
        dateField.setDisable(r.dateLocked);

        // Dauer
        if (r.forcedDauer != null) dauerField.setText(String.valueOf(r.forcedDauer));
        dauerField.setDisable(r.dauerLocked);

        // Modus
        if (r.forcedModus != null) modusBox.setValue(r.forcedModus);
        modusBox.setDisable(r.modusLocked);

        // Startzeit
        if (r.forcedStart != null) startzeitSpinner.getValueFactory().setValue(r.forcedStart);
        startzeitSpinner.setDisable(r.startLocked);
    }




    private void updateFieldsForVeranstaltungstyp() {
        String typ = veranstaltungstypBox.getValue();
        if (typ == null) return;
        
        // FULL reset
        resetDefaultsForTypeChange();

        // Unlock EVERYTHING before applying rules (important!)
        inhaltstypBox.setDisable(false);
        dateField.setDisable(false);
        dauerField.setDisable(false);
        modusBox.setDisable(false);
        startzeitSpinner.setDisable(false);

        // Apply rule set
        applyTypeRule(typ);

        // Generate title based on NEW values
        titelField.setText(generateTitle(
            typ,
            inhaltstypBox.getValue()
        ));

        validateFields();
    }

    private String generateTitle(String typ, String inhalt) {
        if (typ == null) return "";

        // Führung: fixed title
        if (typ.equals("fuehrung")) {
            return "Bibliotheksführung";
        }

        // If no topic chosen yet → no title
        if (inhalt == null || inhalt.isBlank()) {
            return "";
        }

        switch (typ) {

            case "schulung":
                return "Schulung: " + inhalt;

            case "coffeelecture":
                return "Coffee Lecture: " + inhalt;

            case "selbstlerneinheit":
                return "Selbstlerneinheit: " + inhalt;

            default:
                return "";
        }
    }

    
    private void resetDefaultsForTypeChange() {
        // Reset ONLY the fields the user requested:
        inhaltstypBox.setValue(null);
        inhaltstypBox.setDisable(false);

        titelField.clear();

        modusBox.setValue(null);
        modusBox.setDisable(false);
    }

    private void updateTitleFromInhaltstyp() {
        String typ = veranstaltungstypBox.getValue();
        String inhalt = inhaltstypBox.getValue();

        titelField.setText(generateTitle(typ, inhalt));

        validateFields();
    }

    public void refreshTrainingTypes() {
        fillInhaltstypBoxFromDatabase();
    }

    private void saveTraining() {
        try {
            if (!validateFields()) return;

            String veranstaltungstyp = veranstaltungstypBox.getValue();
            String inhaltstyp = inhaltstypBox.getValue();
            String titel = titelField.getText();
            LocalDate datum = dateField.getValue();

            LocalTime startzeit;
            try {
                startzeit = LocalTime.parse(startzeitSpinner.getEditor().getText(), TIME_FORMAT);
            } catch (DateTimeParseException e) {
                markField(startzeitSpinner.getEditor(), false);
                validateFields();
                return;
            }

            Integer dauer = parseIntSafe(dauerField.getText());
            String modus = modusBox.getValue();
            Integer teilnehmende = parseIntSafe(teilnehmerAnzahlField.getText());
            String teilnehmendeTyp = teilnehmerTypBox.getValue();
            String personInput = durchfuehrendePersonBox.getEditor().getText();
            if (personInput == null || personInput.isBlank())
                personInput = durchfuehrendePersonBox.getValue();
            String person = PersonMapping.toKuerzel(personInput);
            String grund = ausgefallenBox.getValue();
            String kommentar = kommentarField.getText();

            String datumStr = datum.format(DateTimeFormatter.ISO_LOCAL_DATE);
            String startzeitStr = startzeit.format(TIME_FORMAT);
            
            Double evaluation = parseDoubleSafe(evaluationField.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();
                return;
            }


            TrainingDAO dao = new TrainingDAO();
            dao.insertTraining(
                    datumStr,
                    startzeitStr,
                    dauer,
                    modus,
                    teilnehmende,
                    teilnehmendeTyp,
                    person,
                    grund,
                    titel,
                    inhaltstyp,
                    veranstaltungstyp,
                    kommentar,
                    0,
                    evaluation
            );

            new Alert(Alert.AlertType.INFORMATION, "Datensatz erfolgreich gespeichert.").showAndWait();
            resetForm();

        } catch (Exception ex) {
            new Alert(Alert.AlertType.ERROR, "Fehler beim Speichern: " + ex.getMessage()).showAndWait();
            ex.printStackTrace();
        }
    }

    // Hilfsmethoden ------------------------------------------------------------------

    private void applyIntegerFilter(TextField field) {
        field.textProperty().addListener((obs, old, neu) -> {
            if (!neu.matches("\\d*")) field.setText(neu.replaceAll("[^\\d]", ""));
        });
    }
    
    private void applyDecimalFilter(TextField field) {
        field.textProperty().addListener((obs, old, neu) -> {
            if (!neu.matches("\\d*(\\.\\d*)?")) field.setText(neu.replaceAll("[^\\d.]", ""));
        });
    }


    private Integer parseIntSafe(String text) {
        if (text == null || text.isBlank()) return null;
        try {
            return Integer.parseInt(text.trim());
        } catch (NumberFormatException e) {
            return null;
        }
    }
    
    private Double parseDoubleSafe(String text) {
        if (text == null || text.isBlank()) return null;
        try {
            return Double.parseDouble(text.trim());
        } catch (NumberFormatException e) {
            return null;
        }
    }


    
    private boolean validateFields() {
        boolean valid = true;

        valid &= markField(veranstaltungstypBox, veranstaltungstypBox.getValue() != null);
        valid &= markField(inhaltstypBox, inhaltstypBox.getValue() != null && !inhaltstypBox.getValue().isBlank());
        valid &= markField(titelField, !titelField.getText().isBlank());
        valid &= markField(dateField, dateField.getValue() != null);
        valid &= markField(dauerField, !dauerField.getText().isBlank());
        valid &= markField(modusBox, modusBox.getValue() != null);
        valid &= markField(teilnehmerAnzahlField, !teilnehmerAnzahlField.getText().isBlank());
        valid &= markField(teilnehmerTypBox, teilnehmerTypBox.getValue() != null);

        String timeText = startzeitSpinner.getEditor().getText();
        boolean validTime = false;
        if (timeText != null && !timeText.isBlank()) {
            try {
                LocalTime.parse(timeText, TIME_FORMAT);
                validTime = true;
            } catch (DateTimeParseException e) {
                validTime = false;
            }
        }
        valid &= markField(startzeitSpinner.getEditor(), validTime);

        speichernButton.setDisable(!valid);
        return valid;
    }

    private boolean markField(Control field, boolean ok) {
        if (ok) {
            field.setStyle("");
        } else {
            field.setStyle("-fx-border-color: red; -fx-border-width: 2;");
        }
        return ok;
    }

    private void resetForm() {
        veranstaltungstypBox.setValue(null);
        inhaltstypBox.setDisable(false);
        inhaltstypBox.setValue(null);
        titelField.clear();
        dateField.setValue(null);
        startzeitSpinner.getValueFactory().setValue(LocalTime.of(10, 0));
        dauerField.clear();
        modusBox.setValue(null);
        teilnehmerAnzahlField.clear();
        teilnehmerTypBox.setValue(null);
        ausgefallenBox.setValue("");
        kommentarField.clear();
        validateFields();
    }
}
