package de.duehl.vocabulary.japanese.ui.dialog.testing;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Point;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
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.JTextPane;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;

import de.duehl.swing.logic.LongTimeProcessInformer;
import de.duehl.swing.ui.GuiTools;
import de.duehl.swing.ui.components.MultipleElementsPanel;
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.data.TranslationDirection;
import de.duehl.vocabulary.japanese.common.persistence.Options;
import de.duehl.vocabulary.japanese.data.FumikoDataStructures;
import de.duehl.vocabulary.japanese.data.Vocable;
import de.duehl.vocabulary.japanese.tools.VocabularyTools;
import de.duehl.vocabulary.japanese.ui.components.display.KanjiAndKanaDisplay;
import de.duehl.vocabulary.japanese.ui.components.display.RomajiAndPronunciationDisplay;
import de.duehl.vocabulary.japanese.ui.components.display.TranslationCommentAndVocabularyDescriptionDisplay;
import de.duehl.vocabulary.japanese.ui.data.FumikoUiObjects;
import de.duehl.vocabulary.japanese.ui.dialog.testing.data.VocableAndVocablePanel;
import de.duehl.vocabulary.japanese.ui.dialog.vocables.detail.VocableWithInternaDialog;
import de.duehl.vocabulary.japanese.ui.dialog.vocables.detail.addtolist.VocableToOwnListAdderGui;
import de.duehl.vocabulary.japanese.ui.dialog.vocables.detail.findlists.ListsWithVocableFinderGui;
import de.duehl.vocabulary.japanese.ui.dialog.vocables.detail.related.VerbsAndAdjectivesFinderGui;

/**
 * Diese Klasse zeigt den Erfolg oder Misserfolg nach dem Übersetzen einer Variablen an.
 *
 * @version 1.01     2025-11-21
 * @author Christian Dühl
 */

public class TranslationEvaluationDialog extends ModalDialogBase {

    /**
     * Die zu den japanischen Kana oder Kanji und Kana bzw. zum abgefragten deutschen Begriff
     * passenden Vokabeln.
     */
    private final List<Vocable> matchingVocables;

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

    /** Die Richtung, in die übersetzt wird (Japanisch - Deutsch oder Deutsch - Japanisch). */
    private final TranslationDirection translationDirection;

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

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

    /** Der Panel mit den passenden Vokabeln. */
    private final JPanel matchingVocablesPanel;

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

    /** Die Vokabeln mit ihren Panels zur Darstellung. */
    private List<VocableAndVocablePanel> vocablesAndVocablePanels;

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

    /**
     * Konstruktor.
     *
     * @param matchingVocables
     *            Die zu den japanischen Kana oder Kanji und Kana bzw. zum abgefragten deutschen
     *            Begriff passenden Vokabeln.
     * @param correct
     *            Gibt an, ob die Übersetzung korrekt war.
     * @param translationDirection
     *            Die Richtung, in die übersetzt wird (Japanisch - Deutsch oder Deutsch -
     *            Japanisch).
     * @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 TranslationEvaluationDialog(List<Vocable> matchingVocables, boolean correct,
            TranslationDirection translationDirection, FumikoDataStructures dataStructures,
            FumikoUiObjects uiObjects, Point parentLocation) {
        super(parentLocation, uiObjects.getProgramImage(),
                (correct ? "Richtig!" : "Leider falsch") + "  -  F9, Strg-D");
        addEscapeBehaviour();

        this.matchingVocables = matchingVocables;
        this.correct = correct;
        this.translationDirection = translationDirection;
        this.dataStructures = dataStructures;
        this.uiObjects = uiObjects;

        onlyTypingError = false;

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

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

        matchingVocablesPanel = new JPanel();

        quitButton = new JButton("Beenden");

        fillDialog();
    }

    /** Baut die Gui auf. */
    @Override
    protected void populateDialog() {
        initElements();

        add(createCenterPart(), BorderLayout.CENTER);
        add(createButtonsPart(),  BorderLayout.SOUTH);

        fillWithMatchingVocables();

        if (!correct) {
            keybindingsForOnlyTypingError();
        }
        keybindingsForDetailDialog();
        keybindingsForPlaySound();

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

    private void initElements() {
        matchingVocablesPanel.setLayout(new BorderLayout());

        GuiTools.addReturnListener(quitButton, () -> quitButton.doClick());
    }

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

        panel.add(createMessagePart());
        if (matchingVocables.size() == 1) {
            panel.add(matchingVocablesPanel);
        }
        else {
            panel.add(GuiTools.createScrollPane(matchingVocablesPanel));
        }

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

        return GuiTools.createScrollPane(panel);
    }

    private Component createMessagePart() {
        JLabel label = new JLabel(message);
        GuiTools.biggerFont(label, 5);
        label.setOpaque(true);
        label.setBackground(backgroundColor);
        return label;
    }

    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(createQuitButton(), BorderLayout.EAST);

        return panel;
    }

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

    private void fillWithMatchingVocables() {
        createVocablesAndVocablePanels();
        displayVocablePanels();
        pack();
    }

    private void createVocablesAndVocablePanels() {
        vocablesAndVocablePanels = new ArrayList<>();

        for (Vocable vocable : matchingVocables) {
            Component vocablePanel = fillMatchingVocable(vocable);
            VocableAndVocablePanel vocableAndVocablePanel =
                    new VocableAndVocablePanel(vocable, vocablePanel);
            vocablesAndVocablePanels.add(vocableAndVocablePanel);
        }
    }

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

        if (translationDirection == TranslationDirection.GERMAN_TO_JAPANESE) {
            panel.add(createKanjiAndKanaPane(vocable));
            panel.add(createRomajiAndPronunciationPane(vocable));
        }
        panel.add(createTranslationAndCommentPane(vocable));

        return panel;
    }

    private JTextPane createKanjiAndKanaPane(Vocable vocable) {
        Options options = dataStructures.getOptions();
        JTextPane kanjiAndKanaPane = new JTextPane();
        KanjiAndKanaDisplay display = new KanjiAndKanaDisplay(vocable, kanjiAndKanaPane,
                backgroundColor, options);
        display.display();
        return kanjiAndKanaPane;
    }

    private JTextPane createRomajiAndPronunciationPane(Vocable vocable) {
        Options options = dataStructures.getOptions();
        JTextPane romajiAndPronunciationPane = new JTextPane();
        RomajiAndPronunciationDisplay display2 = new RomajiAndPronunciationDisplay(vocable,
                romajiAndPronunciationPane, backgroundColor, options);
        display2.display();
        return romajiAndPronunciationPane;
    }

    private Component createTranslationAndCommentPane(Vocable vocable) {
        Options options = dataStructures.getOptions();
        JTextPane translationAndCommentPane = new JTextPane();
        TranslationCommentAndVocabularyDescriptionDisplay display =
                new TranslationCommentAndVocabularyDescriptionDisplay(vocable,
                        translationAndCommentPane, backgroundColor, options);
        display.hideTranslationIntro();
        if (!options.isShowAllTranslations()) {
            display.setNumberOfShownTranslations(options.getNumberOfShownTranslations());
        }
        display.display();
        return translationAndCommentPane;
    }

    private void displayVocablePanels() {
        if (vocablesAndVocablePanels.size() == 1) {
            displaySingeVocable(vocablesAndVocablePanels.get(0));
        }
        else {
            displayMultipleVocables();
        }
    }

    private void displaySingeVocable(VocableAndVocablePanel vocableAndVocablePanel) {
        Component component = createComponentWithVocableAndDetailButton(vocableAndVocablePanel);
        matchingVocablesPanel.add(component, BorderLayout.CENTER);
    }

    private void displayMultipleVocables() {
        int numerOfVocables = vocablesAndVocablePanels.size();
        int numberOfColumns;
        if (numerOfVocables > 4) {
            numberOfColumns = 3;
        }
        else if (numerOfVocables > 2) {
            numberOfColumns = 2;
        }
        else {
            numberOfColumns = 1;
        }

        List<Component> vocablePanels = new ArrayList<>();
        for (VocableAndVocablePanel vocableAndVocablePanel : vocablesAndVocablePanels) {
            Component component = createComponentWithVocableAndDetailButton(vocableAndVocablePanel);
            vocablePanels.add(component);
        }
        JPanel panel = new MultipleElementsPanel<Component>(vocablePanels, numberOfColumns, 1);
        matchingVocablesPanel.add(panel, BorderLayout.CENTER);
    }

    private Component createComponentWithVocableAndDetailButton(
            VocableAndVocablePanel vocableAndVocablePanel) {
        JPanel panel = new JPanel();
        panel.setLayout(new BorderLayout());

        panel.add(vocableAndVocablePanel.getVocabelPanel(), BorderLayout.CENTER);
        panel.add(createButtonPart(vocableAndVocablePanel.getVocable()), BorderLayout.SOUTH);

        return panel;
    }

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

        panel.add(createDetailsButton(vocable));
        Options options = dataStructures.getOptions();
        if (options.isShowDetailBottomButonsInTranslationEvaluationToo()) {
            ListsWithVocableFinderGui listsWithVocableFinderGui = new ListsWithVocableFinderGui(
                    vocable, dataStructures, getWindowAsComponent());
            VocableToOwnListAdderGui vocableToOwnListAdderGui = new VocableToOwnListAdderGui(
                    vocable, dataStructures, uiObjects, getLocation());
            VerbsAndAdjectivesFinderGui verbsAndAdjectivesFinderGui = new VerbsAndAdjectivesFinderGui(
                    vocable, dataStructures, uiObjects, getLocation(),
                    (LongTimeProcessInformer) this);
            listsWithVocableFinderGui.appendButtonToPanel(panel);
            vocableToOwnListAdderGui.appendButtonToPanel(panel);
            verbsAndAdjectivesFinderGui.appendButtonsToPanel(panel);
        }

        return panel;
    }

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

    private void showDetails(Vocable vocable) {
        VocableWithInternaDialog dialog = new VocableWithInternaDialog(vocable, dataStructures,
                uiObjects, getLocation());
        dialog.setVisible(true);
    }

    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 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 void showDetails() {
        if (matchingVocables.size() == 1) {
            Vocable vocable = matchingVocables.get(0);
            showDetails(vocable);
        }
    }

    private void keybindingsForPlaySound() {
        KeyStroke keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_F9, 0);
        String actionMapKey = "F9";
        Action action = BindKeysOnRootPane.runnableToAction(() -> playMp3());

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

    /** Spielt die zugehörige MP3 ab. */
    private void playMp3() {
        if (!matchingVocables.isEmpty()) {
            Vocable vocable = matchingVocables.get(0);
            String mp3 = vocable.getMp3();
            VocabularyTools.playMp3(mp3);
        }
    }

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

}
