package de.gecheckt.pdf.umbenenner.adapter.in.gui.editor;

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

import java.time.Instant;
import java.util.List;

import org.junit.jupiter.api.Test;

/**
 * Tests for {@link GuiEditorValidationResult}.
 */
class GuiEditorValidationResultTest {

    @Test
    void empty_producesResultWithNoFindingsAndCurrentTimestamp() {
        var result = GuiEditorValidationResult.empty();

        assertThat(result.messages()).isEmpty();
        assertThat(result.fieldFindings()).isEmpty();
        assertThat(result.evaluatedAt()).isNotNull();
    }

    @Test
    void hasErrors_falseWhenNoMessages() {
        var result = GuiEditorValidationResult.empty();
        assertThat(result.hasErrors()).isFalse();
    }

    @Test
    void hasErrors_trueWhenMessageWithErrorSeverity() {
        var messages = List.of(GuiMessageEntry.of(GuiMessageSeverity.ERROR, "API-Key fehlt"));
        var result = new GuiEditorValidationResult(messages, List.of(), Instant.now());

        assertThat(result.hasErrors()).isTrue();
    }

    @Test
    void hasErrors_trueWhenFieldFindingWithErrorSeverity() {
        var fieldFindings = List.of(GuiFieldFinding.error("source.folder", "Pflichtfeld fehlt"));
        var result = new GuiEditorValidationResult(List.of(), fieldFindings, Instant.now());

        assertThat(result.hasErrors()).isTrue();
    }

    @Test
    void hasErrors_falseWhenOnlyWarnings() {
        var messages = List.of(GuiMessageEntry.of(GuiMessageSeverity.WARNING, "Hohe Zeichenzahl"));
        var fieldFindings = List.of(GuiFieldFinding.warning("max.text.characters", "Warnung"));
        var result = new GuiEditorValidationResult(messages, fieldFindings, Instant.now());

        assertThat(result.hasErrors()).isFalse();
    }

    @Test
    void hasFieldFindingFor_trueWhenFindingExists() {
        var fieldFindings = List.of(GuiFieldFinding.error("source.folder", "Pflichtfeld fehlt"));
        var result = new GuiEditorValidationResult(List.of(), fieldFindings, Instant.now());

        assertThat(result.hasFieldFindingFor("source.folder")).isTrue();
    }

    @Test
    void hasFieldFindingFor_falseWhenFindingAbsent() {
        var result = GuiEditorValidationResult.empty();
        assertThat(result.hasFieldFindingFor("source.folder")).isFalse();
    }

    @Test
    void messages_isDefensiveCopy() {
        var mutableMessages = new java.util.ArrayList<>(
                List.of(GuiMessageEntry.of(GuiMessageSeverity.INFO, "info")));
        var result = new GuiEditorValidationResult(mutableMessages, List.of(), Instant.now());
        mutableMessages.add(GuiMessageEntry.of(GuiMessageSeverity.ERROR, "error"));

        assertThat(result.messages()).hasSize(1);
    }

    @Test
    void fieldFindings_isDefensiveCopy() {
        var mutableFindings = new java.util.ArrayList<>(
                List.of(GuiFieldFinding.error("f", "t")));
        var result = new GuiEditorValidationResult(List.of(), mutableFindings, Instant.now());
        mutableFindings.add(GuiFieldFinding.warning("g", "t2"));

        assertThat(result.fieldFindings()).hasSize(1);
    }

    @Test
    void rejectsNullMessages() {
        assertThatNullPointerException()
                .isThrownBy(() -> new GuiEditorValidationResult(null, List.of(), Instant.now()));
    }

    @Test
    void rejectsNullFieldFindings() {
        assertThatNullPointerException()
                .isThrownBy(() -> new GuiEditorValidationResult(List.of(), null, Instant.now()));
    }

    @Test
    void rejectsNullTimestamp() {
        assertThatNullPointerException()
                .isThrownBy(() -> new GuiEditorValidationResult(List.of(), List.of(), null));
    }

    @Test
    void hasFieldFindingFor_rejectsNullFieldKey() {
        var result = GuiEditorValidationResult.empty();
        assertThatNullPointerException()
                .isThrownBy(() -> result.hasFieldFindingFor(null));
    }
}
