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

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

import javax.swing.BorderFactory;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;

import de.duehl.basics.datetime.time.watch.StopWatch;
import de.duehl.swing.ui.GuiTools;
import de.duehl.swing.ui.dialogs.base.NonModalFrameDialogBase;
import de.duehl.swing.ui.layout.VerticalLayout;
import de.duehl.swing.ui.lights.CheckLight;
import de.duehl.swing.ui.lights.data.CheckLightMode;
import de.duehl.vocabulary.japanese.common.chan.Chan;
import de.duehl.vocabulary.japanese.startup.ui.data.SplashScreenable;

/**
 * Diese Klasse ist die grafische Oberfläche beim Startup (vgl. Klasse StartUp), diese lädt beim
 * Starten des Vokabeltrainers die Vokabulare ein, sucht die Sound-Files und stellt die Verbindung
 * zu den benutzerabhängigen, internen Daten jeder Variablen her.
 *
 * Hier wird das ganze grafisch dargestellt und die angezeigten Informationen gesammelt, damit man
 * diese später über das Menü abfragen kann.
 *
 * @version 1.01     2025-11-23
 * @author Christian Dühl
 */

public class SplashScreen extends NonModalFrameDialogBase implements SplashScreenable {

    /**
     * Die Art der Darstellung:
     *
     *    a) eine einzelne Ampel, die die drei Zustände annehmen kann
     *    b) zwei Ampeln, eine schwarz/grün, die andere schwarz/rot
     *    c) drei Ampeln, eine schwarz/grün, die zweite schwarz/gelb und die dritte schwarz/rot
     */
    private static final CheckLightMode CHECK_LIGHT_MODE = CheckLightMode.THREE; // ONE THREE


    /** Die Bezeichnungen der Arbeitsschritte. */
    private final List<String> steps;

    /** Die Elemente zur Darstellung des Zustandes der Schritte. */
    private final List<CheckLight> stepLights;

    /** Der StringBuilder für den Text, der beim Starten des Vokabeltrainers angezeigt wird. */
    private final StringBuilder splashTextBuilder;

    /** Das Textfeld, wo die Daten über den Einleseprozess angezeigt werden. */
    private final JTextArea startupTextArea;

    /** Das Textfeld, wo der aktuelle Schritt angezeigt werden. */
    private final JTextArea actualStepTextArea;

    /** Das Label zur Anzeige der Laufzeit der bislang abgearbeiteten Schritte. */
    private final JLabel finishedStepsRuntimeLabel;

    /** Misst die Laufzeit der bislang abgearbeiteten Schritte. */
    private final StopWatch finishedStepsRuntimeWatch;

    /** Gibt an, ob der SplashScreengeschlossen werden kann. */
    private boolean canClose;

    /**
     * Konstruktor.
     *
     * @param steps
     *            Die Bezeichnungen der Arbeitsschritte.
     * @param programImage
     *            Das Icon für das Programm.
     */
    public SplashScreen(List<String> steps, Image programImage) {
        super(new Point(150, 100), programImage,
                "Start von " + Chan.CHAN_NAME + "s Vokabel-Trainer");
        addClosingWindowListener(() -> closeDialogIfDone());

        this.steps = steps;

        stepLights = createStepLights();

        splashTextBuilder = new StringBuilder();
        startupTextArea = new JTextArea();
        actualStepTextArea = new JTextArea();
        finishedStepsRuntimeLabel = new JLabel();
        finishedStepsRuntimeWatch = new StopWatch();

        canClose = false;

        init();
        fillDialog();
    }

    private List<CheckLight> createStepLights() {
        List<CheckLight> stepLigths = new ArrayList<>();

        for (String step : steps) {
            CheckLight checkLight = new CheckLight(CHECK_LIGHT_MODE, step);
            stepLigths.add(checkLight);
        }

        return stepLigths;
    }

    private void init() {
        initTextArea();
        initActualStepTextArea();
        initFinishedStepsRuntimeLabel();
    }

    private void initTextArea() {
        startupTextArea.setRows(45);
        startupTextArea.setColumns(100); // 120
        startupTextArea.setEditable(false);
        startupTextArea.setFocusable(false);
    }

    private void initActualStepTextArea() {
        actualStepTextArea.setRows(3);
        actualStepTextArea.setColumns(80);
        actualStepTextArea.setEditable(false);
        actualStepTextArea.setFocusable(false);
        GuiTools.biggerFont(actualStepTextArea, 10);
    }

    private void initFinishedStepsRuntimeLabel() {
        GuiTools.biggerFont(finishedStepsRuntimeLabel, 15);
        finishedStepsRuntimeLabel.setBorder(BorderFactory.createEmptyBorder(2, 10, 2, 10));
        actualiseFinishedStepsRuntimeLabel();
    }

    /** Baut die Gui auf. */
    @Override
    protected void populateDialog() {
        // Später das Bild ...

        add(createStepLightsPart(), BorderLayout.WEST);
        add(createMainPart(), BorderLayout.CENTER);
    }

    private Component createStepLightsPart() {
        JPanel panel = new JPanel();
        panel.setLayout(new VerticalLayout(7, VerticalLayout.BOTH));

        for (CheckLight stepLight : stepLights) {
            panel.add(stepLight.getPanel());
        }

        return panel;
    }

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

        panel.add(createActualStepTextAndFinishedStepsRuntimePart(), BorderLayout.NORTH);
        panel.add(GuiTools.createScrollPane(startupTextArea), BorderLayout.CENTER);

        return panel;
    }

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

        panel.add(actualStepTextArea, BorderLayout.CENTER);
        panel.add(finishedStepsRuntimeLabel, BorderLayout.EAST);

        return panel;
    }

    /** Fügt eine Nachricht hinzu. */
    @Override
    public void appendMessage(String message) {
        appendMessageToSplashTextBuilder(message);
        appendMessageToTextArea(message);
    }

    private void appendMessageToSplashTextBuilder(String message) {
        splashTextBuilder.append(message).append("\n");
    }

    private void appendMessageToTextArea(String message) {
        try {
            tryToAppendMessageToTextArea(message);
        }
        catch (BadLocationException e) {
            throw new RuntimeException("Kann die Nachricht [" + message + "] nicht an das Ende "
                    + "des Dokuments der JTextArea des SplashScreens anhängen.");
        }
    }

    private void tryToAppendMessageToTextArea(String message) throws BadLocationException {
        Document doc = startupTextArea.getDocument();
        doc.insertString(doc.getLength(), message + "\n", null);
        startupTextArea.setCaretPosition(startupTextArea.getDocument().getLength());
    }

    /** Teilt mit, dass ein Schritt gestartet wird. */
    @Override
    public void startStep(String step) {
        CheckLight stepLight = determineLightByStep(step);
        stepLight.setBlack();
        actualStepTextArea.setText(step);
    }

    /** Teilt mit, dass ein Schritt erfolgreich beendet wurde. */
    @Override
    public void stepGood(String step) {
        CheckLight stepLight = determineLightByStep(step);
        stepLight.setGreen();
        actualStepTextArea.setText("");
        actualiseFinishedStepsRuntimeLabel();
    }

    /** Teilt mit, dass ein Schritt mit Warnungen beendet wurde. */
    @Override
    public void stepWarning(String step) {
        CheckLight stepLight = determineLightByStep(step);
        stepLight.setYellow();
        actualStepTextArea.setText("");
        actualiseFinishedStepsRuntimeLabel();
    }

    /** Teilt mit, dass ein Schritt mit Fehlern beendet wurde. */
    @Override
    public void stepError(String step) {
        CheckLight stepLight = determineLightByStep(step);
        stepLight.setRed();
        actualStepTextArea.setText("");
        actualiseFinishedStepsRuntimeLabel();
    }

    /** Ermittelt aus der Bezeichnung des Arbeitsschritt das zugehörige CheckLight-Objekt. */
    private CheckLight determineLightByStep(String step) {
        int index = steps.indexOf(step);
        if (index == -1) {
            throw new IllegalArgumentException("Unbekannter Schritt '" + step + "'.");
        }
        CheckLight stepLight = stepLights.get(index);
        return stepLight;
    }

    private void actualiseFinishedStepsRuntimeLabel() {
        finishedStepsRuntimeLabel.setText(finishedStepsRuntimeWatch.getTime());
    }

    /** Teilt dem SplashScreen mit, dass er geschlossen werden kann. */
    public void canClose() {
        canClose = true;
    }

    private void closeDialogIfDone() {
        if (canClose) {
            closeDialog();
        }
        else {
            //
        }
    }

    /** Getter für den Text, der beim Starten des Vokabeltrainers angezeigt wurde. */
    public String getSplashText() {
        return splashTextBuilder.toString();
    }

}
