package de.duehl.vocabulary.japanese.ui.dialog.kanji.kanjitest;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.Point;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.util.List;

import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.InputMap;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRootPane;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;

import de.duehl.basics.text.Text;
import de.duehl.swing.ui.GuiTools;
import de.duehl.swing.ui.components.selections.TextAreaSelection;
import de.duehl.swing.ui.components.selections.tools.SelectionsHelper;
import de.duehl.swing.ui.dialogs.base.ModalDialogBase;
import de.duehl.swing.ui.key.BindKeysOnRootPane;
import de.duehl.swing.ui.layout.VerticalLayout;
import de.duehl.vocabulary.japanese.common.color.VocableColors;
import de.duehl.vocabulary.japanese.common.persistence.Options;
import de.duehl.vocabulary.japanese.data.FumikoDataStructures;
import de.duehl.vocabulary.japanese.data.symbol.Kanji;
import de.duehl.vocabulary.japanese.logic.symbol.kanji.test.data.KanjiUserInputType;
import de.duehl.vocabulary.japanese.logic.symbol.kanji.test.data.SingleUserInputKanjiCheckResult;
import de.duehl.vocabulary.japanese.ui.data.FumikoUiObjects;
import de.duehl.vocabulary.japanese.ui.dialog.kanji.display.KanjiPanel;
import de.duehl.vocabulary.japanese.ui.dialog.kanji.detail.KanjiDetailDialog;
import de.duehl.vocabulary.japanese.ui.dialog.kanji.display.KanjiGermanMeaningAndLesungenPanel;

/**
 * Diese Klasse zeigt den Erfolg oder Misserfolg nach dem Abfragen eines Kanji an.
 *
 * @version 1.01     2026-01-01
 * @author Christian Dühl
 */

public class KanjiTestEvaluationDialog extends ModalDialogBase {

    /** Minimale Breite des Fensters, ansonsten passt es sich an den Inhalt an. */
    private static final int MIN_WIDTH = 1400;


    /** Das Ergebnis der Prüfung. */
    private final SingleUserInputKanjiCheckResult result;

    /** Das Kanji welches abgefragt wurde. */
    private final Kanji kanji;

    /** Gibt an, ob die Übersetzung korrekt war. */
    private final boolean correct;

    /** Die Datenstrukturen des Vokabeltrainers. */
    private final FumikoDataStructures dataStructures;

    /** Die häufig verwendeten Funktionen der grafischen Oberfläche des Vokabeltrainers. */
    private final FumikoUiObjects uiObjects;

    /** Die anzuzeigende Nachricht. */
    private final String message;

    /** Das Objekt das passende Farben erzeugt. */
    private final VocableColors vocableColors;

    /** Die Hintergrundfarbe. */
    private final Color backgroundColor;

    /** Erzeugt die Komponente, die das Kanji groß dargestellt. */
    private final KanjiPanel kanjiPanel;

    /** Stellt die deutschen Bedeutungen und die Lesungen des Kanji dar. */
    private final KanjiGermanMeaningAndLesungenPanel kanjiGermanMeaningAnLesungenPanel;

    /** Der Button zum Beenden des Dialogs. */
    private final JButton quitButton;

    /** Gibt an, ob im Fall einer falsch beantworteten Vokabel nur ein Tippfehler vorlag. */
    private boolean onlyTypingError;

    private final TextAreaSelection userInputGermanMeaningSelection;
    private final TextAreaSelection userInputOnLesungenSelection;
    private final TextAreaSelection userInputKunLesungenSelection;

    private final TextAreaSelection errorMessageSelection;
    private final TextAreaSelection memorandumSelection;

    private boolean errorFilled;
    private boolean memorandumFilled;

    /**
     * Konstruktor.
     *
     * @param result
     *            Das Ergebnis der Bewertung der Benutzereingaben inklusive Kanji, welches
     *            abgefragt wurde.
     * @param userInputGermanMeaning
     *            Die vom Benutzer eingegebene deutsche Bedeutung.
     * @param userInputOnLesung
     *            Die vom Benutzer eingebenen ON-Lesungen.
     * @param userInputKunLesung
     *            Die vom Benutzer eingebenen kun-Lesungen.
     * @param correct
     *            Gibt an, ob die Abfrage korrekt war.
     * @param dataStructures
     *            Die Datenstrukturen des Vokabeltrainers.
     * @param uiObjects
     *            Die häufig verwendeten Funktionen der grafischen Oberfläche des Vokabeltrainers.
     * @param parentLocation
     *            Position des Rahmens der Oberfläche, vor der dieser Dialog erzeugt wird.
     */
    public KanjiTestEvaluationDialog(SingleUserInputKanjiCheckResult result,
            String userInputGermanMeaning, String userInputOnLesung, String userInputKunLesung,
            FumikoDataStructures dataStructures, FumikoUiObjects uiObjects, Point parentLocation) {
        super(parentLocation, uiObjects.getProgramImage(),
                result.isOk() ? "Richtig!" : "Leider falsch");
        addEscapeBehaviour();

        this.result = result;
        this.kanji = result.getKanji();
        this.correct = result.isOk();
        this.dataStructures = dataStructures;
        this.uiObjects = uiObjects;

        onlyTypingError = false;

        message = correct ? "Richtig beantwortet, sehr gut!" : "Das war leider nicht richtig";

        vocableColors = new VocableColors(dataStructures.getOptions());
        backgroundColor = correct
                ? vocableColors.getSuccessColor()
                : vocableColors.getFailureColor();

        quitButton = new JButton("Beenden");

        kanjiPanel = new KanjiPanel();
        kanjiPanel.setBiggerFontSize(200); // Default: 400
        kanjiPanel.showKanji(kanji);
        kanjiPanel.setAfterFontButtonPressedRunnable(() -> pack());

        kanjiGermanMeaningAnLesungenPanel = new KanjiGermanMeaningAndLesungenPanel(kanji);

        userInputGermanMeaningSelection = new TextAreaSelection("Eingebene deutsche Bedeutung");
        userInputOnLesungenSelection = new TextAreaSelection("Eingebene ON-Lesungen");
        userInputKunLesungenSelection = new TextAreaSelection("Eingebene kun-Lesungen");
        errorMessageSelection = new TextAreaSelection("Fehlermeldungen");
        memorandumSelection = new TextAreaSelection("Hinweise");

        init(userInputGermanMeaning, userInputOnLesung, userInputKunLesung);
        fillDialog();
    }

    private void init(String userInputGermanMeaning, String userInputOnLesung,
            String userInputKunLesung) {
        initUserInputTextSelections();
        fillUserInputTextSelections(userInputGermanMeaning, userInputOnLesung, userInputKunLesung);

        initResultTextSelections();
        fillResultTextSelections();

        initQuitButton();
    }

    private void initUserInputTextSelections() {
        SelectionsHelper.initSelectionAsViewer(userInputGermanMeaningSelection);
        SelectionsHelper.initSelectionAsViewer(userInputOnLesungenSelection);
        SelectionsHelper.initSelectionAsViewer(userInputKunLesungenSelection);
        userInputGermanMeaningSelection.setFocusable(true);
        userInputOnLesungenSelection.setFocusable(true);
        userInputKunLesungenSelection.setFocusable(true);

        Options options = dataStructures.getOptions();
        if (options.isColorUserInputAtKanjiTestEvaluationDialog()) {
            setUserInputTextSelectionsBackgrounds();
        }
    }

    private void setUserInputTextSelectionsBackgrounds() {
        List<KanjiUserInputType> wrongKanjiUserInputTypes = result.getWrongKanjiUserInputTypes();
        boolean germanMeaningCorrect = !wrongKanjiUserInputTypes.contains(
                KanjiUserInputType.GERMAN_MEANING);
        boolean onLesungCorrect = !wrongKanjiUserInputTypes.contains(
                KanjiUserInputType.ON_LESUNG);
        boolean kunLesungCorrect = !wrongKanjiUserInputTypes.contains(
                KanjiUserInputType.KUN_LESUNG);

        Color germanMeaningColor = getSuccessOrFailureColor(germanMeaningCorrect);
        Color onLesungColor = getSuccessOrFailureColor(onLesungCorrect);
        Color kunLesungColor = getSuccessOrFailureColor(kunLesungCorrect);

        userInputGermanMeaningSelection.setBackgroundColor(germanMeaningColor);
        userInputOnLesungenSelection.setBackgroundColor(onLesungColor);
        userInputKunLesungenSelection.setBackgroundColor(kunLesungColor);
    }

    private Color getSuccessOrFailureColor(boolean correct) {
        if (correct) {
            return vocableColors.getSuccessColor();
        }
        else {
            return vocableColors.getFailureColor();
        }
    }

    private void fillUserInputTextSelections(String userInputGermanMeaning,
            String userInputOnLesung, String userInputKunLesung) {
        int numberOfGermanMeanings = kanji.getGermanMeanings().size();
        int numberOfOnLesungen = kanji.getOnLesungen().size();
        int numberOfKunLesungen = kanji.getKunLesungen().size();

        String germanMeaningsByUser;
        if (kanjiHasSpacesInGermanMeanings()) {
            germanMeaningsByUser = splitByKomma(userInputGermanMeaning, numberOfGermanMeanings);
        }
        else {
            germanMeaningsByUser = splitBySpaceOrKomma(userInputGermanMeaning,
                    numberOfGermanMeanings);
        }
        String onLesungenByUser = splitBySpaceOrKomma(userInputOnLesung, numberOfOnLesungen);
        String kunLsungenByUser = splitBySpaceOrKomma(userInputKunLesung, numberOfKunLesungen);

        userInputGermanMeaningSelection.setText(germanMeaningsByUser);
        userInputOnLesungenSelection.setText(onLesungenByUser);
        userInputKunLesungenSelection.setText(kunLsungenByUser);
    }

    private boolean kanjiHasSpacesInGermanMeanings() {
        for (String germanMeaning : kanji.getGermanMeanings()) {
            if (germanMeaning.contains(" ")) {
                return true;
            }
        }

        return false;
    }

    private String splitByKomma(String userInputGermanMeaning, int wantedSize) {
        List<String> parts = Text.splitByKomma(userInputGermanMeaning);
        return joinWithLineBreak(parts, wantedSize);
    }

    private String splitBySpaceOrKomma(String userInputLesung, int wantedSize) {
        List<String> parts = Text.splitBy(userInputLesung, " *, *| +");
        return joinWithLineBreak(parts, wantedSize);
    }

    private String joinWithLineBreak(List<String> parts, int wantedSize) {
        while (parts.size() < wantedSize) {
            parts.add("");
        }
        return Text.joinWithLineBreak(parts);
    }

    private void initResultTextSelections() {
        SelectionsHelper.initSelectionAsViewer(errorMessageSelection);
        SelectionsHelper.initSelectionAsViewer(memorandumSelection);
    }

    private void fillResultTextSelections() {
        String errorDescription = result.getErrorDescription();
        String memorandum = result.getMemorandum();

        errorMessageSelection.setText(errorDescription);
        memorandumSelection.setText(memorandum);

        errorFilled = !errorDescription.isBlank();
        memorandumFilled = !memorandum.isBlank();
    }

    private void initQuitButton() {
        GuiTools.addReturnListener(quitButton, () -> quitButton.doClick());
    }

    /** Baut die Gui auf. */
    @Override
    protected void populateDialog() {
        add(createCenterPart(), BorderLayout.CENTER);
        add(createButtonsPart(),  BorderLayout.SOUTH);

        if (!correct) {
            keybindingsForOnlyTypingError();
        }

        keybindingsForDetailDialog();
        SwingUtilities.invokeLater(() -> quitButton.requestFocus());
        pack();
    }

    private Component createCenterPart() {
        JPanel panel = new JPanel();
        panel.setLayout(new BorderLayout());

        panel.add(createMessagePart(), BorderLayout.NORTH);
        panel.add(createBigCenterPart(), BorderLayout.CENTER);

        return panel;
    }

    private Component createMessagePart() {
        JPanel panel = new JPanel();
        panel.setLayout(new BorderLayout());
        GuiTools.createTitle(panel);

        panel.add(createMessageLabel(), BorderLayout.CENTER);

        return panel;
    }

    private Component createMessageLabel() {
        JLabel label = new JLabel(message);
        label.setHorizontalAlignment(JLabel.CENTER);
        label.setPreferredSize(new Dimension(MIN_WIDTH, 30));

        GuiTools.biggerFont(label, 7);
        label.setOpaque(true);
        label.setBackground(backgroundColor);
        return label;
    }

    private Component createBigCenterPart() {
        JPanel panel = new JPanel();
        panel.setLayout(new VerticalLayout(0, VerticalLayout.BOTH));

        panel.add(createLeftBigCenterPart());
        panel.add(createRightBigCenterPart());

        return panel;
    }

    private Component createLeftBigCenterPart() {
        JPanel panel = new JPanel();
        panel.setLayout(new GridLayout(1, 0, 2, 2));

        panel.add(createUpperLeftBigCenterPart());
        panel.add(createUpperRightBigCenterPart());

        return panel;
    }

    private Component createRightBigCenterPart() {
        JPanel panel = new JPanel();
        panel.setLayout(new GridLayout(1, 0, 2, 2));

        panel.add(createLowerLeftBigCenterPart());
        panel.add(createLowerRightBigCenterPart());

        return panel;
    }

    private Component createUpperLeftBigCenterPart() {
        JPanel panel = new JPanel();
        panel.setLayout(new BorderLayout());
        GuiTools.createBlueTitle("Daten zum abgefragten Kanji:", panel);

        panel.add(kanjiPanel.getPanel(), BorderLayout.NORTH);

        return panel;
    }

    private Component createUpperRightBigCenterPart() {
        JPanel panel = new JPanel();
        panel.setLayout(new BorderLayout());

        if (errorFilled || memorandumFilled) {
            panel.add(createErrorMessageAndMemorandumPart(), BorderLayout.NORTH);
        }

        return panel;
    }

    private Component createLowerLeftBigCenterPart() {
        JPanel panel = new JPanel();
        panel.setLayout(new BorderLayout());
        GuiTools.createBlueTitle("Daten zum abgefragten Kanji:", panel);

        panel.add(kanjiGermanMeaningAnLesungenPanel.getPanel(), BorderLayout.SOUTH);

        return panel;
    }

    private Component createLowerRightBigCenterPart() {
        JPanel panel = new JPanel();
        panel.setLayout(new BorderLayout());

        panel.add(createUserDataPart(), BorderLayout.SOUTH);

        return panel;
    }

//    private Component createLeftBigCenterPart() {
//        JPanel panel = new JPanel();
//        panel.setLayout(new VerticalLayout(0, VerticalLayout.BOTH));
//
//        panel.add(createKanjiDataPart());
//
//        return panel;
//    }
//
//    private Component createKanjiDataPart() {
//        JPanel panel = new JPanel();
//        panel.setLayout(new BorderLayout());
//        GuiTools.createBlueTitle("Daten zum abgefragten Kanji:", panel);
//
//        panel.add(kanjiPanel.getPanel(), BorderLayout.NORTH);
//        panel.add(createDummyPanel(), BorderLayout.CENTER);
//        panel.add(kanjiGermanMeaningAnLesungenPanel.getPanel(), BorderLayout.SOUTH);
//
//        return panel;
//    }
//
//    private Component createDummyPanel() {
//        JPanel panel = new JPanel();
//        panel.setLayout(new BorderLayout());
//
//        panel.add(new JLabel(), BorderLayout.CENTER);
//
//        return panel;
//    }
//
//    private Component createRightBigCenterPart() {
//        JPanel panel = new JPanel();
//        panel.setLayout(new BorderLayout());
//
//        if (errorFilled || memorandumFilled) {
//            panel.add(createErrorMessageAndMemorandumPart(), BorderLayout.NORTH);
//        }
//        panel.add(createUserDataPart(), BorderLayout.SOUTH);
//
//        return panel;
//    }

    private Component createErrorMessageAndMemorandumPart() {
        JPanel panel = new JPanel();
        panel.setLayout(new VerticalLayout(0, VerticalLayout.BOTH));
        GuiTools.createBlueTitle("Anmerkungen:", panel);
        /*
        if (errorFilled && memorandumFilled) {
            GuiTools.createBlueTitle("Fehlermeldungen und Hinweise:", panel);
        }
        else if (errorFilled) {
            GuiTools.createBlueTitle("Fehlermeldungen:", panel);
        }
        else if (memorandumFilled) {
            GuiTools.createBlueTitle("Hinweise:", panel);
        }
        */

        if (errorFilled) {
            panel.add(createErrorMessagePart());
        }
        if (memorandumFilled) {
            panel.add(createMemorandumPart());
        }

        return panel;
    }

    private Component createUserDataPart() {
        JPanel panel = new JPanel();
        panel.setLayout(new VerticalLayout(0, VerticalLayout.BOTH));
        GuiTools.createBlueTitle("Vom Benutzer eingegebene Daten:", panel);

        panel.add(userInputGermanMeaningSelection.getPanel());
        panel.add(userInputOnLesungenSelection.getPanel());
        panel.add(userInputKunLesungenSelection.getPanel());

        return panel;
    }

    private Component createErrorMessagePart() {
        JPanel panel = new JPanel();
        panel.setLayout(new VerticalLayout(0, VerticalLayout.BOTH));
        //GuiTools.createBlueTitle("Fehler:", panel);

        panel.add(errorMessageSelection.getPanel());

        return panel;
    }

    private Component createMemorandumPart() {
        JPanel panel = new JPanel();
        panel.setLayout(new VerticalLayout(0, VerticalLayout.BOTH));
        //GuiTools.createBlueTitle("Hinweise:", panel);

        panel.add(memorandumSelection.getPanel());

        return panel;
    }

    private Component createButtonsPart() {
        JPanel panel = new JPanel();
        panel.setLayout(new BorderLayout());

        panel.add(createDetailButton(), BorderLayout.WEST);
        if (!correct) {
            panel.add(GuiTools.centerHorizontal(createOnlyTypingErrorLabel()), BorderLayout.CENTER);
        }
        panel.add(createQuitButton(), BorderLayout.EAST);

        return panel;
    }

    private Component createDetailButton() {
        JButton button = new JButton("Details anzeigen");
        button.addActionListener(e -> showDetails());
        return button;
    }

    private void showDetails() {
        KanjiDetailDialog dialog = new KanjiDetailDialog(kanji, dataStructures , uiObjects,
                uiObjects.getInformer(), getLocation());
        dialog.setVisible(true);
    }

    private void keybindingsForDetailDialog() {
        KeyStroke keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_D, InputEvent.CTRL_DOWN_MASK);
        String actionMapKey = "Strg-D";
        Action action = BindKeysOnRootPane.runnableToAction(() -> showDetails());

        JRootPane rootPane = getRootPane();
        InputMap inputMap = rootPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
        inputMap.put(keyStroke, actionMapKey);
        rootPane.getActionMap().put(actionMapKey, action);
    }

    private Component createOnlyTypingErrorLabel() {
        JLabel label = new JLabel("War es nur ein Tippfehler? Dann Strg-Shift-K drücken.");
        label.setBorder(BorderFactory.createEmptyBorder(0,  5,  0,  5));
        return label;
    }

    private Component createQuitButton() {
        quitButton.addActionListener(e -> closeDialog());
        quitButton.setBackground(backgroundColor);
        return quitButton;
    }

    private void keybindingsForOnlyTypingError() {
        KeyStroke keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_K,
                InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK);
        String actionMapKey = "Strg-Shift-K";
        Action action = BindKeysOnRootPane.runnableToAction(() -> setToOnlyTypingError());

        JRootPane rootPane = getRootPane();
        InputMap inputMap = rootPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
        inputMap.put(keyStroke, actionMapKey);
        rootPane.getActionMap().put(actionMapKey, action);
    }

    private void setToOnlyTypingError() {
        String title = "War es nur ein Tippfehler?";
        String userMessage = "War die falsche Eingabe wirklich nur ein Tippfehler?\n"
                + "Bitte gewissenhaft antworten und sich nicht selbst belügen.";
        onlyTypingError = GuiTools.askUser(getWindowAsComponent(), title, userMessage);
        if (onlyTypingError) {
            closeDialog();
        }
    }

    /** Gibt an, ob im Fall einer falsch beantworteten Vokabel nur ein Tippfehler vorlag. */
    public boolean wasOnlyTypingError() {
        return onlyTypingError;
    }

}
