package de.duehl.vocabulary.japanese.ui.components;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.util.List;
import java.util.Random;

import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JTextPane;
import javax.swing.SwingUtilities;

import de.duehl.basics.io.FileHelper;
import de.duehl.swing.ui.buttons.painted.GoButton;
import de.duehl.swing.ui.components.selections.StringSelection;
import de.duehl.swing.ui.components.selections.tools.SelectionsHelper;
import de.duehl.swing.ui.layout.VerticalLayout;
import de.duehl.vocabulary.japanese.common.color.VocableColors;
import de.duehl.vocabulary.japanese.common.data.InternalAdditionalVocableData;
import de.duehl.vocabulary.japanese.common.data.TranslationDirection;
import de.duehl.vocabulary.japanese.common.persistence.Options;
import de.duehl.vocabulary.japanese.data.Vocable;
import de.duehl.vocabulary.japanese.data.symbol.Hiragana;
import de.duehl.vocabulary.japanese.tools.VocabularyTools;
import de.duehl.vocabulary.japanese.ui.components.data.VocableTestReactor;
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;

/**
 * Diese Klasse fragt eine Vokabel ab.
 *
 * @version 1.01     2025-07-15
 * @author Christian Dühl
 */

public class VocableTester {

    /** Das Objekt das auf die Eingabe der Übersetzung durch den Benutzer reagiert. */
    private final VocableTestReactor vocableTestReactor;

    /** Die Programmoptionen. */
    private final Options options;

    /** Der Panel auf dem die Vokabel dargestellt wird. */
    private final JPanel panel;

    /**
     * Die TextPane für die Übersetzung von Japanisch in Deutsch in der die Kanji und Kana
     * dargestellt werden.
     */
    private final JTextPane kanjiAndKanaPane;

    /**
     * Die TextPane für die Übersetzung von Japanisch in Deutsch in der die Romaji und Aussprache
     * dargestellt werden.
     */
    private final JTextPane romajiAndPronunciationPane;

    /**
     * Die TextPane für die Übersetzung von Japanisch in Deutsch in der die Übersetzungen, den
     * Kommentar und die Beschreibung des Vokabulars dargestellt werden.
     */
    private final JTextPane commentAndVocabularyDescriptionPane;

    /**
     * Die TextPane für die Übersetzung von Deutsch in Japanisch mit dem deutschen Begriff.
     */
    private final StringSelection germanToJapaneseSelection;

    /** Eingabe für die Übersetzung des Benutzers. */
    private final StringSelection translationSelection;

    /** Der Button zum Abspielen der japanischen Aussprache. */
    private final GoButton playMp3Button;

    /** Der Button zum Abschicken der Übersetzung. */
    private final JButton okButton;

    /** Für die Auswahl einer zufälligen Übersetzung. */
    private final Random random;

    /** Die Vokabel, welche abgefragt wird. */
    private Vocable vocable;

    /** Der abgefragte deutsche Begriff, wenn von Deutsch nach Japanisch übersetzt wird. */
    private String germanTerm;

    /** Gibt an, ob der Benutzer die Vokabel bereits übersetzt hat. */
    private boolean translated;

    /** Gibt an, ob die letzte Vokabel angezeigt wird. */
    private boolean lastVocable;

    /** Die zu verwendende Hintergrundfarbe. */
    private Color backgroundColor;

    /**
     * Konstruktor.
     *
     * @param vocableTestReactor
     *            Das Objekt das auf die Eingabe der Übersetzung durch den Benutzer reagiert.
     * @param options
     *            Die Programmoptionen.
     */
    public VocableTester(VocableTestReactor vocableTestReactor, Options options) {
        this.vocableTestReactor = vocableTestReactor;
        this.options = options;

        panel = new JPanel();
        kanjiAndKanaPane = new JTextPane();
        romajiAndPronunciationPane = new JTextPane();
        commentAndVocabularyDescriptionPane = new JTextPane();
        germanToJapaneseSelection = new StringSelection("Deutscher Begriff");
        translationSelection = new StringSelection("Übersetzung");
        playMp3Button = new GoButton();
        okButton = new JButton("Übersetzung abschicken");

        random = new Random();

        initSelections();
        createPanel();
    }

    private void initSelections() {
        SelectionsHelper.initSelectionAsEditor(translationSelection);

        playMp3Button.addActionListener(e -> playMp3());
        playMp3Button.setForceSquare(true);
        playMp3Button.setPreferredSize(new Dimension(50, 50));

        SelectionsHelper.initSelectionAsEditor(germanToJapaneseSelection);
        germanToJapaneseSelection.biggerText(5);

        translationSelection.addReturnListener(() -> userEnteredTranslation());
        okButton.addActionListener(e -> okButtonPressed());

        requestFocusInTranslationField();
    }

    private void requestFocusInTranslationField() {
        SwingUtilities.invokeLater(() -> translationSelection.requestFocus());
    }

    private void createPanel() {
        panel.setLayout(new VerticalLayout(0, VerticalLayout.BOTH));

        TranslationDirection translationDirection = options.getTranslationDirection();
        if (translationDirection == TranslationDirection.JAPANESE_TO_GERMAN) {
            panel.add(createKanjiKanaAndMp3PlayButtonArea());
            panel.add(romajiAndPronunciationPane);
            panel.add(commentAndVocabularyDescriptionPane);
        }
        else if (translationDirection == TranslationDirection.GERMAN_TO_JAPANESE){
            panel.add(germanToJapaneseSelection.getPanel());
        }
        else {
            throw new RuntimeException("Unbekannte Abfragerichtung " + translationDirection);
        }
        panel.add(translationSelection.getPanel());
        panel.add(okButton);
    }

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

        panel.add(kanjiAndKanaPane, BorderLayout.CENTER);
        panel.add(playMp3Button, BorderLayout.EAST);

        return panel;
    }

    /** Getter für den Panel auf dem die Vokabel dargestellt wird. */
    public Component getPanel() {
        return panel;
    }

    /** Zeigt eine neue Variable an. */
    public void showVocable(Vocable vocable, InternalAdditionalVocableData data,
            boolean lastVocable) {
        this.vocable = vocable;
        this.lastVocable = lastVocable;

        VocableColors vocableColors = new VocableColors(options);
        backgroundColor = vocableColors.determineBackgroundColor(data,
                options.isColorVocableDependingOnLastSuccessWhenTestingVocable(),
                options.getTranslationDirection());

        TranslationDirection translationDirection = options.getTranslationDirection();
        if (translationDirection == TranslationDirection.JAPANESE_TO_GERMAN) {
            showJapaneseToGermanVocable();
        }
        else if (translationDirection == TranslationDirection.GERMAN_TO_JAPANESE){
            showGermanToJapaneseVocable();
        }
        else {
            throw new RuntimeException("Unbekannte Abfragerichtung " + translationDirection);
        }

        translationSelection.setEditable(true);
        translationSelection.setText("");

        okButton.setText("Übersetzung abschicken");

        translated = false;
        panel.repaint();

        if (options.isPlayMP3WhenTestingVocables()
                && translationDirection == TranslationDirection.JAPANESE_TO_GERMAN) {
            playMp3();
        }
    }

    private void showJapaneseToGermanVocable() {
        displayKanjiAndKana();
        displayRomajiAndPronunciation();
        displayTranslationCommentAndVocabularyDescription();
        modifyMp3Button();
    }

    private void displayKanjiAndKana() {
        KanjiAndKanaDisplay display = new KanjiAndKanaDisplay(vocable, kanjiAndKanaPane,
                backgroundColor, options);

        if (!options.isShowKanaWhenTestingVocable()) {
            display.hideKana();
        }
        if (options.isShowKanaInKanjiSizeWhenTestingVocable()) {
            display.showKanaInKanjiSize();
        }

        if (options.isShowKanjiWhenTestingVocable()) {
            if (options.isHideKanjiWhenTestingVocableAndKanaContainsOnlyHiragana()
                    && Hiragana.containsOnlyHiragana(vocable.getKana())) {
                display.hideKanji();
            }
        }
        else {
            display.hideKanji();
        }

        display.display();
    }

    private void displayRomajiAndPronunciation() {
        RomajiAndPronunciationDisplay display = new RomajiAndPronunciationDisplay(vocable,
                romajiAndPronunciationPane, backgroundColor, options);

        if (options.isShowRomajiWhenTestingVocable()) {
            if (options.isHideRomajiWhenTestingVocableAndKanaContainsOnlyHiragana()
                    && Hiragana.containsOnlyHiragana(vocable.getKana())) {
                display.hideRomaji();
            }
        }
        else {
            display.hideRomaji();
        }

        if (options.isShowPronunciationWhenTestingVocable()) {
            if (options.isHidePronunciationWhenTestingVocableAndKanaContainsOnlyHiragana()
                    && Hiragana.containsOnlyHiragana(vocable.getKana())) {
                display.hidePronunciation();
            }
        }
        else {
            display.hidePronunciation();
        }

        display.display();
    }

    private void displayTranslationCommentAndVocabularyDescription() {
        TranslationCommentAndVocabularyDescriptionDisplay display =
                new TranslationCommentAndVocabularyDescriptionDisplay(vocable,
                        commentAndVocabularyDescriptionPane, backgroundColor, options);
        display.hideTranslations();
        if (!options.isShowCommentWhenTestingVocable()) {
            display.hideComment();
        }
        if (!options.isShowVocabularyDescriptionWhenTestingVocable()) {
            display.hideVocabularyDescription();
        }
        display.display();
    }

    private void modifyMp3Button() {
        playMp3Button.setBackgroundColor(backgroundColor);
        String mp3 = vocable.getMp3();
        playMp3Button.setEnabled(!mp3.isBlank() && FileHelper.isFile(mp3));
    }

    private void showGermanToJapaneseVocable() {
        germanTerm = createGermanTerm(vocable);
        germanToJapaneseSelection.setText(germanTerm);
        germanToJapaneseSelection.setBackgroundColor(backgroundColor);

        playMp3Button.setEnabled(false); // auch wenn er gar nicht angezeigt wird.
    }

    /**
     * Erzeugt aus einer in der Richtung Deutsch zu Japanisch abzufragenden Vokabel den
     * abzufragenden deutschen Begriff.
     *
     * @param vocable
     *            Die Vokabel die man abfragen möchte.
     */
    private String createGermanTerm(Vocable vocable) {
        List<String> translations = vocable.getTranslations();
        if (translations.isEmpty()) {
            throw new RuntimeException("Die Vokabel hat keine deutschen Übersetzungen!\n"
                    + vocable.toNiceString(4));
        }
        if (options.isUseOnlyFirstGermanTermWhenTestingVocableGermanToJapanese()) {
            return translations.get(0);
        }
        else {
            int index = random.nextInt(translations.size());
            return translations.get(index);
        }
    }

    private void okButtonPressed() {
        userEnteredTranslation();
        requestFocusInTranslationField();
    }

    private void userEnteredTranslation() {
        if (!translated) {
            handleUserEnteredTranslation();
        }
    }

    private void handleUserEnteredTranslation() {
        String translationByUser = translationSelection.getTrimmedText();

        if (!translationByUser.isBlank()
                || vocableTestReactor.doWeHaveToReactOnEmptyTranslation()) {
            translated = true;
            translationSelection.setEditable(false);

            if (lastVocable) {
                okButton.setText("Ende");
                okButton.setEnabled(false);
            }
            else {
                okButton.setText("weiter zur nächsten Vokabel");
            }

            userEnteredTranslation(translationByUser);
        }
    }

    private void userEnteredTranslation(String translationByUser) {
        TranslationDirection translationDirection = options.getTranslationDirection();
        if (translationDirection == TranslationDirection.JAPANESE_TO_GERMAN) {
            userEnteredJapaneseToGermanTranslation(translationByUser);
        }
        else if (translationDirection == TranslationDirection.GERMAN_TO_JAPANESE){
            userEnteredGermanToJapaneseTranslation(translationByUser);
        }
        else {
            throw new RuntimeException("Unbekannte Abfragerichtung " + translationDirection);
        }
    }

    private void userEnteredJapaneseToGermanTranslation(String translationByUser) {
        String kana = vocable.getKana();

        String kanji = determineKanjiToTest();

        vocableTestReactor.userEnteredJapaneseToGermanTranslation(kana, kanji,
                translationByUser);
    }

    private String determineKanjiToTest() {
        if (options.isShowKanjiWhenTestingVocable()) {
            String kana = vocable.getKana();
            if (options.isHideKanjiWhenTestingVocableAndKanaContainsOnlyHiragana()
                    && Hiragana.containsOnlyHiragana(kana)) {

                return "";
            }
            else {
                return vocable.getKanji();
            }
        }
        else {
            return "";
        }
    }

    private void userEnteredGermanToJapaneseTranslation(String translationByUser) {
        vocableTestReactor.userEnteredGermanToJapaneseTranslation(germanTerm,
                translationByUser);
    }

    /** Spielt die zugehörige MP3 ab. */
    public void playMp3() {
        String mp3 = vocable.getMp3();
        VocabularyTools.playMp3(mp3);
        requestFocusInTranslationField();
    }

    public void disable() {
        translationSelection.setEnabled(false);
        okButton.setEnabled(false);
    }

}
