package de.duehl.vocabulary.japanese.ui.dialog.kana.katakanatest;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Image;
import java.awt.Point;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;

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.swing.ui.GuiTools;
import de.duehl.swing.ui.components.selections.StringSelection;
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.Katakana;
import de.duehl.vocabulary.japanese.logic.symbol.kana.test.data.SingleUserInputKatakanaCheckResult;
import de.duehl.vocabulary.japanese.ui.data.FumikoUiObjects;
import de.duehl.vocabulary.japanese.ui.dialog.kana.katakanatest.components.KatakanaDetailDialog;
import de.duehl.vocabulary.japanese.ui.dialog.kana.katakanatest.components.KatakanaPanel;
import de.duehl.vocabulary.japanese.ui.dialog.kanji.stroke.KanjiStrokesUiTools;

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

public class KatakanaTestEvaluationDialog extends ModalDialogBase {

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


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

    /** Das Katakana welches abgefragt wurde. */
    private final Katakana katakana;

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

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

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

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

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

    /** Das UI-Komponente, auf der die Daten des Katakana dargestellt werden. */
    private final KatakanaPanel katakanaPanel;

    /** 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 StringSelection userInputHepburnSelection;

    private final TextAreaSelection errorMessageSelection;

    private boolean errorFilled;

    /**
     * Konstruktor.
     *
     * @param result
     *            Das Ergebnis der Bewertung der Benutzereingaben inklusive Katakana, 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 options
     *            Die Programmoptionen.
     * @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.
     * @param programImage
     *            Anzuzeigendes ProgrammIcon.
     */
    public KatakanaTestEvaluationDialog(SingleUserInputKatakanaCheckResult result,
            String userInputHepburn, Options options, FumikoDataStructures dataStructures,
            FumikoUiObjects uiObjects, Point parentLocation, Image programImage) {
        super(parentLocation, programImage, result.isOk() ? "Richtig!" : "Leider falsch");
        addEscapeBehaviour();

        this.result = result;
        this.dataStructures = dataStructures;
        this.uiObjects = uiObjects;

        katakana = result.getKatakana();
        correct = result.isOk();

        onlyTypingError = false;

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

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

        quitButton = new JButton("Beenden");

        katakanaPanel = new KatakanaPanel(dataStructures, uiObjects);
        userInputHepburnSelection = new StringSelection("Eingebene Hepburn-Darstellung");
        errorMessageSelection = new TextAreaSelection("Fehlermeldungen");

        init(userInputHepburn);
        fillDialog();
    }

    private void init(String userInputHepburn) {
        initKatakanaPanel();
        fillKatakanaPanel();

        initUserInputTextSelectionms();
        fillUserInputTextSelections(userInputHepburn);

        initResultTextSelections();
        fillResultTextSelections();

        initQuitButton();
    }

    private void initKatakanaPanel() {
        katakanaPanel.createGui();
    }

    private void fillKatakanaPanel() {
        katakanaPanel.showKatakana(katakana, getLocation());
    }

    private void initUserInputTextSelectionms() {
        SelectionsHelper.initSelectionAsViewer(userInputHepburnSelection);
    }

    private void fillUserInputTextSelections(String userInputHepburn) {
        userInputHepburnSelection.setText(userInputHepburn);
    }

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

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

        errorMessageSelection.setText(errorDescription);

        errorFilled = !errorDescription.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();
        }

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

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

        panel.add(createMessagePart());
        panel.add(createKatakanaDataPart());
        panel.add(createUserDataPart());
        if (errorFilled) {
            panel.add(createErrorMesagePart());
        }

        if (!correct) {
            panel.add(createOnlyTypingErrorLabel());
        }

        return GuiTools.createScrollPane(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 createKatakanaDataPart() {
        JPanel panel = new JPanel();
        panel.setLayout(new VerticalLayout(0, VerticalLayout.BOTH));
        GuiTools.createBlueTitle("Daten zum abgefragten Katakana:", panel);

        panel.add(katakanaPanel.getPanel());

        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(userInputHepburnSelection.getPanel());

        return panel;
    }

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

        if (errorFilled) {
            panel.add(errorMessageSelection.getPanel());
        }

        return panel;
    }

    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 createButtonsPart() {
        JPanel panel = new JPanel();
        panel.setLayout(new BorderLayout());

        panel.add(createLeftButtonsPart(), BorderLayout.WEST);
        panel.add(createQuitButton(), BorderLayout.EAST);

        return panel;
    }

    private Component createLeftButtonsPart() {
        JPanel panel = new JPanel();
        panel.setLayout(new FlowLayout(FlowLayout.LEFT, 2, 2));

        panel.add(createDetailButton());
        panel.add(createStrokesButton());

        return panel;
    }

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

    private void showDetails() {
        KatakanaDetailDialog dialog = new KatakanaDetailDialog(katakana, dataStructures, uiObjects,
                getParentLocation(), getProgramImage());
        dialog.setVisible(true);
    }

    private Component createStrokesButton() {
        JButton button = new JButton("Strichfolge anzeigenn");
        button.addActionListener(e -> showStrokes());
        return button;
    }

    private void showStrokes() {
        KanjiStrokesUiTools.showKanjiStrokes(katakana.getCharacter(),
                dataStructures.getKanjiStrokes(), getWindowAsComponent(), getLocation(),
                uiObjects.getProgramImage());
    }

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

    private void keybindingsForDetailAndStrokesDialog() {
        KeyStroke keyStrokeD = KeyStroke.getKeyStroke(KeyEvent.VK_D, InputEvent.CTRL_DOWN_MASK);
        String actionMapKeyD = "Strg-D";
        Action actionD = BindKeysOnRootPane.runnableToAction(() -> showDetails());

        KeyStroke keyStrokeS = KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.CTRL_DOWN_MASK);
        String actionMapKeyS = "Strg-S";
        Action actionS = BindKeysOnRootPane.runnableToAction(() -> showStrokes());

        JRootPane rootPane = getRootPane();
        InputMap inputMap = rootPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
        inputMap.put(keyStrokeD, actionMapKeyD);
        rootPane.getActionMap().put(actionMapKeyD, actionD);
        inputMap.put(keyStrokeS, actionMapKeyS);
        rootPane.getActionMap().put(actionMapKeyS, actionS);
    }

    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;
    }

}
