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

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

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import de.gecheckt.pdf.umbenenner.application.port.in.ResolveHistoricalFileNameUseCase;
import de.gecheckt.pdf.umbenenner.application.port.out.DocumentPersistenceException;
import de.gecheckt.pdf.umbenenner.application.port.out.DocumentRecordLookupResult;
import de.gecheckt.pdf.umbenenner.application.port.out.DocumentRecordRepository;
import de.gecheckt.pdf.umbenenner.application.port.out.DocumentTerminalSuccess;
import de.gecheckt.pdf.umbenenner.domain.model.DocumentFingerprint;

/**
 * Standardimplementierung von {@link ResolveHistoricalFileNameUseCase}.
 * <p>
 * Fragt den {@link DocumentRecordRepository} nach dem Stammsatz des angegebenen
 * Fingerprints ab. Ist der Stammsatz terminal erfolgreich, wird der zuletzt
 * geschriebene Zieldateiname zurückgegeben.
 * <p>
 * Für alle anderen terminalen Zustände oder wenn kein Stammsatz vorhanden ist,
 * wird ein leeres {@link Optional} zurückgegeben.
 * {@link DocumentPersistenceException}s aus dem Repository werden geloggt (WARN) und
 * führen zu einem leeren {@link Optional}. Andere unerwartete Laufzeitfehler
 * propagieren zum Aufrufer. Erwartete Lookup-Fehler werden als
 * {@code PersistenceLookupTechnicalFailure} im Rückgabewert kodiert und führen
 * ebenfalls zu einem leeren {@link Optional}.
 */
public class DefaultResolveHistoricalFileNameUseCase implements ResolveHistoricalFileNameUseCase {

    private static final Logger logger =
            LogManager.getLogger(DefaultResolveHistoricalFileNameUseCase.class);

    private final DocumentRecordRepository documentRecordRepository;

    /**
     * Creates the use case with the required document master record repository.
     *
     * @param documentRecordRepository repository for reading document master records;
     *                                 must not be {@code null}
     * @throws NullPointerException if {@code documentRecordRepository} is {@code null}
     */
    public DefaultResolveHistoricalFileNameUseCase(
            DocumentRecordRepository documentRecordRepository) {
        this.documentRecordRepository = Objects.requireNonNull(
                documentRecordRepository, "documentRecordRepository must not be null");
    }

    /**
     * Returns the last successfully written target filename for the given fingerprint,
     * or an empty {@link Optional} if no such filename exists.
     * <p>
     * The method queries the document master record. Only documents with a prior
     * successful terminal state carry a non-null {@code lastTargetFileName}. For all
     * other states (unknown, processable, finally failed) and on any technical lookup
     * failure, an empty {@link Optional} is returned.
     *
     * @param fingerprint content-based document identity; must not be {@code null}
     * @return the historical target filename, or empty if not available
     * @throws NullPointerException if {@code fingerprint} is {@code null}
     */
    @Override
    public Optional<String> resolveHistoricalFileName(DocumentFingerprint fingerprint) {
        Objects.requireNonNull(fingerprint, "fingerprint must not be null");
        try {
            DocumentRecordLookupResult result =
                    documentRecordRepository.findByFingerprint(fingerprint);
            if (result instanceof DocumentTerminalSuccess success) {
                return Optional.ofNullable(success.record().lastTargetFileName());
            }
            return Optional.empty();
        } catch (DocumentPersistenceException e) {
            logger.warn("Persistenzfehler beim Lesen des historischen Dateinamens für Fingerprint {}: {}",
                    fingerprint, e.getMessage(), e);
            return Optional.empty();
        }
    }
}
