package de.duehl.vocabulary.japanese.ui.dialog.kana.katakanatest;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.GridLayout;
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.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.InternalAdditionalKanaData;
import de.duehl.vocabulary.japanese.common.persistence.Options;
import de.duehl.vocabulary.japanese.data.FumikoDataStructures;
import de.duehl.vocabulary.japanese.data.symbol.Katakana;
import de.duehl.vocabulary.japanese.logic.symbol.kana.internal.InternalKanaDataRequester;
import de.duehl.vocabulary.japanese.logic.symbol.kana.test.KatakanaTestChecker;
import de.duehl.vocabulary.japanese.logic.symbol.kana.test.data.SingleUserInputKatakanaCheckResult;
import de.duehl.vocabulary.japanese.tools.VocabularyTools;
import de.duehl.vocabulary.japanese.ui.data.FumikoUiObjects;
import de.duehl.vocabulary.japanese.ui.dialog.kana.katakanatest.components.KatakanaLabel;
import de.duehl.vocabulary.japanese.ui.tools.VocabularyTrainerUiTools;

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

public class KatakanaTester extends ModalDialogBase {

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


    /** Die Liste der abzufragenden Katakana. */
    private final List<Katakana> katakanaToTest;

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

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

    /** Das Label auf dem das Katakana dargestellt wird. */
    private final KatakanaLabel katakanaLabel;

    /** Das Eingabefeld für die Hepburn-Darstellung. */
    private final StringSelection hepburnTextField;

    /** Der Index des angezeigten Katakana. */
    private int shownKatakanaIndex;

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

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

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

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

    private final StringSelection numberOfKatakanaSelection;
    private final StringSelection numberOfDoneKatakanaSelection;
    private final StringSelection numberOfCorrectDoneKatakanaSelection;
    private final StringSelection correctDonePercentKatakanaSelection;

    /**
     * Konstruktor.
     *
     * @param katakanaToTest
     *            Die Liste der abzufragenden Katakana.
     * @param dataStructures
     *            Die Datenstrukturen des Vokabeltrainers.
     * @param uiObjects
     *            Die häufig verwendeten Funktionen der grafischen Oberfläche des Vokabeltrainers.
     */
    public KatakanaTester(List<Katakana> katakanaToTest, FumikoDataStructures dataStructures,
            FumikoUiObjects uiObjects) {
        super(uiObjects.getGuiLocation(), uiObjects.getProgramImage(), "Katakana-Test",
                DIALOG_DIMENSION);
        this.katakanaToTest = katakanaToTest;
        this.dataStructures = dataStructures;
        this.uiObjects = uiObjects;

        katakanaLabel = new KatakanaLabel();

        hepburnTextField = new StringSelection("Hepburn-Darstellung");

        quitButton = new JButton("");

        lastTenTestsPercentBefore = VocabularyTrainerUiTools
                .createLastTenKatakanaTestsPercent(katakanaToTest, dataStructures);

        numberOfKatakanaSelection = new StringSelection("Anzahl abzufragender Katakana");
        numberOfDoneKatakanaSelection = new StringSelection("Anzahl bereits abgefragte Katakana");
        numberOfCorrectDoneKatakanaSelection = new StringSelection(
                "Anzahl korrekt beantworteter Katakana");
        correctDonePercentKatakanaSelection = new StringSelection(
                "Prozent korrekt beantworteter Katakana");

        init();
        fillDialog();
    }

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

        initStringSelections();

        shownKatakanaIndex = 0;
        showKatakanaAtIndex();
    }

    private void initStringSelections() {
        SelectionsHelper.initSelectionAsEditor(hepburnTextField);

        hepburnTextField.addReturnListener(() -> checkAndShowNextOrEndDialog());

        SelectionsHelper.initSelectionAsViewer(numberOfKatakanaSelection);
        SelectionsHelper.initSelectionAsViewer(numberOfDoneKatakanaSelection);
        SelectionsHelper.initSelectionAsViewer(numberOfCorrectDoneKatakanaSelection);
        SelectionsHelper.initSelectionAsViewer(correctDonePercentKatakanaSelection);

        numberOfKatakanaSelection.setText(NumberString.taupu(katakanaToTest.size()));
        setNumbersAndPercent();
    }

    private void showKatakanaAtIndex() {
        Katakana katakana = katakanaToTest.get(shownKatakanaIndex);
        katakanaLabel.showKatakana(katakana);

        hepburnTextField.setText("");

        hepburnTextField.requestFocus();
    }

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

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

        panel.add(createSummeryPart(), BorderLayout.NORTH);
        panel.add(createKatakanaLablePart(), 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(numberOfKatakanaSelection.getPanel());
        panel.add(numberOfDoneKatakanaSelection.getPanel());
        panel.add(numberOfCorrectDoneKatakanaSelection.getPanel());
        panel.add(correctDonePercentKatakanaSelection.getPanel());

        return panel;
    }

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

        panel.add(katakanaLabel.getLabel(), 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(hepburnTextField.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() {
        closeDialog();
    }

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

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

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

        saveUserTestAnswerInInternalKatakanaData(result.getKatakana(), ok);
        setNumbersAndPercent();

        if (tested == katakanaToTest.size()) {
            closeDialog();
            showTotalUserInputCheckResult();
        }
        else {
            ++shownKatakanaIndex;
            showKatakanaAtIndex();
        }
    }

    private SingleUserInputKatakanaCheckResult check() {
        Katakana katakana = katakanaToTest.get(shownKatakanaIndex);
        String hepburn = VocabularyTools.removePuncuationMarks(hepburnTextField.getTrimmedText());

        KatakanaTestChecker checker = new KatakanaTestChecker(katakana, hepburn);
        checker.check();
        return checker.getResult();
    }

    private boolean showSingleUserInputCheckResult(SingleUserInputKatakanaCheckResult result) {
        String userInputHepburn =
                VocabularyTools.removePuncuationMarks(hepburnTextField.getTrimmedText());

        Options options = dataStructures.getOptions();
        KatakanaTestEvaluationDialog dialog = new KatakanaTestEvaluationDialog(result,
                userInputHepburn, options, dataStructures, uiObjects, getParentLocation(),
                getProgramImage());
        dialog.setVisible(true);

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

    private void saveUserTestAnswerInInternalKatakanaData(Katakana katakana, boolean ok) {
        InternalKanaDataRequester requester = dataStructures.getInternalKanaDataRequester();
        InternalAdditionalKanaData data = requester.getInternalDataForKatakana(katakana);
        data.tested(ok);
    }

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

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

        double lastTenTestsPercentAfter =
                VocabularyTrainerUiTools.createLastTenKatakanaTestsPercent(katakanaToTest,
                        dataStructures);
        String originalDialogTitle = createDialogTitle("Katakana abfragen");
        Options options = dataStructures.getOptions();
        AllKatakanaTestEvaluationDialog dialog = new AllKatakanaTestEvaluationDialog(options,
                tested, correctTested, getLocation(),
                getProgramImage(), lastTenTestsPercentBefore, lastTenTestsPercentAfter,
                originalDialogTitle);
        dialog.setVisible(true);
    }

    private String createDialogTitle(String testTitle) {
        return VocabularyTrainerUiTools.generateTitleWithKatakanaTestSuccesss(katakanaToTest,
                testTitle, dataStructures);
    }

}
