package de.duehl.vocabulary.japanese.ui.dialog.vocables.detail;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.GridLayout;
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.JScrollPane;
import javax.swing.KeyStroke;

import de.duehl.basics.collections.CollectionsHelper;
import de.duehl.basics.datetime.date.ImmutualDate;
import de.duehl.basics.text.Text;
import de.duehl.swing.logic.LongTimeProcessInformer;
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.AbstractDialogBase;
import de.duehl.swing.ui.key.BindKeysOnRootPane;
import de.duehl.swing.ui.layout.VerticalLayout;
import de.duehl.vocabulary.japanese.common.data.InternalAdditionalVocableData;
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.data.symbol.Kanji;
import de.duehl.vocabulary.japanese.logic.internal.InternalDataRequester;
import de.duehl.vocabulary.japanese.tools.VocabularyTools;
import de.duehl.vocabulary.japanese.ui.components.VocableViewer;
import de.duehl.vocabulary.japanese.ui.data.FumikoUiObjects;
import de.duehl.vocabulary.japanese.ui.dialog.kanji.detail.KanjiDetailDialog;
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 eine Vokabel mit den zugehörigen benutzerabhängigen Daten auf einem Panel an.
 *
 * @version 1.01     2025-11-21
 * @author Christian Dühl
 */

class VocableWithInternaPanel {

    static final Dimension DIALOG_DIMENSION = new Dimension(1000, 900);


    /** Der Frame oder Dialog, der diesen Panel anzeigt. */
    private final AbstractDialogBase usingComponent;

    /** Die anzuzeigende Vokabel. */
    private final Vocable vocable;

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

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

    /** Die internen Daten zur übergebenen Vokabel. */
    private final InternalAdditionalVocableData data;

    /**
     * Der Panel, auf dem die Vokabel mit ihren den zugehörigen benutzerabhängigen Daten
     * dargestellt wird.
     */
    private final JPanel panel;

    /**
     * Kann einen Button anlegen, um zur angezeigten Vokabel alle eigenen Listen anzuzeigen, welche
     * die Vokabel enthalten.
     */
    private final ListsWithVocableFinderGui listsWithVocableFinderGui;

    /** Kann einen Button anlegen, um die angezeigte Vokabel zu einer eigenen Liste hinzuzufügen. */
    private final VocableToOwnListAdderGui vocableToOwnListAdderGui;

    /**
     * Kann Buttons anlegen, um zur angezeigten Vokabel gehörige Verb- und Adjektivformen zu
     * finden.
     */
    private final VerbsAndAdjectivesFinderGui verbsAndAdjectivesFinderGui;

    /** Die Liste der in der Vokabel vorkommenden Kanji. */
    private List<Kanji> kanjiInVocable;

    /**
     * Konstruktor.
     *
     * @param usingComponent
     *            Der Frame oder Dialog, der diesen Panel anzeigt.
     * @param vocable
     *            Die anzuzeigende Vokabel.
     * @param dataStructures
     *            Die Datenstrukturen des Vokabeltrainers.
     * @param uiObjects
     *            Die häufig verwendeten Funktionen der grafischen Oberfläche des Vokabeltrainers.
     * @param thisPanelUsingDialog
     *            Der modale oder nicht modale Dialog bzw., Frame, der diesen Panel nutzt.
     * @param longTimeProcessInformer
     *            Die Oberfläche, welche diese Klasse aufruft, auf der man eine GlassPane anzeigen
     *            kann.
     */
    public VocableWithInternaPanel(AbstractDialogBase usingComponent, Vocable vocable,
            FumikoDataStructures dataStructures, FumikoUiObjects uiObjects,
            Component thisPanelUsingDialog, LongTimeProcessInformer longTimeProcessInformer) {
        this.usingComponent = usingComponent;
        this.vocable = vocable;
        this.dataStructures = dataStructures;
        this.uiObjects = uiObjects;

        listsWithVocableFinderGui = new ListsWithVocableFinderGui(vocable, dataStructures,
                thisPanelUsingDialog);
        vocableToOwnListAdderGui = new VocableToOwnListAdderGui(vocable, dataStructures, uiObjects,
                usingComponent.getLocation());
        verbsAndAdjectivesFinderGui = new VerbsAndAdjectivesFinderGui(vocable, dataStructures,
                uiObjects, usingComponent.getLocation(), longTimeProcessInformer);

        InternalDataRequester requester = dataStructures.getInternalDataRequester();
        data = requester.getInternalDataForVocable(vocable);
        panel = new JPanel();

        init();
        fillPanel();
    }

    private void init() {
        determineKanjiInVocable();
    }

    private void determineKanjiInVocable() {
        kanjiInVocable = new ArrayList<>();
        kanjiInVocable.addAll(Kanji.getAllKanjiFromText(vocable.getKanji()));
        kanjiInVocable.addAll(Kanji.getAllKanjiFromText(vocable.getComment()));
        CollectionsHelper.makeListDisjunct(kanjiInVocable);
    }

    /** Baut die Gui auf. */
    private void fillPanel() {
        panel.setLayout(new BorderLayout());

        JScrollPane scroll = GuiTools.createScrollPane(createMainPanel());
        panel.add(scroll, BorderLayout.CENTER);
        panel.add(createLowerPart(), BorderLayout.SOUTH);

        GuiTools.scrollScrollbarToMinimumLater(scroll);
        keybindingsForPlaySound();
    }

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

        panel.add(createVocableViewerPart(), BorderLayout.NORTH);
        panel.add(createVocableAndInternalDataSectionPart(), BorderLayout.CENTER);

        return panel;
    }

    private Component createVocableViewerPart() {
        Options options = dataStructures.getOptions();
        InternalDataRequester requester = dataStructures.getInternalDataRequester();
        VocableViewer viewer = new VocableViewer(options);
        viewer.showAllTranslationsForUseInDetailsDialog();
        viewer.showVocable(vocable, requester.getInternalDataForVocable(vocable));
        return viewer.getPanel();
    }

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

        panel.add(createKanaPart());
        panel.add(createKanjiPart());
        panel.add(createRomajiPart());
        panel.add(createPronunciationPart());
        panel.add(createTranslationsPart());
        panel.add(createCommentPart());
        panel.add(createSearchWordsPart());
        panel.add(createPartsOfSpeechPart());
        panel.add(createVocabularyDescriptionPart());
        panel.add(createFirstSeenDatePart());
        panel.add(createJapaneseToGermanTestCountPart());
        panel.add(createCorrectJapaneseToGermanTestCountPart());
        panel.add(createLastJapaneseToGermanTestDatePart());
        panel.add(createLastCorrectJapaneseToGermanTestDatePart());
        panel.add(createLastTenJapaneseToGermanTestResultsPart());
        panel.add(createGermanToJapaneseTestCountPart());
        panel.add(createCorrectGermanToJapaneseTestCountPart());
        panel.add(createLastGermanToJapaneseTestDatePart());
        panel.add(createLastCorrectGermanToJapaneseTestDatePart());
        panel.add(createLastTenGermanToJapaneseTestResultsPart());

        return panel;
    }

    private Component createKanaPart() {
        return createSingleStringPart("Kana", vocable.getKana());
    }

    private Component createKanjiPart() {
        return createSingleStringPart("Kanji", vocable.getKanji());
    }

    private Component createRomajiPart() {
        return createSingleStringPart("Romaji", vocable.getRomaji());
    }

    private Component createPronunciationPart() {
        return createSingleStringPart("Aussprache", vocable.getPronunciation());
    }

    private Component createTranslationsPart() {
        List<String> translations = vocable.getTranslations();
        return createListPart("Übersetzung", "Übersetzungen", translations);
    }

    private Component createCommentPart() {
        return createSingleLongStringPart("Kommentar", vocable.getComment());
    }

    private Component createSearchWordsPart() {
        List<String> searchWords = vocable.getSearchWords();
        return createListPart("Suchbegriff", "Suchbegriffe", searchWords);
    }

    private Component createPartsOfSpeechPart() {
        List<String> partsOfSpeach = vocable.getPartsOfSpeech();
        return createListPart("Wortart", "Wortarten", partsOfSpeach);
    }

    private Component createVocabularyDescriptionPart() {
        return createSingleStringPart("Beschreibung des Vokabulars",
                vocable.getVocabularyDescription());
    }

    private Component createFirstSeenDatePart() {
        return createDatePart("Zuerst gesehen am", data.getFirstSeenDate());
    }

    private Component createJapaneseToGermanTestCountPart() {
        return createIntPart("Anzahl der Übersetzungen Japanisch - Deutsch",
                data.getJapaneseToGermanTestCount());
    }

    private Component createCorrectJapaneseToGermanTestCountPart() {
        return createIntPart("Anzahl der richtigen Übersetzungen Japanisch - Deutsch",
                data.getCorrectJapaneseToGermanTestCount());
    }

    private Component createLastJapaneseToGermanTestDatePart() {
        return createDatePart("Zuletzt abgefragt Japanisch - Deutsch",
                data.getLastJapaneseToGermanTestDate());
    }

    private Component createLastCorrectJapaneseToGermanTestDatePart() {
        return createDatePart("Zuletzt abgefragt und richtig beantwortet Japanisch - Deutsch",
                data.getLastCorrectJapaneseToGermanTestDate());
    }

    private Component createLastTenJapaneseToGermanTestResultsPart() {
        return createSingleStringPart("Erfolg der letzten 10 Abfragen Japanisch - Deutsch",
                data.getLastTenJapaneseToGermanTestResultsAsStorageString());
    }

    private Component createGermanToJapaneseTestCountPart() {
        return createIntPart("Anzahl der Übersetzungen Deutsch - Japanisch",
                data.getGermanToJapaneseTestCount());
    }

    private Component createCorrectGermanToJapaneseTestCountPart() {
        return createIntPart("Anzahl der richtigen Übersetzungen Deutsch - Japanisch",
                data.getCorrectGermanToJapaneseTestCount());
    }

    private Component createLastGermanToJapaneseTestDatePart() {
        return createDatePart("Zuletzt abgefragt Deutsch - Japanisch",
                data.getLastGermanToJapaneseTestDate());

    }

    private Component createLastCorrectGermanToJapaneseTestDatePart() {
        return createDatePart("Zuletzt abgefragt und richtig beantwortet Deutsch - Japanisch",
                data.getLastCorrectGermanToJapaneseTestDate());
    }

    private Component createLastTenGermanToJapaneseTestResultsPart() {
        return createSingleStringPart("Erfolg der letzten 10 Abfragen Deutsch - Japanisch",
                data.getLastTenGermanToJapaneseTestResultsAsStorageString());
    }

    private Component createSingleStringPart(String title, String value) {
        StringSelection selection = new StringSelection(title);
        SelectionsHelper.initSelectionAsViewer(selection);
        selection.setFocusable(true);
        selection.setText(value);
        return selection.getPanel();
    }

    private Component createSingleLongStringPart(String title, String value) {
        String brokenText = Text.addLineBreaks(value, 60);
        List<String> lines = Text.splitByLineBreaks(brokenText);
        int numberOfLines = lines.size();
        if (numberOfLines == 1) {
            return createSingleStringPart(title, lines.get(0));
        }
        else {
            TextAreaSelection selection = new TextAreaSelection(title);
            SelectionsHelper.initSelectionAsViewer(selection);
            selection.setFocusable(true);
            selection.setText(brokenText);
            selection.setRows(numberOfLines);
            return selection.getPanel();
        }
    }

    private Component createListPart(String titleForOneElement, String titleForMoreElements,
            List<String> values) {
        if (values.size() == 1) {
            return createSingleStringPart(titleForOneElement, values.get(0));
        }
        else {
            TextAreaSelection selection = new TextAreaSelection(titleForMoreElements);
            SelectionsHelper.initSelectionAsViewer(selection);
            selection.setFocusable(true);
            selection.setText(Text.joinWithLineBreak(values));
            return selection.getPanel();
        }
    }

    private Component createDatePart(String title, ImmutualDate date) {
        String value;
        if (date.equals(InternalAdditionalVocableData.NOT_SEEN_DATE)) {
            value = "";
        }
        else {
            value = date.toString();
        }
        return createSingleStringPart(title, value);
    }

    private Component createIntPart(String title, int value) {
        return createSingleStringPart(title, Integer.toString(value));
    }

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

        if (!kanjiInVocable.isEmpty()) {
            panel.add(createKanjiButtonsPart());
        }
        listsWithVocableFinderGui.appendButtonToPanel(panel);
        vocableToOwnListAdderGui.appendButtonToPanel(panel);
        verbsAndAdjectivesFinderGui.appendButtonsToPanel(panel);
        panel.add(createButtonsPart());

        return panel;
    }

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

        for (JButton kanjiButton : createKanjiButtons()) {
            panel.add(kanjiButton);
        }

        return panel;
    }

    private List<JButton> createKanjiButtons() {
        List<JButton> kanjiButtons = new ArrayList<>();

        for (Kanji kanji : kanjiInVocable) {
            JButton button = createKanjiButton(kanji);
            kanjiButtons.add(button);
        }

        return kanjiButtons;
    }

    private JButton createKanjiButton(Kanji kanji) {
        JButton button = new JButton(kanji.getCharacter());
        button.addActionListener(e -> showKanji(kanji));
        return button;
    }

    private void showKanji(Kanji kanji) {
        KanjiDetailDialog dialog = new KanjiDetailDialog(kanji, dataStructures, uiObjects,
                usingComponent, usingComponent.getLocation());
        dialog.setVisible(true);
    }

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

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

        return panel;
    }

    private Component createPlaySoundKeyCombinationLabel() {
        JLabel label = new JLabel("Abspielen mit F9");
        label.setBorder(BorderFactory.createEmptyBorder(0,  5,  0,  5));
        return label;
    }

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

        JRootPane rootPane = usingComponent.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() {
        String mp3 = vocable.getMp3();
        VocabularyTools.playMp3(mp3);
    }

    private Component createQuitButton() {
        JButton button = new JButton("Beenden");
        button.addActionListener(e -> quit());
        return button;
    }

    private void quit() {
        usingComponent.closeDialog();
    }

    /**
     * Getter für den Panel, auf dem die Vokabel mit ihren den zugehörigen benutzerabhängigen Daten
     * dargestellt wird.
     */
    public JPanel getPanel() {
        return panel;
    }

}
