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

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;

import de.gecheckt.pdf.umbenenner.bootstrap.startup.RuntimeLogDirectoryReconfigurer.LogDirectoryChange;

/**
 * Tests für {@link RuntimeLogDirectoryReconfigurer}.
 *
 * <p>Die tatsächliche Log4j2-Neukonfiguration wird über eine Test-Unterklasse unterdrückt,
 * damit die Tests den globalen Log4j2-Zustand nicht verändern. Die System-Property
 * {@code log.directory} wird pro Test gesichert, geleert und wiederhergestellt.
 */
class RuntimeLogDirectoryReconfigurerTest {

    private static final String KEY = "log.directory";

    private String originalProperty;

    @TempDir
    Path tempDir;

    /** Variante, die die echte Log4j2-Neukonfiguration durch bloßes Zählen ersetzt. */
    private static final class RecordingReconfigurer extends RuntimeLogDirectoryReconfigurer {
        private int reconfigureCalls = 0;

        @Override
        protected void reconfigure() {
            reconfigureCalls++;
        }
    }

    @BeforeEach
    void clearLogDirectoryProperty() {
        originalProperty = System.getProperty(KEY);
        System.clearProperty(KEY);
    }

    @AfterEach
    void restoreLogDirectoryProperty() {
        if (originalProperty == null) {
            System.clearProperty(KEY);
        } else {
            System.setProperty(KEY, originalProperty);
        }
    }

    @Test
    void apply_creatableDirectory_setsPropertyCreatesDirAndReconfigures() {
        RecordingReconfigurer reconf = new RecordingReconfigurer();
        Path target = tempDir.resolve("logs-sub");

        LogDirectoryChange change = reconf.apply(target);

        assertTrue(change.changed());
        assertNotNull(change.appliedDirectory());
        assertTrue(Files.isDirectory(target), "Konfiguriertes Log-Verzeichnis muss angelegt worden sein");
        assertEquals(target.toAbsolutePath().toString(), System.getProperty(KEY));
        assertEquals(1, reconf.reconfigureCalls);
    }

    @Test
    void apply_nullOrBlank_doesNothing() {
        RecordingReconfigurer reconf = new RecordingReconfigurer();

        assertFalse(reconf.apply(null).changed());
        assertFalse(reconf.apply(Paths.get("")).changed());
        assertNull(System.getProperty(KEY));
        assertEquals(0, reconf.reconfigureCalls);
    }

    @Test
    void apply_alreadyActiveDirectory_isIdempotent() {
        RecordingReconfigurer reconf = new RecordingReconfigurer();
        Path target = tempDir.resolve("logs");
        System.setProperty(KEY, target.toAbsolutePath().toString());

        LogDirectoryChange change = reconf.apply(target);

        assertFalse(change.changed(), "Bereits aktives Verzeichnis darf keine Umstellung auslösen");
        assertEquals(0, reconf.reconfigureCalls);
    }

    @Test
    void apply_nonCreatableDirectory_leavesPropertyUnchanged() throws IOException {
        RecordingReconfigurer reconf = new RecordingReconfigurer();
        Path blocker = tempDir.resolve("blocker.txt");
        Files.writeString(blocker, "x", StandardCharsets.UTF_8);
        Path target = blocker.resolve("sub"); // Unterordner unterhalb einer Datei -> nicht anlegbar

        LogDirectoryChange change = reconf.apply(target);

        assertFalse(change.changed());
        assertNull(System.getProperty(KEY), "Bei Fehlschlag darf keine System-Property gesetzt werden");
        assertEquals(0, reconf.reconfigureCalls);
    }
}
