package de.gecheckt.pdf.umbenenner.adapter.out.targetfolder;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatNullPointerException;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;

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

import de.gecheckt.pdf.umbenenner.application.port.out.TargetFileRenameFailureFileNotFound;
import de.gecheckt.pdf.umbenenner.application.port.out.TargetFileRenameFailureTargetExists;
import de.gecheckt.pdf.umbenenner.application.port.out.TargetFileRenameResult;
import de.gecheckt.pdf.umbenenner.application.port.out.TargetFileRenameSuccess;
import de.gecheckt.pdf.umbenenner.application.port.out.TargetFileRenameTechnicalFailure;

/**
 * Tests für {@link FilesystemTargetFileRenameAdapter}.
 * <p>
 * Prüft Erfolgsfall, fehlende Quelldatei, bereits belegte Zieldatei,
 * Umbenennung auf denselben Namen (No-Op) sowie technische Fehler.
 */
class FilesystemTargetFileRenameAdapterTest {

    @TempDir
    Path targetFolder;

    private FilesystemTargetFileRenameAdapter adapter;

    @BeforeEach
    void setUp() {
        adapter = new FilesystemTargetFileRenameAdapter(targetFolder);
    }

    // -------------------------------------------------------------------------
    // Erfolgreicher Rename
    // -------------------------------------------------------------------------

    @Test
    void rename_erfolgreich_gibtSuccessZurueck() throws IOException {
        String oldName = "2026-01-15 - Rechnung.pdf";
        String newName = "2026-01-15 - Rechnung korrigiert.pdf";
        Files.createFile(targetFolder.resolve(oldName));

        TargetFileRenameResult result = adapter.rename(oldName, newName);

        assertThat(result).isInstanceOf(TargetFileRenameSuccess.class);
        assertThat(targetFolder.resolve(newName)).exists();
        assertThat(targetFolder.resolve(oldName)).doesNotExist();
    }

    // -------------------------------------------------------------------------
    // Quelldatei existiert nicht
    // -------------------------------------------------------------------------

    @Test
    void rename_quelldateiNichtVorhanden_gibtFileNotFoundZurueck() {
        TargetFileRenameResult result = adapter.rename("nicht-vorhanden.pdf", "ziel.pdf");

        assertThat(result).isInstanceOf(TargetFileRenameFailureFileNotFound.class);
        TargetFileRenameFailureFileNotFound notFound = (TargetFileRenameFailureFileNotFound) result;
        assertThat(notFound.oldFileName()).isEqualTo("nicht-vorhanden.pdf");
    }

    // -------------------------------------------------------------------------
    // Zieldatei existiert bereits (andere Datei)
    // -------------------------------------------------------------------------

    @Test
    void rename_zieldateiExistiertsAlsAndereDatei_gibtTargetExistsZurueck() throws IOException {
        String oldName = "2026-01-15 - Quelle.pdf";
        String newName = "2026-01-15 - Ziel.pdf";
        Files.createFile(targetFolder.resolve(oldName));
        Files.createFile(targetFolder.resolve(newName));

        TargetFileRenameResult result = adapter.rename(oldName, newName);

        assertThat(result).isInstanceOf(TargetFileRenameFailureTargetExists.class);
        TargetFileRenameFailureTargetExists targetExists = (TargetFileRenameFailureTargetExists) result;
        assertThat(targetExists.newFileName()).isEqualTo(newName);
        // Originaldatei bleibt erhalten
        assertThat(targetFolder.resolve(oldName)).exists();
    }

    // -------------------------------------------------------------------------
    // Umbenennung auf denselben Namen (No-Op – oldPath.equals(newPath))
    // -------------------------------------------------------------------------

    @Test
    void rename_gleicheName_gibtSuccessZurueck() throws IOException {
        String name = "2026-01-15 - SameName.pdf";
        Files.createFile(targetFolder.resolve(name));

        TargetFileRenameResult result = adapter.rename(name, name);

        assertThat(result).isInstanceOf(TargetFileRenameSuccess.class);
        assertThat(targetFolder.resolve(name)).exists();
    }

    // -------------------------------------------------------------------------
    // Unterordner/invalides Ziel – TechnicalFailure
    // -------------------------------------------------------------------------

    @Test
    void rename_ungueltigesZiel_gibtTechnicalFailureZurueck() throws IOException {
        String oldName = "2026-01-15 - Quelle.pdf";
        Files.createFile(targetFolder.resolve(oldName));

        // Versuche, in einen Unterordner zu verschieben, der nicht existiert.
        // Das resolve erzeugt einen Pfad wie "unterordner/ziel.pdf".
        // Files.move schlägt fehl, weil der Unterordner nicht existiert.
        String newName = "unterordner/ziel.pdf";

        TargetFileRenameResult result = adapter.rename(oldName, newName);

        assertThat(result).isInstanceOf(TargetFileRenameTechnicalFailure.class);
    }

    // -------------------------------------------------------------------------
    // Null-Guard
    // -------------------------------------------------------------------------

    @Test
    void rename_nullOldFileName_wirftNullPointerException() {
        assertThatNullPointerException()
                .isThrownBy(() -> adapter.rename(null, "ziel.pdf"));
    }

    @Test
    void rename_nullNewFileName_wirftNullPointerException() {
        assertThatNullPointerException()
                .isThrownBy(() -> adapter.rename("quelle.pdf", null));
    }

    @Test
    void constructor_nullTargetFolder_wirftNullPointerException() {
        assertThatNullPointerException()
                .isThrownBy(() -> new FilesystemTargetFileRenameAdapter(null));
    }
}
