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 PromptIdentifier} value object.
 * <p>
 * Verifies immutability, value semantics, and correct handling of prompt identifiers.
 */
class PromptIdentifierTest {

    private static final String VALID_IDENTIFIER_1 = "prompt_de_v1.txt";
    private static final String VALID_IDENTIFIER_2 = "2026-03-v2";
    private static final String VALID_IDENTIFIER_3 = "sha256:abc123def456";

    @Test
    void constructor_createsPromptIdentifierWithValidIdentifier() {
        PromptIdentifier identifier = new PromptIdentifier(VALID_IDENTIFIER_1);
        assertNotNull(identifier);
        assertEquals(VALID_IDENTIFIER_1, identifier.identifier());
    }

    @Test
    void constructor_throwsNullPointerExceptionWhenIdentifierIsNull() {
        assertThrows(NullPointerException.class, () -> new PromptIdentifier(null),
                "Constructor should throw NullPointerException for null identifier");
    }

    @Test
    void constructor_acceptsEmptyIdentifier() {
        PromptIdentifier identifier = new PromptIdentifier("");
        assertEquals("", identifier.identifier());
    }

    @Test
    void constructor_acceptsVariousIdentifierFormats() {
        PromptIdentifier id1 = new PromptIdentifier(VALID_IDENTIFIER_1);
        PromptIdentifier id2 = new PromptIdentifier(VALID_IDENTIFIER_2);
        PromptIdentifier id3 = new PromptIdentifier(VALID_IDENTIFIER_3);

        assertEquals(VALID_IDENTIFIER_1, id1.identifier());
        assertEquals(VALID_IDENTIFIER_2, id2.identifier());
        assertEquals(VALID_IDENTIFIER_3, id3.identifier());
    }

    @Test
    void identifier_returnsTheConstructorValue() {
        PromptIdentifier identifier = new PromptIdentifier(VALID_IDENTIFIER_1);
        assertEquals(VALID_IDENTIFIER_1, identifier.identifier());
    }

    @Test
    void equals_returnsTrueForIdenticalIdentifiers() {
        PromptIdentifier id1 = new PromptIdentifier(VALID_IDENTIFIER_1);
        PromptIdentifier id2 = new PromptIdentifier(VALID_IDENTIFIER_1);
        assertEquals(id1, id2);
    }

    @Test
    void equals_returnsFalseForDifferentIdentifiers() {
        PromptIdentifier id1 = new PromptIdentifier(VALID_IDENTIFIER_1);
        PromptIdentifier id2 = new PromptIdentifier(VALID_IDENTIFIER_2);
        assertNotEquals(id1, id2);
    }

    @Test
    void equals_returnsFalseWhenComparedWithNull() {
        PromptIdentifier identifier = new PromptIdentifier(VALID_IDENTIFIER_1);
        assertNotEquals(null, identifier);
    }

    @Test
    void equals_returnsFalseWhenComparedWithDifferentType() {
        PromptIdentifier identifier = new PromptIdentifier(VALID_IDENTIFIER_1);
        assertNotEquals(VALID_IDENTIFIER_1, identifier);
    }

    @Test
    void hashCode_isSameForIdenticalIdentifiers() {
        PromptIdentifier id1 = new PromptIdentifier(VALID_IDENTIFIER_1);
        PromptIdentifier id2 = new PromptIdentifier(VALID_IDENTIFIER_1);
        assertEquals(id1.hashCode(), id2.hashCode());
    }

    @Test
    void hashCode_isDifferentForDifferentIdentifiers() {
        PromptIdentifier id1 = new PromptIdentifier(VALID_IDENTIFIER_1);
        PromptIdentifier id2 = new PromptIdentifier(VALID_IDENTIFIER_2);
        assertNotEquals(id1.hashCode(), id2.hashCode());
    }

    @Test
    void toString_containsTheIdentifier() {
        PromptIdentifier identifier = new PromptIdentifier(VALID_IDENTIFIER_1);
        assertTrue(identifier.toString().contains(VALID_IDENTIFIER_1));
    }

    @Test
    void promptIdentifierCanBeUsedAsMapKey() {
        PromptIdentifier id1 = new PromptIdentifier(VALID_IDENTIFIER_1);
        PromptIdentifier id2 = new PromptIdentifier(VALID_IDENTIFIER_1);
        PromptIdentifier id3 = new PromptIdentifier(VALID_IDENTIFIER_2);

        var map = new java.util.HashMap<PromptIdentifier, String>();
        map.put(id1, "first");
        map.put(id2, "second"); // Should overwrite
        map.put(id3, "third");

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

    @Test
    void promptIdentifierCanBeUsedInSets() {
        PromptIdentifier id1 = new PromptIdentifier(VALID_IDENTIFIER_1);
        PromptIdentifier id2 = new PromptIdentifier(VALID_IDENTIFIER_1);
        PromptIdentifier id3 = new PromptIdentifier(VALID_IDENTIFIER_2);

        var set = new java.util.HashSet<PromptIdentifier>();
        set.add(id1);
        set.add(id2); // Should not add duplicate
        set.add(id3);

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

    @Test
    void constructor_acceptsIdentifierWithSpecialCharacters() {
        String specialIdentifier = "prompt-de_v1.2.3@stable";
        PromptIdentifier identifier = new PromptIdentifier(specialIdentifier);
        assertEquals(specialIdentifier, identifier.identifier());
    }

    @Test
    void constructor_acceptsVeryLongIdentifier() {
        String longIdentifier = "x".repeat(1000);
        PromptIdentifier identifier = new PromptIdentifier(longIdentifier);
        assertEquals(longIdentifier, identifier.identifier());
    }
}
