package de.duehl.vocabulary.japanese.startup.logic.steps;

import java.util.ArrayList;
import java.util.List;

import de.duehl.basics.datetime.time.watch.StopWatch;
import de.duehl.basics.system.SystemTools;
import de.duehl.basics.text.Text;
import de.duehl.vocabulary.japanese.common.persistence.Options;
import de.duehl.vocabulary.japanese.startup.ui.data.MessageAppender;
import de.duehl.vocabulary.japanese.startup.ui.data.SplashScreenable;

/**
 * Diese Basis-Klasse steht für einen Schritt beim Startup des Vokabeltrainers.
 *
 * @version 1.01     2025-11-24
 * @author Christian Dühl
 */

public abstract class StartupStep implements MessageAppender {

    private static final boolean DEBUG = false;


    /** Der Schritt der durchgeführt wird. */
    protected final String step;

    /** Die Programmoptionen. */
    protected final Options options;

    /** Die grafische Oberfläche beim Start in der die Meldungen angezeigt werden. */
    private final SplashScreenable splashScreen;

    /** Misst die Laufzeit des gesamten Startups. */
    private final StopWatch watch;

    /** Gibt an, ob in dem aktuellen Schritt Warnungen aufgetreten sind. */
    private boolean warningsInStep;

    /** Gibt an, ob in dem aktuellen Schritt Fehler aufgetreten sind. */
    private boolean errorsInStep;

    /** Die Meldung zum Fehler, der den Start verhindert. */
    private String errorMessage;

    /** Die Meldungen zu Warnungen. */
    private List<String> warningMessages;

    /**
     * Konstruktor.
     *
     * @param step
     *            Die grafische Oberfläche.
     * @param options
     *            Der Schritt der durchgeführt wird.
     * @param splashScreen
     *            Die grafische Oberfläche beim Start in der die Meldungen angezeigt werden.
     * @param watch
     *            Misst die Laufzeit des gesamten Startups.
     */
    public StartupStep(String step, Options options, SplashScreenable splashScreen,
            StopWatch watch) {
        this.step = step;
        this.options = options;
        this.splashScreen = splashScreen;
        this.watch = watch;

        warningMessages = new ArrayList<>();
    }

    /** Gibt an, ob in dem aktuellen Schritt Warnungen aufgetreten sind. */
    public final boolean isWarningsInStep() {
        return warningsInStep;
    }

    /** Legt fest, dass in dem aktuellen Schritt Warnungen aufgetreten sind. */
    protected final void warningsInStep(String warningMessage) {
        warningMessages.add(warningMessage);
        warningsInStep = true;
    }

    /** Gibt an, ob in dem aktuellen Schritt Fehler aufgetreten sind. */
    public final boolean isErrorsInStep() {
        return errorsInStep;
    }

    /** Legt fest, dass in dem aktuellen Schritt Fehler aufgetreten sind. */
    protected final void errorsInStep(String errorMessage) {
        this.errorMessage = errorMessage;
        errorsInStep = true;
    }

    /** Führt den Schritt aus. */
    public final void runStep() {
        startStep(step);

        runInternalStep();

        endStep(step);
    }

    private void startStep(String step) {
        if (DEBUG) {
            SystemTools.sleepSeconds(1);
        }
        splashScreen.startStep(step);
        warningsInStep = false;
        errorsInStep = false;
    }

    /** Führt den eigentlichen Inhalt des Schritts aus. */
    protected abstract void runInternalStep();

    private void endStep(String step) {
        if (errorsInStep) {
            splashScreen.stepError(step);
        }
        else if (warningsInStep) {
            splashScreen.stepWarning(step);
        }
        else {
            splashScreen.stepGood(step);
        }
    }

    /** Fügt eine Nachricht hinzu. */
    @Override
    public void appendMessage(String message) {
        String realMessage;
        if (options.isShowTimestampsInStartup()) {
            if (message.isBlank()) {
                realMessage = message;
            }
            else {
                String timeIntro = watch.getTime() + " - ";

                if (message.startsWith(" ")) {
                    int index = Text.findIndexOfFirstNonSpace(message);
                    if (index == -1) {
                        throw new RuntimeException("Kann nicht sein, die Nachricht beginnt mit "
                                + "einem Leerzeichen, ist nicht blank, aber ich finde nicht den "
                                + "Index des ersten Nicht-Leerzeichens.");
                    }
                    String spaces = message.substring(0, index);
                    String rest = message.substring(index);
                    realMessage = spaces + timeIntro + rest;
                }
                else {
                    realMessage = timeIntro + message;
                }
            }
        }
        else {
            realMessage = message;
        }
        splashScreen.appendMessage(realMessage);
    }

    /** Getter für die Meldung zum Fehler, der den Start verhindert. */
    public final String getErrorMessage() {
        return errorMessage;
    }

    /** Die Meldungen zu Warnungen. */
    public List<String> getWarningMessages() {
        return warningMessages;
    }

}
