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

import java.awt.BorderLayout;
import java.awt.Component;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JPanel;

import de.duehl.swing.ui.components.MultipleElementsPanel;
import de.duehl.swing.ui.move.data.MovingGui;
import de.duehl.vocabulary.japanese.common.data.VocabularySortOrder;
import de.duehl.vocabulary.japanese.common.persistence.Options;
import de.duehl.vocabulary.japanese.data.FumikoDataStructures;
import de.duehl.vocabulary.japanese.data.OwnList;
import de.duehl.vocabulary.japanese.data.Vocable;
import de.duehl.vocabulary.japanese.data.Vocabulary;
import de.duehl.vocabulary.japanese.logic.VocabularyTrainerLogic;
import de.duehl.vocabulary.japanese.ui.VocabularyTrainerGui;
import de.duehl.vocabulary.japanese.ui.components.bars.VocabularyBar;
import de.duehl.vocabulary.japanese.ui.data.FumikoUiObjects;
import de.duehl.vocabulary.japanese.ui.sort.VocabularyBarSorter;

import static de.duehl.vocabulary.japanese.ui.VocabularyTrainerGui.MAXIMAL_NUMBER_OF_VOCABULARY_PER_COLUMNN;

/**
 * Diese Klasse stellt den Panel mit den Vokabularien einer Unterkategorien (und der übergeordneten
 * Kategorie) dar.
 *
 * @version 1.01     2025-11-20
 * @author Christian Dühl
 */

public class VocabularyPanel implements MovingGui<VocabularyBar> {

    /** Die grafische Oberfläche des Vokabel-Trainers. */
    private final VocabularyTrainerGui gui;

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

    /** Der Panel mit den Vokabularien. */
    private final JPanel vocabularyPanel;

    /** Die Liste der Bars zu den Vokabularien der Kategorie und Unterkategorie. */
    private List<VocabularyBar> vocabularyBars;

    /**
     * Konstruktor.
     *
     * @param vocabulariesOfSubCategory
     *            Die Vokabularien zur Unterkategorie (in der übergeordneten Kategorie).
     * @param logic
     *            Die Logik des Vokabel-Trainers.
     * @param gui
     *            Die grafische Oberfläche des Vokabel-Trainers.
     * @param dataStructures
     *            Die Datenstrukturen des Vokabeltrainers..
     * @param uiObjects
     *            Die häufig verwendeten Funktionen der grafischen Oberfläche des Vokabeltrainers.
     */
    public VocabularyPanel(List<Vocabulary> vocabulariesOfSubCategory, VocabularyTrainerLogic logic,
            VocabularyTrainerGui gui, FumikoDataStructures dataStructures,
            FumikoUiObjects uiObjects) {
        this.gui = gui;
        this.dataStructures = dataStructures;

        vocabularyPanel = new JPanel();

        vocabularyBars = new ArrayList<>();

        for (Vocabulary vocabulary : vocabulariesOfSubCategory) {
            VocabularyBar bar = new VocabularyBar(vocabulary, logic, gui, dataStructures, uiObjects,
                    this);
            vocabularyBars.add(bar);
        }

        init();
        populateVocabularyPanel();
    }

    private void init() {
        vocabularyPanel.setLayout(new BorderLayout());
    }

    private void populateVocabularyPanel() {
        vocabularyPanel.removeAll();

        Options options = dataStructures.getOptions();
        int numberOfVocabularyBarColumns = options.getNumberOfVocabularyBarColumns();

        List<Component> vocabularyBarPanels = new ArrayList<>();
        for (VocabularyBar vocabularyBar : vocabularyBars) {
            Component panel = vocabularyBar.getPanel();
            vocabularyBarPanels.add(panel);
        }

        JPanel panel = new MultipleElementsPanel<Component>(vocabularyBarPanels,
                numberOfVocabularyBarColumns,
                MAXIMAL_NUMBER_OF_VOCABULARY_PER_COLUMNN
                );


        for (VocabularyBar vocabularyBar : vocabularyBars) { // geht nur hinterher!
            vocabularyBar.setUpAndDownButtonColorsAndEnabled();
        }

        vocabularyPanel.add(panel, BorderLayout.CENTER);
    }


    /** Gibt an, ob die übergebene Bar eines Vokabulars nach oben bewegt werden kann. */
    @Override
    public boolean canBarMoveUp(VocabularyBar bar) {
        List<VocabularyBar> barsOfCategory = determineBarsOfCategory(bar.getVocabularyCategory());
        return barsOfCategory.contains(bar)
                && bar != barsOfCategory.get(0);
                // Ja mit !=, es ist wirklich das selbe Objekt!
    }

    /** Gibt an, ob die übergebene Bar eines Vokabulars nach unten bewegt werden kann. */
    @Override
    public boolean canBarMoveDown(VocabularyBar bar) {
        List<VocabularyBar> barsOfCategory = determineBarsOfCategory(bar.getVocabularyCategory());
        return barsOfCategory.contains(bar)
                && bar != barsOfCategory.get(barsOfCategory.size() - 1);
                // Ja mit !=, es ist wirklich das selbe Objekt!
    }

    /** Verschiebt die übergebene Bar eines Vokabulars an die erste Stelle. */
    @Override
    public void moveBarToFirst(VocabularyBar bar) {
        List<VocabularyBar> barsOfCategory = determineBarsOfCategory(bar.getVocabularyCategory());
        VocabularyBar firstBarInCategory = barsOfCategory.get(0);
        int indexOfFirstInCategory = vocabularyBars.indexOf(firstBarInCategory);

        int index = vocabularyBars.indexOf(bar);
        vocabularyBars.remove(index);
        vocabularyBars.add(indexOfFirstInCategory, bar);
        populateVocabularyPanel();

        gui.saveManualVocabularyOrder();
    }

    /** Verschiebt die übergebene Bar eines Vokabulars nach oben. */
    @Override
    public void moveBarUp(VocabularyBar bar) {
        List<VocabularyBar> barsOfCategory = determineBarsOfCategory(bar.getVocabularyCategory());
        int indexInCategory = barsOfCategory.indexOf(bar);
        /*
         * Da der Schalter nur dann benutzbar ist, wenn man auch nach oben verschieben kann, prüfe
         * ich das hier nicht. Ansonsten könnte indexInCategory - 1 natürlich zu klein sein.
         */
        VocabularyBar previousBarInCategory = barsOfCategory.get(indexInCategory - 1);
        int indexOfPreviousInCategory = vocabularyBars.indexOf(previousBarInCategory);

        int index = vocabularyBars.indexOf(bar);
        vocabularyBars.remove(index);
        vocabularyBars.add(indexOfPreviousInCategory, bar);
        populateVocabularyPanel();
        gui.saveManualVocabularyOrder();
    }

    /** Verschiebt die übergebene Bar eines Vokabulars nach unten. */
    @Override
    public void moveBarDown(VocabularyBar bar) {
        List<VocabularyBar> barsOfCategory = determineBarsOfCategory(bar.getVocabularyCategory());
        int indexInCategory = barsOfCategory.indexOf(bar);
        /*
         * Da der Schalter nur dann benutzbar ist, wenn man auch nach unten verschieben kann, prüfe
         * ich das hier nicht. Ansonsten könnte indexInCategory + 1 natürlich zu groß sein.
         */
        VocabularyBar nextBarInCategory = barsOfCategory.get(indexInCategory + 1);
        int indexOfNextInCategory = vocabularyBars.indexOf(nextBarInCategory);

        int index = vocabularyBars.indexOf(bar);
        vocabularyBars.remove(index);
        vocabularyBars.add(indexOfNextInCategory, bar); // da darüber entfernt, entfällt hier + 1
        populateVocabularyPanel();
        gui.saveManualVocabularyOrder();
    }

    /** Verschiebt die übergebene Bar eines Vokabulars an die letzte Stelle. */
    @Override
    public void moveBarToLast(VocabularyBar bar) {
        List<VocabularyBar> barsOfCategory = determineBarsOfCategory(bar.getVocabularyCategory());
        VocabularyBar lastBarInCategory = barsOfCategory.get(barsOfCategory.size() - 1);
        int indexOfLastInCategory = vocabularyBars.indexOf(lastBarInCategory);

        int index = vocabularyBars.indexOf(bar);
        vocabularyBars.remove(index);
        vocabularyBars.add(indexOfLastInCategory, bar); // da darüber entfernt, entfällt hier + 1
        populateVocabularyPanel();
        gui.saveManualVocabularyOrder();
    }

    /** Gibt die angezeigten VocabularyBars zurück. */
    public List<VocabularyBar> getBars() {
        List<VocabularyBar> list = new ArrayList<>();

        for (VocabularyBar bar : vocabularyBars) {
            list.add(bar);
        }

        return list;
    }

    /**
     * Ermittelt die zur übergebenen Kategorie gehörigen VocabularyBars.
     *
     * Die Frage ob man die Bars verschieben kann sowie das Verschieben selbst wird durch die
     * Reiter etwas verkompliziert.
     *
     * Darum wird eine Liste der angezeigten Bars gebildet und in dieser geprüft. Verschoben wird
     * aber natürlich dann in der richtigen Liste!
     *
     * Da darf man dann nicht nur eine Position nach oben oder an die erste Stelle, sondern muss
     * das natürlich unter Berücksichtigung der Position der anderen Bars der gleichen Kategorie
     * tun.
     *
     * @param wantedCategory
     *            Die gewünschte Kategorie.
     * @return Die Liste mit den VocabularyBar, die zur gewünschten Kategorie gehören.
     */
    private List<VocabularyBar> determineBarsOfCategory(String wantedCategory) {
        List<VocabularyBar> actualShownBars = new ArrayList<>();

        for (VocabularyBar vocabularyBar : vocabularyBars) {
            String categoryOfTheBar = vocabularyBar.getVocabularyCategory();
            if (wantedCategory.equals(categoryOfTheBar)) {
                actualShownBars.add(vocabularyBar);
            }
        }

        return actualShownBars;
    }

    /**
     * Setzt die Vordergrundfarbe auf den nach den Optionen und ggf. dem Durchschnitt der
     * erfolgreichen Abfrage der Vokabeln aus dem Vokabular in allen Vokabularien richtig.
     */
    public void setCorrectForegroundColorOfVocabularyBars() {
        for (VocabularyBar bar : vocabularyBars) {
            bar.setCorrectForegroundColor();
        }
    }

    /** Aktualisiert den angezeigten Text in allen Vokabularien je nach den Optionen. */
    public void setCorrectTextOfVocabularyBars() {
        for (VocabularyBar bar : vocabularyBars) {
            bar.setCorrectText();
        }
    }

    /**
     * Aktualisiert den angezeigten Text zum Prozent des Erfolges in allen Vokabularien je nach den
     * Optionen.
     */
    public void showOrHidePercentInVocabularyBars() {
        for (VocabularyBar bar : vocabularyBars) {
            bar.showOrHidePercent();
        }
    }

    /** Zeigt oder versteckt die Buttons zur individuellen Sortierung der Vokabularien. */
    public void showOrHideIndividualVocabularySortModeMoveButtons() {
        for (VocabularyBar vocabularyBar : vocabularyBars) {
            vocabularyBar.showOrHideIndividualVocabularySortModeMoveButtons();
        }
    }

    /**
     * Gibt die Vokabularien in der benutzerdefinierten Reihenfolge zurück.
     *
     * Wird nur aufgerufen, wenn die Vokabularien auch in der individuellen Sortierung angezeigt
     * werden.
     */
    public List<Vocabulary> getVocabularyBarsInIndividualOrder() {
        List<Vocabulary> list = new ArrayList<>();

        for (VocabularyBar bar : vocabularyBars) {
            list.add(bar.getVocabulary());
        }

        return list;
    }

    /**
     * Gibt die OwnLists in der benutzerdefinierten Reihenfolge zurück.
     *
     * Wird nur aufgerufen, wenn die Vokabularien auch in der individuellen Sortierung angezeigt
     * werden.
     */
    public List<OwnList> getOwnListsInIndividualOrder() {
        List<OwnList> list = new ArrayList<>();

        for (VocabularyBar bar : vocabularyBars) {
            list.add(bar.getVocabularyAsOwnList());
        }

        return list;
    }

    /** Ermittelt die Liste der Vokabeln aus den ausgewählten Vokabularien. */
    public List<Vocable> collectVocablesOfSelectedVocabularies() {
        List<Vocable> vocables = new ArrayList<>();

        for (VocabularyBar bar : vocabularyBars) {
            if (bar.isSelected()) {
                Vocabulary vocabulary = bar.getVocabulary();
                vocables.addAll(vocabulary.getVocables());
            }
        }

        return vocables;
    }

    /** Sortiert die angezeigten Vokabularien so, wie es in den Optionen eingetragen ist. */
    public void showVocabularyBarsInWantedOrder() {
        Options options = dataStructures.getOptions();
        VocabularySortOrder sortOrder = options.getVocabularySortOrder();

        VocabularyBarSorter sorter = new VocabularyBarSorter(vocabularyBars, sortOrder);
        sorter.sort();

        populateVocabularyPanel();
    }

    /** Der Panel mit den Vokabularien. */
    public JPanel getVocabularyPanel() {
        return vocabularyPanel;
    }

    /**
     * Zeigt auf dem Übersetzen-Buttons aller Bars das richtige Icon für die Richtung der
     * Übersetzung an.
     */
    public void showTranslationDirectionOnBarButtons() {
        for (VocabularyBar vocabularyBar : vocabularyBars) {
            vocabularyBar.showTranslationDirectionOnBarButtons();
        }
    }

    /** Buttons zum Exportieren, Bearbeiten und Löschen von eigene Listen ein oder ausschalten. */
    public void toggleShowOwnListButtons() {
        for (VocabularyBar vocabularyBar : vocabularyBars) {
            vocabularyBar.toggleShowOwnListButtons();
        }
    }

    /** Zeigt die normalen Button zum Abfragen und betrachten der Vokabularien an. */
    public void showTestViewListSheetButtons() {
        for (VocabularyBar vocabularyBar : vocabularyBars) {
            vocabularyBar.showTestViewListSheetButtons();
        }
    }

    /** Zeigt bei eigenen Listen die Buttons zum Löschen, Bearbeiten und Exportieren an. */
    public void showOwnListExtraButtons() {
        for (VocabularyBar vocabularyBar : vocabularyBars) {
            vocabularyBar.showOwnListExtraButtons();
        }
    }

}
