package at.vvo.omds.client.gui;

import at.vvo.omds.helpers.GuiProdukt;
import at.vvo.omds.types.omds3.r2025_05.common.*;
import javafx.animation.PauseTransition;
import javafx.geometry.Insets;
import javafx.scene.Node;
import javafx.scene.control.*;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Paint;
import javafx.scene.text.Font;
import javafx.scene.text.FontWeight;
import javafx.scene.text.Text;
import javafx.util.Duration;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.*;

public class ItemAttribute {
    Map<TreeItem<GuiProdukt>, Map<AttributType, String>> infoBoxFromItem = new HashMap<>();
    List<VersichertesInteresseMitAttributMetadatenType> risikoobjekte = new ArrayList<>();

    public List<VersichertesInteresseMitAttributMetadatenType> getRisikoobjekte() {
        return risikoobjekte;
    }

    public void setRisikoobjekte(List<VersichertesInteresseMitAttributMetadatenType> risikoobjekte) {
        this.risikoobjekte = risikoobjekte;
    }

    public Map<TreeItem<GuiProdukt>, Map<AttributType, String>> getInfoBoxFromItem() {
        return infoBoxFromItem;
    }
    public void setInfoBoxFromItem(Map<TreeItem<GuiProdukt>, Map<AttributType, String>> infoBoxFromItem) {
        this.infoBoxFromItem = infoBoxFromItem;
    }

    public VBox addItemInfo(TreeItem<GuiProdukt> newSelection, VBox attributBox) {
        for(int j = 0; j < ((ProduktbausteinType)newSelection.getValue().getProdukt()).getAttribute().size(); j++) {
            VBox singleAttributBox = new VBox();
            singleAttributBox.setPadding(new Insets(10));

            Label label = new Label(
                    ((ProduktbausteinType)newSelection.getValue().getProdukt()).getAttribute().get(j).getBezeichnung() + ": ");
            label.setId("label");
            TextField textField = new TextField();

            CheckBox checkBox = new CheckBox();

            AttributStringType stringAttribut;
            AttributBooleanType attributBoolean;
            AttributDezimalType attributDezimal;
            AttributIntType attributInt;

            if (((ProduktbausteinType)newSelection.getValue().getProdukt()).getAttribute().get(j).getClass()
                    .equals(AttributBooleanType.class)) {
                attributDezimal = null;
                attributInt = null;
                stringAttribut = null;

                attributBoolean = (AttributBooleanType) (
                        (ProduktbausteinType)newSelection.getValue().getProdukt()).getAttribute().get(j);

                if (infoBoxFromItem.get(newSelection) != null && infoBoxFromItem.get(newSelection).get(attributBoolean)
                        != null && !infoBoxFromItem.get(newSelection).get(attributBoolean).isEmpty()){
                    if (infoBoxFromItem.get(newSelection).get(attributBoolean).equals("false")){
                        checkBox.setSelected(false);
                    }else if(infoBoxFromItem.get(newSelection).get(attributBoolean).equals("true")){
                        checkBox.setSelected(true);
                    }
                }
            } else if (((ProduktbausteinType)newSelection.getValue().getProdukt()).getAttribute().get(j).getClass()
                    .equals(AttributStringType.class)) {
                attributDezimal = null;
                attributBoolean = null;
                attributInt = null;

                stringAttribut = (AttributStringType) ((ProduktbausteinType)newSelection.getValue().getProdukt()).getAttribute().get(j);

                if (stringAttribut.isPflichtfeld()) {
                    label.setText(label.getText().substring(0, label.getText().length()-2) + "*: ");
                }
                if (stringAttribut.isAenderbar() != null && !stringAttribut.isAenderbar()) {
                    textField.setEditable(false);
                }
                if (infoBoxFromItem.get(newSelection) != null
                        && infoBoxFromItem.get(newSelection).get(stringAttribut) != null
                        && !infoBoxFromItem.get(newSelection).get(stringAttribut).isEmpty()){
                    textField.setText(infoBoxFromItem.get(newSelection).get(stringAttribut));
                } else if (stringAttribut.getValue() != null && !stringAttribut.getValue().equals("null")) {
                    textField.setText(stringAttribut.getValue());
                } else if (stringAttribut.getDefault() != null) {
                    textField.setText(stringAttribut.getDefault());
                }
                textField.setPromptText("Text eingeben");

            } else if (((ProduktbausteinType)newSelection.getValue().getProdukt()).getAttribute().get(j).getClass()
                    .equals(AttributDezimalType.class)) {
                attributBoolean = null;
                attributInt = null;
                stringAttribut = null;

                attributDezimal = (AttributDezimalType) ((ProduktbausteinType)newSelection.getValue().getProdukt()).getAttribute().get(j);

                if (attributDezimal.isPflichtfeld()) {
                    label.setText(label.getText().substring(0, label.getText().length()-2) + "*: ");
                }
                if (attributDezimal.isAenderbar() != null && !attributDezimal.isAenderbar()) {
                    textField.setEditable(false);
                }
                if (infoBoxFromItem.get(newSelection) != null
                        && infoBoxFromItem.get(newSelection).get(attributDezimal) != null
                        && !infoBoxFromItem.get(newSelection).get(attributDezimal).isEmpty()){
                    textField.setText(infoBoxFromItem.get(newSelection).get(attributDezimal));
                } else if (attributDezimal.getValue() != null && !(attributDezimal.getValue().toString().equals("-1"))) {
                    textField.setText(attributDezimal.getValue().toString());
                } else if (attributDezimal.getDefault() != null) {
                    textField.setText(attributDezimal.getDefault().toString());
                }
                textField.setPromptText("Dezimalzahl eingeben");
            } else {
                attributDezimal = null;
                attributBoolean = null;
                stringAttribut = null;

                attributInt = (AttributIntType) ((ProduktbausteinType)newSelection.getValue().getProdukt()).getAttribute().get(j);

                if (attributInt.isPflichtfeld()) {
                    label.setText(label.getText().substring(0, label.getText().length()-2) + "*: ");
                }
                if (attributInt.isAenderbar() != null && !attributInt.isAenderbar()) {
                    textField.setEditable(false);
                }
                if (infoBoxFromItem.get(newSelection) != null
                        && infoBoxFromItem.get(newSelection).get(attributInt) != null
                        && !infoBoxFromItem.get(newSelection).get(attributInt).isEmpty()){
                    textField.setText(infoBoxFromItem.get(newSelection).get(attributInt));
                } else if (attributInt.getValue() != null && !attributInt.getValue().equals(-1)) {
                    textField.setText(attributInt.getValue().toString());
                } else if (attributInt.getDefault() != null) {
                    textField.setText(attributInt.getDefault().toString());
                }
                textField.setPromptText("Ganzzahl eingeben");
            }

            if (attributBoolean != null && attributBoolean.isValue() != null) {
                checkBox.setSelected(attributBoolean.isValue());
            }else if(attributBoolean != null && attributBoolean.isDefault() != null) {
                checkBox.setSelected(attributBoolean.isDefault());
            }

            if (attributBoolean != null && attributBoolean.isAenderbar() != null && !attributBoolean.isAenderbar()) {
                checkBox.setDisable(true);
            }
            if (attributBoolean != null && attributBoolean.isPflichtfeld()) {
                label.setText(label.getText().substring(0, label.getText().length()-2) + "*: ");
            }

            int finalJ = j;
            checkBox.selectedProperty().addListener((obsVal, oldVal, newVal) -> {
                if (attributBoolean != null) {
                    infoBoxFromItem.computeIfAbsent(newSelection,
                            k -> new HashMap<>()).put(attributBoolean, checkBox.isSelected() ? "true" : "false");
                    attributBoolean.setValue(checkBox.isSelected());
                    ((ProduktbausteinType)newSelection.getValue().getProdukt()).getAttribute().set(finalJ, attributBoolean);
                }
            });
            textField.focusedProperty().addListener((observableValue, oldVal, newVal) -> {
                if (!newVal) {
                    PauseTransition pause = new PauseTransition(Duration.seconds(3));
                    pause.setOnFinished(ep -> {
                        textField.setStyle("-fx-border-color: #bfbfbf");
                    });
                    if (attributDezimal != null){
                        infoBoxFromItem.computeIfAbsent(newSelection,
                                k -> new HashMap<>()).put(attributDezimal, textField.getText());

                        String eingabe = textField.getText().replace(",",".");
                        if (textField.getText().isEmpty()){
                            if (attributDezimal.isPflichtfeld()){

                                Label failedCheck = new Label("Es muss ein Wert mitgegeben werden");
                                failedCheck.setVisible(true);
                                failedCheck.setTextFill(Paint.valueOf("#DD0000"));

                                textField.setStyle("-fx-border-color: #dd0000");

                                pause.play();

                                if (singleAttributBox.getChildren().size() > 2) singleAttributBox.getChildren().removeLast();
                                singleAttributBox.getChildren().addLast(failedCheck);
                            }
                        } else if(!textField.getText().matches("^-?[0-9]+[,.]?[0-9]*")){
                            Label failedCheck = new Label("Der Wert muss einer Dezimal Zahl entsprechen ");
                            failedCheck.setVisible(true);
                            failedCheck.setTextFill(Paint.valueOf("#DD0000"));

                            textField.setStyle("-fx-border-color: #dd0000");
                            pause.play();

                            if (singleAttributBox.getChildren().size() > 2) singleAttributBox.getChildren().removeLast();
                            singleAttributBox.getChildren().addLast(failedCheck);
                        } else if (new BigDecimal(eingabe).compareTo(attributDezimal.getMin()) < 0 ||
                                new BigDecimal(eingabe).compareTo(attributDezimal.getMax()) > 0) {
                            Label failedCheck = new Label("Der Wert muss zwischen "
                                    + attributDezimal.getMin() + " und " + attributDezimal.getMax() + " liegen");
                            failedCheck.setVisible(true);
                            failedCheck.setTextFill(Paint.valueOf("#DD0000"));

                            textField.setStyle("-fx-border-color: #dd0000");
                            pause.play();

                            if (singleAttributBox.getChildren().size() > 2) singleAttributBox.getChildren().removeLast();
                            singleAttributBox.getChildren().addLast(failedCheck);
                        }else {
                            if (singleAttributBox.getChildren().size() > 2) singleAttributBox.getChildren().removeLast();
                            attributDezimal.setValue(new BigDecimal(eingabe));
                            ((ProduktbausteinType)newSelection.getValue().getProdukt()).getAttribute().set(finalJ, attributDezimal);
                        }
                    } else if (attributInt != null) {
                        infoBoxFromItem.computeIfAbsent(newSelection,
                                k -> new HashMap<>()).put(attributInt, textField.getText());

                        if (textField.getText() == null || textField.getText().isEmpty()
                                || !textField.getText().matches("^-?[0-9]*")) {
                            Label failedCheck = new Label("Es muss ein ganzzahliger Wert eingegeben werden");
                            failedCheck.setVisible(true);
                            failedCheck.setTextFill(Paint.valueOf("#DD0000"));

                            textField.setStyle("-fx-border-color: #dd0000");
                            pause.play();

                            if (singleAttributBox.getChildren().size() > 2) singleAttributBox.getChildren().removeLast();
                            singleAttributBox.getChildren().addLast(failedCheck);
                        }else if (Integer.parseInt(textField.getText()) < attributInt.getMin()
                                || Integer.parseInt(textField.getText()) > attributInt.getMax()) {
                            Label failedCheck = new Label("Der Wert muss zwischen " + attributInt.getMin()
                                    + " und " + attributInt.getMax() + " liegen");
                            failedCheck.setVisible(true);
                            failedCheck.setTextFill(Paint.valueOf("#DD0000"));

                            textField.setStyle("-fx-border-color: #dd0000");
                            pause.play();

                            if (singleAttributBox.getChildren().size() > 2) singleAttributBox.getChildren().removeLast();
                            singleAttributBox.getChildren().addLast(failedCheck);
                        }else {
                            if (singleAttributBox.getChildren().size() > 2) singleAttributBox.getChildren().removeLast();
                            attributInt.setValue(Integer.parseInt(textField.getText()));
                            ((ProduktbausteinType)newSelection.getValue().getProdukt()).getAttribute().set(finalJ, attributInt);
                        }
                    } else if (stringAttribut != null) {
                        infoBoxFromItem.computeIfAbsent(newSelection,
                                k -> new HashMap<>()).put(stringAttribut, textField.getText());

                        if (textField.getText() == null ||
                                (stringAttribut.getMinLaenge() != null
                                        && textField.getText().length() < stringAttribut.getMinLaenge()) ||
                                (stringAttribut.getMaxLaenge() != null
                                        && textField.getText().length() > stringAttribut.getMaxLaenge()) ||
                                (stringAttribut.getRegex() != null
                                        && !textField.getText().matches(stringAttribut.getRegex()))) {
                            Label failedCheck = new Label("Der Wert muss zwischen " +
                                    stringAttribut.getMinLaenge() + " und " + stringAttribut.getMaxLaenge() +
                                    (stringAttribut.getRegex() != null ? " Buchstaben haben und der Form " +
                                            stringAttribut.getRegex() + " entsprechen" : "Buchstaben haben"));
                            failedCheck.setVisible(true);
                            failedCheck.setTextFill(Paint.valueOf("#DD0000"));

                            textField.setStyle("-fx-border-color: #dd0000");
                            pause.play();

                            if (singleAttributBox.getChildren().size() > 2) singleAttributBox.getChildren().removeLast();
                            ((ProduktbausteinType)newSelection.getValue().getProdukt()).getAttribute().set(finalJ, attributInt);

                        }else {
                            if (singleAttributBox.getChildren().size() > 2) singleAttributBox.getChildren().removeLast();
                            stringAttribut.setValue(textField.getText());
                            ((ProduktbausteinType)newSelection.getValue().getProdukt()).getAttribute().set(finalJ, stringAttribut);
                        }
                    }

                }
            });
            if (attributBoolean != null) {
                singleAttributBox.getChildren().addAll(label, checkBox);
            }else {
                textField.setId("textField");
                singleAttributBox.getChildren().addAll(label, textField);
            }

            singleAttributBox.setId("singleAttributBox");

            attributBox.getChildren().add(singleAttributBox);
        }

        if (((ProduktbausteinType) newSelection.getValue().getProdukt()).isRisikoobjektErforderlich()) {

            VBox risikoobjektAuswahlBox = new VBox();
            Label vpRo = new Label("Mit dem Baustein assoziierte Risikoobjekte: ");

            for (int i = 0; i < risikoobjekte.size(); i++) {
                CheckBox checkBox = new CheckBox();
                checkBox.setText(risikoobjekte.get(i).toString());

                if (risikoobjekte.get(i) instanceof FahrzeugType) {
                    checkBox.setText(((FahrzeugType) risikoobjekte.get(i)).getHandelsbez() + " ("
                            + ((FahrzeugType) risikoobjekte.get(i)).getBaujahr() + ")");

                    int finalI = i;

                    if (((ProduktbausteinType) newSelection.getValue().getProdukt()).getVersicherteObjekte()
                            .stream().anyMatch(v -> ((FahrzeugType) v).getHandelsbez()
                                    .equals(((FahrzeugType) risikoobjekte.get(finalI)).getHandelsbez()))) {
                        checkBox.setSelected(true);
                    }

                    checkBox.selectedProperty().addListener((observableValue, oldValue, newValue) -> {
                        if (newValue) {
                            ((ProduktbausteinType) newSelection.getValue().getProdukt()).getVersicherteObjekte().add(risikoobjekte.get(finalI));
                        } else {
                            ((ProduktbausteinType) newSelection.getValue().getProdukt()).getVersicherteObjekte().remove(finalI);
                        }
                    });
                }
                risikoobjektAuswahlBox.getChildren().add(checkBox);
            }

            risikoobjektAuswahlBox.getChildren().addFirst(vpRo);
            risikoobjektAuswahlBox.setPadding(new Insets(10));
            risikoobjektAuswahlBox.setId("risikoobjektAuswahlBox");

            attributBox.getChildren().removeIf(c -> c.getId() != null && c.getId().equals("risikoobjektAuswahlBox"));
            attributBox.getChildren().add(risikoobjektAuswahlBox);
        }

        return addFaultsInfo((ProduktbausteinType) newSelection.getValue().getProdukt(), attributBox);
    }

    public VBox addFaultsInfo(ProduktbausteinType produktbaustein, VBox attributBox) {
        if (produktbaustein.getMeldungen() != null && !produktbaustein.getMeldungen().isEmpty()) {
            attributBox.getChildren().removeIf(n -> n.getId() != null && n.getId().equals("faultsbox"));
            VBox faultsBox = new VBox();
            faultsBox.setId("faultsbox");

            for (ServiceFault sf : produktbaustein.getMeldungen()) {
                HBox singleFaultBox = new HBox();

                Text symbole = new Text("\u26A0 ");
                symbole.setFont(Font.font("System", FontWeight.BOLD, symbole.getFont().getSize() + 2));

                if (sf.getErrorType().equals(BigInteger.ONE)) {
                    symbole.setFill(Paint.valueOf("#aa3333"));
                } else if (sf.getErrorType().equals(BigInteger.TWO)) {
                    symbole.setFill(Paint.valueOf("#ccbb00"));
                }
                Label errorText = new Label(sf.getErrorMsg() + System.lineSeparator());
                errorText.setId("errorText");

                singleFaultBox.getChildren().addAll(symbole, errorText);
                singleFaultBox.setId("singleFaultBox");
                faultsBox.getChildren().add(singleFaultBox);
            }

            if (!faultsBox.getChildren().isEmpty()) {
                if (produktbaustein.getAttribute().isEmpty()) {
                    attributBox.getChildren().addAll(faultsBox);
                }else {
                    List<Node> singleAttributBoxes = attributBox.getChildren().stream().filter(n -> n.getId() != null && n.getId().equals("singleAttributBox")).toList();
                    Optional<Node> textField;
                    Optional<Node> label;
                    for (Node singleAttributBox : singleAttributBoxes) {
                        textField = ((VBox)singleAttributBox).getChildren().stream().filter(n -> n.getId() != null && n.getId().equals("textField")).findFirst();
                        label = ((VBox)singleAttributBox).getChildren().stream().filter(n -> n.getId() != null && n.getId().equals("label")).findFirst();
                        List<Node> singleFaultBoxes = faultsBox.getChildren().stream().filter(n -> n.getId() != null && n.getId().equals("singleFaultBox")).toList();

                        if (textField.isPresent() && label.isPresent()) {

                            for (Node singleFaultBox : singleFaultBoxes) {
                                Optional<Node> errorText = ((HBox)singleFaultBox).getChildren().stream().filter(c -> c.getId() != null && c.getId().equals("errorText")).findFirst();

                                if (errorText.isPresent() && ((Label)errorText.get()).getText().contains(((Label)label.get()).getText().replace(":","").replace("*",""))) {
                                    textField.get().setStyle("-fx-border-color: #dd0000");
                                    ((VBox)singleAttributBox).getChildren().addLast(faultsBox);
                                    Optional<Node> finalTextField = textField;
                                    textField.get().focusedProperty().addListener(s -> finalTextField.get().setStyle(null));

                                }
                            }
                        }
                    }
                }
            }
        }
        return attributBox;
    }

    public VBox addVpInfo(VBox attributBox, boolean meldungVorhanden, VerkaufsproduktType vp) {
        attributBox.getChildren().removeIf(c -> c.getId() != null && c.getId().equals("vpLabel"));

        Label vpLabel = new Label();
        if (!meldungVorhanden) {
            vpLabel.setText("Gültiges Verkaufsprodukt " + System.lineSeparator());
        }else {
            vpLabel.setText("Kein Gültiges Verkaufsprodukt " + System.lineSeparator());
        }
        vpLabel.setPadding(new Insets(10));
        attributBox.getChildren().addFirst(vpLabel);


//        VBox vpMeldungenTexts = new VBox();
//        vp.getMeldungen().forEach( m -> {
//            Label vpMeldungText = new Label(m.getErrorMsg() + System.lineSeparator());
//            vpMeldungText.setPadding(new Insets(10));
//
//            vpMeldungenTexts.getChildren().add(vpMeldungText);
//        });

        attributBox.getChildren().removeIf(c -> c.getId() != null && c.getId().equals("vpMeldungenTexts"));
//        attributBox.getChildren().addAll(vpMeldungenTexts);

        return attributBox;
    }

}
