package de.duehl.vocabulary.japanese.ui.dialog.kanji.kanjitest;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.Point;
import java.util.List;

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

import de.duehl.basics.text.NumberString;
import de.duehl.basics.text.Text;
import de.duehl.swing.ui.GuiTools;
import de.duehl.swing.ui.components.selections.StringSelection;
import de.duehl.swing.ui.components.selections.tools.SelectionsHelper;
import de.duehl.swing.ui.dialogs.base.ModalDialogBase;
import de.duehl.swing.ui.layout.VerticalLayout;
import de.duehl.vocabulary.japanese.common.data.InternalAdditionalKanjiData;
import de.duehl.vocabulary.japanese.common.persistence.Options;
import de.duehl.vocabulary.japanese.data.FumikoDataStructures;
import de.duehl.vocabulary.japanese.data.symbol.Kanji;
import de.duehl.vocabulary.japanese.logic.symbol.kanji.internal.InternalKanjiDataRequester;
import de.duehl.vocabulary.japanese.logic.symbol.kanji.test.KanjiTestChecker;
import de.duehl.vocabulary.japanese.logic.symbol.kanji.test.data.SingleUserInputKanjiCheckResult;
import de.duehl.vocabulary.japanese.tools.VocabularyTools;
import de.duehl.vocabulary.japanese.ui.data.FumikoUiObjects;
import de.duehl.vocabulary.japanese.ui.data.MessageSetter;
import de.duehl.vocabulary.japanese.ui.dialog.kanji.display.KanjiPanel;
import de.duehl.vocabulary.japanese.ui.tools.VocabularyTrainerUiTools;

/**
 * Diese Klasse fragt ein Kanji nach dem anderen ab: Das Symbol wird angezeigt und der Benutzer
 * kann deutsche Bedeutungen sowie ON- und kun-Lesungen eingeben.
 *
 * Anhand der in den Kanji-Enum-Objekten wird dann überprüft, ob (ausreichend viel) eingegeben
 * wurde und im Dialog zur Bewertung der einen Abfrage werden alle Daten zu dem Kanji angezeigt.
 *
 * @version 1.01     2026-06-25
 * @author Christian Dühl
 */

public class KanjiTester extends ModalDialogBase {

    private static final Dimension DIALOG_DIMENSION = new Dimension(900, 800);


    /** Die Liste der abzufragenden Kanji. */
    private final List<Kanji> kanjiToTest;

    /** Eine Beschreibung der abgefragten Kanji. */
    private final String kanjiToTestDescription;

    /**
     * Gibt an, ob bei der Überprüfung der deutschen Bedeutung auf Groß-/Kleinschreibung geachtet
     * werden soll.
     */
    private final boolean germanMeaningCaseSensitivity;

    /**
     * Gibt an, ob bei der Überprüfung der ON-Lesung auf Groß-/Kleinschreibung geachtet werden
     * soll.
     */
    private final boolean onLesungCaseSensitivity;

    /**
     * Gibt an, ob bei der Überprüfung der kun-Lesung auf Groß-/Kleinschreibung geachtet werden
     * soll.
     */
    private final boolean kunLesungCaseSensitivity;

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

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

    /** Erzeugt die Komponente, die das Kanji groß dargestellt. */
    private final KanjiPanel kanjiPanel;

    /** Das Eingabefeld für die Deutsche Bedeutung. */
    private final StringSelection germanMeaningTextField;

    /** Das Eingabefeld für die ON-Lesung. */
    private final StringSelection onLesungTextField;

    /** Das Eingabefeld für die kun-Lesung. */
    private final StringSelection kunLesungTextField;

    /** Der Index des angezeigten Kanji. */
    private int shownKanjiIndex;

    /** Die Anzahl der abgefragten Kanji. */
    private int tested;

    /** Die Anzahl der richtig abgefragten Kanji. */
    private int correctTested;

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

    /**
     * Die Prozentzahl des Erfolgs der letzten zehn Abfragen dieser Kanji bevor der aktuelle
     * Test gelaufen ist.
     */
    private final double lastTenTestsPercentBefore;

    private final StringSelection numberOfKanjiSelection;
    private final StringSelection numberOfDoneKanjiSelection;
    private final StringSelection numberOfCorrectDoneKanjiSelection;
    private final StringSelection correctDonePercentKanjiSelection;

    /**
     * Konstruktor.
     *
     * @param kanjiToTest
     *            Die Liste der abzufragenden Kanji.
     * @param kanjiToTestDescription
     *            Eine Beschreibung der abgefragten Kanji.
     * @param germanMeaningCaseSensitivity
     *            Gibt an, ob bei der Überprüfung der deutschen Bedeutung auf Groß-/Kleinschreibung
     *            geachtet werden soll.
     * @param onLesungCaseSensitivity
     *            Gibt an, ob bei der Überprüfung der ON-Lesung auf Groß-/Kleinschreibung geachtet
     *            werden soll.
     * @param kunLesungCaseSensitivity
     *            Gibt an, ob bei der Überprüfung der kun-Lesung auf Groß-/Kleinschreibung geachtet
     *            werden soll.
     * @param dataStructures
     *            Die Datenstrukturen des Vokabeltrainers.
     * @param uiObjects
     *            Die häufig verwendeten Funktionen der grafischen Oberfläche des Vokabeltrainers.
     * @param parentLocation
     *            Die Position des Rahmens der Oberfläche, vor der dieser Dialog erzeugt wird.
     */
    public KanjiTester(List<Kanji> kanjiToTest, String kanjiToTestDescription,
            boolean germanMeaningCaseSensitivity, boolean onLesungCaseSensitivity,
            boolean kunLesungCaseSensitivity, FumikoDataStructures dataStructures,
            FumikoUiObjects uiObjects, Point parentLocation) {
        super(parentLocation, uiObjects.getProgramImage(), "Kanji-Test - " + kanjiToTestDescription,
                DIALOG_DIMENSION);
        this.kanjiToTest = kanjiToTest;
        this.kanjiToTestDescription = kanjiToTestDescription;
        this.germanMeaningCaseSensitivity = germanMeaningCaseSensitivity;
        this.onLesungCaseSensitivity = onLesungCaseSensitivity;
        this.kunLesungCaseSensitivity = kunLesungCaseSensitivity;
        this.dataStructures = dataStructures;
        this.uiObjects = uiObjects;

        germanMeaningTextField = new StringSelection("Deutsche Bedeutung");
        onLesungTextField = new StringSelection("ON-Lesung");
        kunLesungTextField = new StringSelection("kun-Lesung");

        kanjiPanel = new KanjiPanel();
        kanjiPanel.setAfterFontButtonPressedRunnable(
                () -> germanMeaningTextField.requestFocusLater());

        quitButton = new JButton("");

        lastTenTestsPercentBefore = VocabularyTrainerUiTools.createLastTenKanjiTestsPercent(
                kanjiToTest, dataStructures);

        numberOfKanjiSelection = new StringSelection("Anzahl abzufragender Kanji");
        numberOfDoneKanjiSelection = new StringSelection("Anzahl bereits abgefragte Kanji");
        numberOfCorrectDoneKanjiSelection = new StringSelection(
                "Anzahl korrekt beantworteter Kanji");
        correctDonePercentKanjiSelection = new StringSelection(
                "Prozent korrekt beantworteter Kanji");

        init();
        fillDialog();
    }

    private void init() {
        tested = 0;
        correctTested = 0;

        initStringSelections();

        shownKanjiIndex = 0;
        showKanjiAtIndex();
    }

    private void initStringSelections() {
        SelectionsHelper.initSelectionAsEditor(germanMeaningTextField);
        SelectionsHelper.initSelectionAsEditor(onLesungTextField);
        SelectionsHelper.initSelectionAsEditor(kunLesungTextField);

        germanMeaningTextField.addReturnListener(() -> checkAndShowNextOrEndDialog());
        onLesungTextField.addReturnListener(() -> checkAndShowNextOrEndDialog());
        kunLesungTextField.addReturnListener(() -> checkAndShowNextOrEndDialog());

        SelectionsHelper.initSelectionAsViewer(numberOfKanjiSelection);
        SelectionsHelper.initSelectionAsViewer(numberOfDoneKanjiSelection);
        SelectionsHelper.initSelectionAsViewer(numberOfCorrectDoneKanjiSelection);
        SelectionsHelper.initSelectionAsViewer(correctDonePercentKanjiSelection);

        numberOfKanjiSelection.setText(NumberString.taupu(kanjiToTest.size()));
        setNumbersAndPercent();
    }

    private void showKanjiAtIndex() {
        Kanji kanji = kanjiToTest.get(shownKanjiIndex);
        kanjiPanel.showKanji(kanji);

        germanMeaningTextField.setText("");
        onLesungTextField.setText("");
        kunLesungTextField.setText("");

        germanMeaningTextField.requestFocusLater();
    }

    /** Baut die Gui auf. */
    @Override
    protected void populateDialog() {
        add(createCenterPart(), BorderLayout.CENTER);
    }

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

        panel.add(createSummeryPart(), BorderLayout.NORTH);
        panel.add(createBigKanjiDisplayPart(), BorderLayout.CENTER);
        panel.add(createUserInputPart(), BorderLayout.SOUTH);

        return panel;
    }

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

        panel.add(numberOfKanjiSelection.getPanel());
        panel.add(numberOfDoneKanjiSelection.getPanel());
        panel.add(numberOfCorrectDoneKanjiSelection.getPanel());
        panel.add(correctDonePercentKanjiSelection.getPanel());

        return panel;
    }

    private Component createBigKanjiDisplayPart() {
        JPanel panel = new JPanel();
        panel.setLayout(new BorderLayout());
        GuiTools.createTitle(panel);

        panel.add(kanjiPanel.getPanel(), BorderLayout.CENTER);

        return panel;
    }

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

        panel.add(createPureUserInputPart(), BorderLayout.CENTER);
        panel.add(createButtonsPart(), BorderLayout.SOUTH);

        return panel;
    }

    private Component createPureUserInputPart() {
        JPanel panel = new JPanel();
        panel.setLayout(new VerticalLayout(3, VerticalLayout.BOTH));
        GuiTools.createTitle(panel);

        panel.add(germanMeaningTextField.getPanel());
        panel.add(onLesungTextField.getPanel());
        panel.add(kunLesungTextField.getPanel());

        return panel;
    }

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

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

        return panel;
    }
    private Component createQuitButton() {
        quitButton.setText("Abbrechen");
        quitButton.addActionListener(e -> quit());
        return quitButton;
    }

    private void quit() {
        MessageSetter messageSetter = uiObjects.getMessageSetter();
        messageSetter.setMessage("Abfage von Kanji abgebrochen: " + kanjiToTestDescription);
        closeDialog();
    }

    private Component createOkButton() {
        JButton button = new JButton("   Prüfen   ");
        GuiTools.biggerFont(button, 5);
        button.addActionListener(e -> checkAndShowNextOrEndDialog());
        return button;
    }

    private void checkAndShowNextOrEndDialog() {
        ++tested;
        SingleUserInputKanjiCheckResult result = check();
        boolean ok = result.isOk();
        if (result.isOk()) {
            ++correctTested;
        }

        boolean wasOnlyTypingError = showSingleUserInputCheckResult(result);
        if (!result.isOk() && wasOnlyTypingError) {
            ++correctTested;
            ok = true;
        }

        saveUserTestAnswerInInternalKanjiData(result.getKanji(), ok);
        setNumbersAndPercent();

        if (tested == kanjiToTest.size()) {
            closeDialog();
            showTotalUserInputCheckResult();
        }
        else {
            ++shownKanjiIndex;
            showKanjiAtIndex();
        }
    }

    private SingleUserInputKanjiCheckResult check() {
        Kanji kanji = kanjiToTest.get(shownKanjiIndex);
        String germanMeaning = Text.removeCommaAtEnd(germanMeaningTextField.getTrimmedText());
        String onLesung = prepareUserEnteredValue(onLesungTextField.getTrimmedText());
        String kunLesung = prepareUserEnteredValue(kunLesungTextField.getTrimmedText());

        KanjiTestChecker checker = new KanjiTestChecker(kanji, germanMeaning, onLesung, kunLesung,
                germanMeaningCaseSensitivity, onLesungCaseSensitivity, kunLesungCaseSensitivity);
        checker.check();
        return checker.getResult();
    }

    private static String prepareUserEnteredValue(String value) {
        String valueOut = value;

        //valueOut = Text.removeCommaAtEnd(valueOut);
        valueOut = VocabularyTools.removePuncuationMarksForKanjiReading(valueOut);

        return valueOut;
    }

    private boolean showSingleUserInputCheckResult(SingleUserInputKanjiCheckResult result) {
        String userInputGermanMeaning =
                Text.removeCommaAtEnd(germanMeaningTextField.getTrimmedText());
        String userInputOnLesung = prepareUserEnteredValue(onLesungTextField.getTrimmedText());
        String userInputKunLesung = prepareUserEnteredValue(kunLesungTextField.getTrimmedText());

        KanjiTestEvaluationDialog dialog = new KanjiTestEvaluationDialog(result,
                userInputGermanMeaning, userInputOnLesung, userInputKunLesung, dataStructures,
                uiObjects, getLocation());
        dialog.setVisible(true);

        if (result.isOk()) {
            return false;
        }
        else {
            return dialog.wasOnlyTypingError();
        }
    }

    private void saveUserTestAnswerInInternalKanjiData(Kanji kanji, boolean ok) {
        InternalKanjiDataRequester requester = dataStructures.getInternalKanjiDataRequester();
        InternalAdditionalKanjiData data = requester.getInternalDataForKanji(kanji);
        data.tested(ok);
    }

    public void setNumbersAndPercent() {
        numberOfDoneKanjiSelection.setText(NumberString.taupu(tested));
        numberOfCorrectDoneKanjiSelection.setText(NumberString.taupu(correctTested));
        if (tested == 0) {
            correctDonePercentKanjiSelection.setText("0.00 %");
        }
        else {
            correctDonePercentKanjiSelection.setText(
                    NumberString.percent(correctTested, tested) + " %");
        }
    }

    private void showTotalUserInputCheckResult() {
        quitButton.setText("Beenden");
        SwingUtilities.invokeLater(() -> quitButton.requestFocus());

        Options options = dataStructures.getOptions();
        double lastTenTestsPercentAfter =
                VocabularyTrainerUiTools.createLastTenKanjiTestsPercent(kanjiToTest, dataStructures);
        String originalDialogTitle = createDialogTitle(
                "Kanji abfragen - " + kanjiToTestDescription);
        AllKanjiTestEvaluationDialog dialog = new AllKanjiTestEvaluationDialog(options, tested,
                correctTested, getLocation(), getProgramImage(), lastTenTestsPercentBefore,
                lastTenTestsPercentAfter, originalDialogTitle, kanjiToTestDescription);
        dialog.setVisible(true);

        MessageSetter messageSetter = uiObjects.getMessageSetter();
        messageSetter.setMessage("Es wurden Kanji abgefragt: " + kanjiToTestDescription);
    }

    private String createDialogTitle(String testTitle) {
        return VocabularyTrainerUiTools.generateTitleWithKanjiTestSuccesss(kanjiToTest, testTitle,
                dataStructures);
    }

}
