package de.gecheckt.pdf.umbenenner.application.validation.technicaltest;

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

import org.junit.jupiter.api.Test;

/**
 * Tests für das versiegelte Interface {@link CorrectionOutcome} und seine Untertypen.
 */
class CorrectionOutcomeTest {

    private final CorrectionSuggestion suggestion =
            new CorrectionSuggestion.CreateDirectory("/some/dir", "Ordner anlegen");

    @Test
    void applied_storesSuggestionAndMessage() {
        var outcome = new CorrectionOutcome.Applied(suggestion, "Ordner wurde angelegt");
        assertThat(outcome.suggestion()).isSameAs(suggestion);
        assertThat(outcome.message()).isEqualTo("Ordner wurde angelegt");
    }

    @Test
    void applied_nullSuggestionThrows() {
        assertThatNullPointerException()
                .isThrownBy(() -> new CorrectionOutcome.Applied(null, "msg"));
    }

    @Test
    void failed_storesSuggestionAndErrorMessage() {
        var outcome = new CorrectionOutcome.Failed(suggestion, "Zugriff verweigert");
        assertThat(outcome.suggestion()).isSameAs(suggestion);
        assertThat(outcome.errorMessage()).isEqualTo("Zugriff verweigert");
    }

    @Test
    void failed_nullErrorMessageThrows() {
        assertThatNullPointerException()
                .isThrownBy(() -> new CorrectionOutcome.Failed(suggestion, null));
    }

    @Test
    void notAttempted_storesSuggestionAndReason() {
        var outcome = new CorrectionOutcome.NotAttempted(suggestion, "Elternordner nicht erreichbar");
        assertThat(outcome.suggestion()).isSameAs(suggestion);
        assertThat(outcome.reason()).isEqualTo("Elternordner nicht erreichbar");
    }

    @Test
    void patternMatching_coversAllPermittedTypes() {
        CorrectionOutcome applied = new CorrectionOutcome.Applied(suggestion, "ok");
        CorrectionOutcome failed = new CorrectionOutcome.Failed(suggestion, "error");
        CorrectionOutcome notAttempted = new CorrectionOutcome.NotAttempted(suggestion, "reason");

        assertThat(classify(applied)).isEqualTo("applied");
        assertThat(classify(failed)).isEqualTo("failed");
        assertThat(classify(notAttempted)).isEqualTo("notAttempted");
    }

    private String classify(CorrectionOutcome outcome) {
        return switch (outcome) {
            case CorrectionOutcome.Applied a -> "applied";
            case CorrectionOutcome.Failed f -> "failed";
            case CorrectionOutcome.NotAttempted n -> "notAttempted";
        };
    }
}
