package de.gecheckt.pdf.umbenenner.adapter.in.gui.batchrun;

import java.util.Objects;
import java.util.Optional;

/**
 * Immutable result of a single batch run launched from the GUI.
 * <p>
 * The outcome reports to the tab whether the run finished normally, could not even be
 * started (hard failure), or ended because of an unexpected exception. The GUI uses this
 * to transition between its "laufend" and "bereit"/"Fehler" states.
 *
 * <h2>Fields</h2>
 * <ul>
 *   <li>{@link #successfullyStarted()} — {@code true} when the launcher managed to enter
 *       the batch execution phase; {@code false} when the run was rejected before any
 *       candidate could be processed (e.g. configuration invalid, lock held, SQLite
 *       unavailable).</li>
 *   <li>{@link #batchCompletedNormally()} — {@code true} when the run returned from the
 *       batch use case with a normal outcome (whether empty, partial, or full). Only
 *       meaningful when {@link #successfullyStarted()} is also {@code true}.</li>
 *   <li>{@link #failureMessage()} — present when either the run could not start or an
 *       unexpected technical exception terminated it. Empty when the run completed
 *       normally.</li>
 * </ul>
 */
public record GuiBatchRunLaunchOutcome(
        boolean successfullyStarted,
        boolean batchCompletedNormally,
        Optional<String> failureMessage) {

    /**
     * Compact constructor normalising the failure message holder.
     */
    public GuiBatchRunLaunchOutcome {
        failureMessage = Objects.requireNonNullElse(failureMessage, Optional.empty());
    }

    /**
     * Returns an outcome describing a run that finished normally.
     *
     * @return a started + completed outcome without failure message
     */
    public static GuiBatchRunLaunchOutcome completed() {
        return new GuiBatchRunLaunchOutcome(true, true, Optional.empty());
    }

    /**
     * Returns an outcome describing a run that could not start because of a hard
     * configuration, persistence, or lock failure.
     *
     * @param failureMessage the user-visible German failure description; must not be blank
     * @return a rejected-startup outcome carrying the supplied message
     */
    public static GuiBatchRunLaunchOutcome rejected(String failureMessage) {
        Objects.requireNonNull(failureMessage, "failureMessage must not be null");
        if (failureMessage.isBlank()) {
            throw new IllegalArgumentException("failureMessage must not be blank");
        }
        return new GuiBatchRunLaunchOutcome(false, false, Optional.of(failureMessage));
    }

    /**
     * Returns an outcome describing a run that started but ended due to an unexpected
     * technical exception.
     *
     * @param failureMessage the user-visible German failure description; must not be blank
     * @return an aborted-after-start outcome carrying the supplied message
     */
    public static GuiBatchRunLaunchOutcome failedAfterStart(String failureMessage) {
        Objects.requireNonNull(failureMessage, "failureMessage must not be null");
        if (failureMessage.isBlank()) {
            throw new IllegalArgumentException("failureMessage must not be blank");
        }
        return new GuiBatchRunLaunchOutcome(true, false, Optional.of(failureMessage));
    }
}
