package de.gecheckt.pdf.umbenenner.application.usecase;

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

import de.gecheckt.pdf.umbenenner.application.port.out.DocumentRecord;
import de.gecheckt.pdf.umbenenner.application.port.out.ProcessingAttempt;
import de.gecheckt.pdf.umbenenner.application.port.out.history.HistoryQueryPort;
import de.gecheckt.pdf.umbenenner.domain.model.DocumentFingerprint;

/**
 * Use-Case-Implementierung für das Laden der Detailansicht eines Dokuments im Historien-Tab.
 * <p>
 * Kombiniert den Dokument-Stammsatz und alle historisierten Verarbeitungsversuche
 * für einen bestimmten Fingerprint in einem einzigen Ergebnisobjekt.
 * <p>
 * Wird kein Stammsatz gefunden (z. B. weil das Dokument zwischenzeitlich gelöscht wurde),
 * liefert {@link #loadDetails(DocumentFingerprint)} ein leeres {@link Optional}.
 */
public class DefaultHistoryDetailsUseCase {

    private final HistoryQueryPort historyQueryPort;

    /**
     * Erzeugt den Use-Case mit dem erforderlichen Abfrage-Port.
     *
     * @param historyQueryPort Port für lesende Historienabfragen; darf nicht {@code null} sein
     * @throws NullPointerException wenn {@code historyQueryPort} null ist
     */
    public DefaultHistoryDetailsUseCase(HistoryQueryPort historyQueryPort) {
        this.historyQueryPort = Objects.requireNonNull(historyQueryPort, "historyQueryPort darf nicht null sein");
    }

    /**
     * Lädt den Stammsatz und alle Verarbeitungsversuche für den angegebenen Fingerprint.
     *
     * @param fingerprint Dokumentbezeichner; darf nicht {@code null} sein
     * @return Optional mit den Detaildaten, oder leer wenn kein Stammsatz gefunden wurde
     * @throws de.gecheckt.pdf.umbenenner.application.port.out.DocumentPersistenceException
     *         bei technischen Datenbankfehlern
     */
    public Optional<HistoryDetailsResult> loadDetails(DocumentFingerprint fingerprint) {
        Objects.requireNonNull(fingerprint, "fingerprint darf nicht null sein");

        Optional<DocumentRecord> record = historyQueryPort.findRecordByFingerprint(fingerprint);
        if (record.isEmpty()) {
            return Optional.empty();
        }

        List<ProcessingAttempt> attempts = historyQueryPort.findAttemptsByFingerprint(fingerprint);
        return Optional.of(new HistoryDetailsResult(record.get(), attempts));
    }

    /**
     * Ergebnis einer Historien-Detailabfrage.
     *
     * @param record   Dokument-Stammsatz; nie {@code null}
     * @param attempts alle historisierten Verarbeitungsversuche aufsteigend nach Versuchsnummer;
     *                 nie {@code null}; kann leer sein
     */
    public record HistoryDetailsResult(DocumentRecord record, List<ProcessingAttempt> attempts) {

        /**
         * Kompakter Konstruktor mit Pflichtfeldprüfung.
         *
         * @throws NullPointerException wenn {@code record} oder {@code attempts} null ist
         */
        public HistoryDetailsResult {
            Objects.requireNonNull(record, "record darf nicht null sein");
            Objects.requireNonNull(attempts, "attempts darf nicht null sein");
        }
    }
}
