package de.gecheckt.pdf.umbenenner.application.port.in;

import java.time.Instant;
import java.util.Objects;
import java.util.Optional;

/**
 * Historischer Kontext eines Dokuments, das in einem früheren Lauf bereits terminal
 * abgeschlossen wurde.
 * <p>
 * Wird genutzt, um im GUI-Detailbereich bei übersprungenen Dokumenten Informationen
 * darüber anzuzeigen, wann und mit welchem Ergebnis die Datei früher verarbeitet wurde.
 * <p>
 * Für Dokumente mit früherem Erfolgsstatus ({@code wasEverSuccessful == true}) sind
 * {@code lastTargetFileName} und {@code lastSuccessInstant} belegt.
 * Für Dokumente, die endgültig fehlgeschlagen sind, ist {@code lastFailureInstant} belegt.
 *
 * @param lastTargetFileName  letzter erfolgreich geschriebener Zieldateiname; leer wenn
 *                            das Dokument nie erfolgreich kopiert wurde
 * @param lastSuccessInstant  Zeitpunkt der letzten erfolgreichen Verarbeitung; leer wenn
 *                            das Dokument nie erfolgreich verarbeitet wurde
 * @param lastFailureInstant  Zeitpunkt des letzten Fehlschlags; leer wenn noch kein
 *                            Fehlschlag aufgetreten ist
 * @param wasEverSuccessful   {@code true} wenn das Dokument mindestens einmal erfolgreich
 *                            verarbeitet wurde
 */
public record HistoricalDocumentContext(
        Optional<String> lastTargetFileName,
        Optional<Instant> lastSuccessInstant,
        Optional<Instant> lastFailureInstant,
        boolean wasEverSuccessful) {

    /**
     * Kompakter Konstruktor zur Normalisierung von {@code null}-Werten.
     *
     * @throws NullPointerException wenn {@code lastTargetFileName},
     *                              {@code lastSuccessInstant} oder
     *                              {@code lastFailureInstant} {@code null} sind
     */
    public HistoricalDocumentContext {
        lastTargetFileName = Objects.requireNonNullElse(lastTargetFileName, Optional.empty());
        lastSuccessInstant = Objects.requireNonNullElse(lastSuccessInstant, Optional.empty());
        lastFailureInstant = Objects.requireNonNullElse(lastFailureInstant, Optional.empty());
    }

    /**
     * Erstellt einen Kontext für ein erfolgreich verarbeitetes Dokument.
     *
     * @param lastTargetFileName letzter Zieldateiname; darf {@code null} sein
     * @param lastSuccessInstant Zeitpunkt des Erfolgs; darf {@code null} sein
     * @return neuer Kontext mit {@code wasEverSuccessful == true}
     */
    public static HistoricalDocumentContext ofSuccess(
            String lastTargetFileName, Instant lastSuccessInstant) {
        return new HistoricalDocumentContext(
                Optional.ofNullable(lastTargetFileName),
                Optional.ofNullable(lastSuccessInstant),
                Optional.empty(),
                true);
    }

    /**
     * Erstellt einen Kontext für ein endgültig fehlgeschlagenes Dokument.
     *
     * @param lastFailureInstant Zeitpunkt des letzten Fehlschlags; darf {@code null} sein
     * @return neuer Kontext mit {@code wasEverSuccessful == false}
     */
    public static HistoricalDocumentContext ofFinalFailure(Instant lastFailureInstant) {
        return new HistoricalDocumentContext(
                Optional.empty(),
                Optional.empty(),
                Optional.ofNullable(lastFailureInstant),
                false);
    }
}
