package de.gecheckt.pdf.umbenenner.bootstrap.adapter;

import java.nio.file.InvalidPathException;
import java.nio.file.Paths;
import java.util.Optional;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.appender.RollingFileAppender;

import de.gecheckt.pdf.umbenenner.application.validation.technicaltest.LogDiagnosticsPort;

/**
 * Log4j2-basierte Implementierung von {@link LogDiagnosticsPort}.
 * <p>
 * Liest den aktiven {@link RollingFileAppender} aus dem laufenden {@link LoggerContext}
 * und gibt dessen absoluten Dateipfad zurück. Diese Information zeigt, wo Log-Einträge
 * tatsächlich landen – unabhängig vom konfigurierten {@code log.directory}-Wert in der
 * Properties-Datei.
 * <p>
 * Gibt einen leeren {@link Optional} zurück, wenn kein dateibasierter Appender aktiv ist,
 * der Kontext nicht auslesbar ist oder der Pfad nicht zu einem absoluten Pfad aufgelöst
 * werden kann.
 */
public class Log4jLogDiagnosticsAdapter implements LogDiagnosticsPort {

    /**
     * Erstellt einen neuen {@code Log4jLogDiagnosticsAdapter}.
     */
    public Log4jLogDiagnosticsAdapter() {
        // zustandslos
    }

    /**
     * Ermittelt den absoluten Pfad der aktiven Log-Datei aus dem laufenden Log4j2-Kontext.
     * <p>
     * Durchsucht die Appender-Liste des aktiven {@link LoggerContext} nach dem ersten
     * {@link RollingFileAppender} und gibt dessen {@code fileName} als absoluten Pfad zurück.
     * Alle Ausnahmen werden abgefangen und als leeres Ergebnis zurückgegeben.
     *
     * @return absoluter Pfad der aktiven Log-Datei; leer wenn nicht bestimmbar
     */
    @Override
    public Optional<String> resolveActiveLogFilePath() {
        try {
            LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
            return ctx.getConfiguration().getAppenders().values().stream()
                    .filter(a -> a instanceof RollingFileAppender)
                    .map(a -> (RollingFileAppender) a)
                    .map(RollingFileAppender::getFileName)
                    .filter(name -> name != null && !name.isBlank())
                    .map(this::toAbsolutePath)
                    .filter(Optional::isPresent)
                    .map(Optional::get)
                    .findFirst();
        } catch (Exception e) {
            return Optional.empty();
        }
    }

    private Optional<String> toAbsolutePath(String path) {
        try {
            return Optional.of(Paths.get(path).toAbsolutePath().toString());
        } catch (InvalidPathException e) {
            return Optional.empty();
        }
    }
}
