package de.gecheckt.pdf.umbenenner.domain.model;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;

import org.junit.jupiter.api.Test;

/**
 * Unit tests for {@link AiRawResponse} value object.
 * <p>
 * Verifies immutability, value semantics, and correct handling of raw AI responses.
 */
class AiRawResponseTest {

    private static final String VALID_JSON_RESPONSE = "{\"date\": \"2026-03-05\", \"title\": \"Stromabrechnung\", \"reasoning\": \"...\"}";
    private static final String MALFORMED_JSON = "{invalid json}";
    private static final String EMPTY_RESPONSE = "";
    private static final String WHITESPACE_RESPONSE = "   ";

    @Test
    void constructor_createsAiRawResponseWithValidContent() {
        AiRawResponse response = new AiRawResponse(VALID_JSON_RESPONSE);
        assertNotNull(response);
        assertEquals(VALID_JSON_RESPONSE, response.content());
    }

    @Test
    void constructor_throwsNullPointerExceptionWhenContentIsNull() {
        assertThrows(NullPointerException.class, () -> new AiRawResponse(null),
                "Constructor should throw NullPointerException for null content");
    }

    @Test
    void constructor_acceptsEmptyContent() {
        AiRawResponse response = new AiRawResponse(EMPTY_RESPONSE);
        assertEquals(EMPTY_RESPONSE, response.content());
    }

    @Test
    void constructor_acceptsMalformedJsonContent() {
        AiRawResponse response = new AiRawResponse(MALFORMED_JSON);
        assertEquals(MALFORMED_JSON, response.content());
    }

    @Test
    void constructor_acceptsWhitespaceOnlyContent() {
        AiRawResponse response = new AiRawResponse(WHITESPACE_RESPONSE);
        assertEquals(WHITESPACE_RESPONSE, response.content());
    }

    @Test
    void content_returnsTheConstructorValue() {
        AiRawResponse response = new AiRawResponse(VALID_JSON_RESPONSE);
        assertEquals(VALID_JSON_RESPONSE, response.content());
    }

    @Test
    void equals_returnsTrueForIdenticalContent() {
        AiRawResponse response1 = new AiRawResponse(VALID_JSON_RESPONSE);
        AiRawResponse response2 = new AiRawResponse(VALID_JSON_RESPONSE);
        assertEquals(response1, response2);
    }

    @Test
    void equals_returnsFalseForDifferentContent() {
        AiRawResponse response1 = new AiRawResponse(VALID_JSON_RESPONSE);
        AiRawResponse response2 = new AiRawResponse(MALFORMED_JSON);
        assertNotEquals(response1, response2);
    }

    @Test
    void equals_returnsFalseWhenComparedWithNull() {
        AiRawResponse response = new AiRawResponse(VALID_JSON_RESPONSE);
        assertNotEquals(null, response);
    }

    @Test
    void equals_returnsFalseWhenComparedWithDifferentType() {
        AiRawResponse response = new AiRawResponse(VALID_JSON_RESPONSE);
        assertNotEquals(VALID_JSON_RESPONSE, response);
    }

    @Test
    void hashCode_isSameForIdenticalContent() {
        AiRawResponse response1 = new AiRawResponse(VALID_JSON_RESPONSE);
        AiRawResponse response2 = new AiRawResponse(VALID_JSON_RESPONSE);
        assertEquals(response1.hashCode(), response2.hashCode());
    }

    @Test
    void hashCode_isDifferentForDifferentContent() {
        AiRawResponse response1 = new AiRawResponse(VALID_JSON_RESPONSE);
        AiRawResponse response2 = new AiRawResponse(MALFORMED_JSON);
        assertNotEquals(response1.hashCode(), response2.hashCode());
    }

    @Test
    void toString_containsTheContent() {
        AiRawResponse response = new AiRawResponse(VALID_JSON_RESPONSE);
        assertTrue(response.toString().contains(VALID_JSON_RESPONSE));
    }

    @Test
    void aiRawResponseCanBeUsedAsMapKey() {
        AiRawResponse response1 = new AiRawResponse(VALID_JSON_RESPONSE);
        AiRawResponse response2 = new AiRawResponse(VALID_JSON_RESPONSE);
        AiRawResponse response3 = new AiRawResponse(MALFORMED_JSON);

        var map = new java.util.HashMap<AiRawResponse, String>();
        map.put(response1, "first");
        map.put(response2, "second"); // Should overwrite
        map.put(response3, "third");

        assertEquals(2, map.size());
        assertEquals("second", map.get(response1));
    }

    @Test
    void aiRawResponseCanBeUsedInSets() {
        AiRawResponse response1 = new AiRawResponse(VALID_JSON_RESPONSE);
        AiRawResponse response2 = new AiRawResponse(VALID_JSON_RESPONSE);
        AiRawResponse response3 = new AiRawResponse(MALFORMED_JSON);

        var set = new java.util.HashSet<AiRawResponse>();
        set.add(response1);
        set.add(response2); // Should not add duplicate
        set.add(response3);

        assertEquals(2, set.size());
    }

    @Test
    void constructor_preservesExactContentWithSpecialCharacters() {
        String contentWithSpecialChars = "{\"text\": \"Special chars: äöü€\\n\\t\"}";
        AiRawResponse response = new AiRawResponse(contentWithSpecialChars);
        assertEquals(contentWithSpecialChars, response.content());
    }

    @Test
    void constructor_preservesVeryLongContent() {
        String longContent = "x".repeat(10000);
        AiRawResponse response = new AiRawResponse(longContent);
        assertEquals(longContent, response.content());
    }
}
