package de.gecheckt.pdf.umbenenner.application.validation.technicaltest;

import java.util.Objects;

/**
 * Versiegeltes Ergebnis der Ausführung eines einzelnen {@link CorrectionSuggestion}-Vorschlags.
 * <p>
 * Nach Benutzerbestätigung eines {@link CorrectionPlan} wird jeder enthaltene Vorschlag
 * durch den {@link ResourceCreationPort} ausgeführt. Das Ergebnis jeder Ausführung wird
 * als eines der drei möglichen Zustände modelliert:
 * <ul>
 *   <li>{@link Applied} – die Korrektur wurde erfolgreich durchgeführt.</li>
 *   <li>{@link Failed} – die Korrektur wurde versucht, aber ist technisch gescheitert.</li>
 *   <li>{@link NotAttempted} – die Korrektur wurde nicht versucht, obwohl sie im Plan enthalten war.
 *       Typischer Grund: eine Voraussetzung war zur Laufzeit nicht erfüllt.</li>
 * </ul>
 * <p>
 * Alle Implementierungen sind immutable und enthalten keine JavaFX-Typen.
 */
public sealed interface CorrectionOutcome
        permits CorrectionOutcome.Applied,
                CorrectionOutcome.Failed,
                CorrectionOutcome.NotAttempted {
    String SUGGESTION_NOT_NULL = "suggestion must not be null";


    /**
     * Gibt den Korrekturvorschlag zurück, auf den sich dieses Ergebnis bezieht.
     *
     * @return Korrekturvorschlag; nie {@code null}
     */
    CorrectionSuggestion suggestion();

    /**
     * Die Korrektur wurde erfolgreich durchgeführt.
     *
     * @param suggestion  der ausgeführte Korrekturvorschlag; nie {@code null}
     * @param message     deutsche Bestätigungsmeldung; nie {@code null}
     */
    record Applied(
            CorrectionSuggestion suggestion,
            String message) implements CorrectionOutcome {

        /**
         * Erstellt ein Erfolgs-Ergebnis.
         *
         * @param suggestion  Korrekturvorschlag; darf nicht {@code null} sein
         * @param message     Bestätigungsmeldung; darf nicht {@code null} sein
         * @throws NullPointerException wenn ein Parameter {@code null} ist
         */
        public Applied {
            Objects.requireNonNull(suggestion, SUGGESTION_NOT_NULL);
            Objects.requireNonNull(message, "message must not be null");
        }
    }

    /**
     * Die Korrektur wurde versucht, aber ist technisch gescheitert.
     *
     * @param suggestion    der nicht erfolgreich ausgeführte Korrekturvorschlag; nie {@code null}
     * @param errorMessage  deutsche Fehlerbeschreibung; nie {@code null}
     */
    record Failed(
            CorrectionSuggestion suggestion,
            String errorMessage) implements CorrectionOutcome {

        /**
         * Erstellt ein Fehler-Ergebnis.
         *
         * @param suggestion    Korrekturvorschlag; darf nicht {@code null} sein
         * @param errorMessage  Fehlerbeschreibung; darf nicht {@code null} sein
         * @throws NullPointerException wenn ein Parameter {@code null} ist
         */
        public Failed {
            Objects.requireNonNull(suggestion, SUGGESTION_NOT_NULL);
            Objects.requireNonNull(errorMessage, "errorMessage must not be null");
        }
    }

    /**
     * Die Korrektur wurde nicht versucht, obwohl sie im Plan enthalten war.
     * <p>
     * Typischer Grund: Eine Voraussetzung war zur Ausführungszeit nicht erfüllt
     * (z. B. übergeordneter Ordner nicht erreichbar). Dies ist kein technischer Fehler
     * des Korrekturprozesses selbst, sondern ein Hinweis auf eine unerfüllbare Bedingung.
     *
     * @param suggestion  der nicht versuchte Korrekturvorschlag; nie {@code null}
     * @param reason      deutsche Begründung; nie {@code null}
     */
    record NotAttempted(
            CorrectionSuggestion suggestion,
            String reason) implements CorrectionOutcome {

        /**
         * Erstellt ein Nicht-Versucht-Ergebnis.
         *
         * @param suggestion  Korrekturvorschlag; darf nicht {@code null} sein
         * @param reason      Begründung; darf nicht {@code null} sein
         * @throws NullPointerException wenn ein Parameter {@code null} ist
         */
        public NotAttempted {
            Objects.requireNonNull(suggestion, SUGGESTION_NOT_NULL);
            Objects.requireNonNull(reason, "reason must not be null");
        }
    }
}
