package org.raddatz.familienarchiv.document.transcription;

import jakarta.persistence.EntityManager;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.raddatz.familienarchiv.PostgresContainerConfig;
import org.raddatz.familienarchiv.config.FlywayConfig;
import org.raddatz.familienarchiv.document.annotation.AnnotationRepository;
import org.raddatz.familienarchiv.document.DocumentRepository;
import org.raddatz.familienarchiv.document.Document;
import org.raddatz.familienarchiv.document.annotation.DocumentAnnotation;
import org.raddatz.familienarchiv.document.DocumentStatus;
import org.raddatz.familienarchiv.document.transcription.PersonMention;
import org.raddatz.familienarchiv.document.transcription.TranscriptionBlock;
import org.raddatz.familienarchiv.person.Person;
import org.raddatz.familienarchiv.person.PersonRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.jdbc.test.autoconfigure.AutoConfigureTestDatabase;
import org.springframework.boot.data.jpa.test.autoconfigure.DataJpaTest;
import org.springframework.context.annotation.Import;

import java.util.List;
import java.util.UUID;

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

@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@Import({PostgresContainerConfig.class, FlywayConfig.class})
class TranscriptionBlockMentionsRepositoryTest {

    @Autowired TranscriptionBlockRepository blockRepository;
    @Autowired DocumentRepository documentRepository;
    @Autowired AnnotationRepository annotationRepository;
    @Autowired PersonRepository personRepository;
    @Autowired EntityManager em;

    private UUID documentId;
    private UUID annotationId;

    @BeforeEach
    void setUp() {
        Document doc = documentRepository.save(Document.builder()
                .title("Letter")
                .originalFilename("letter.pdf")
                .status(DocumentStatus.UPLOADED)
                .build());
        documentId = doc.getId();

        DocumentAnnotation annotation = annotationRepository.save(DocumentAnnotation.builder()
                .documentId(documentId)
                .pageNumber(1)
                .x(0.1).y(0.2).width(0.3).height(0.4)
                .color("#00C7B1")
                .build());
        annotationId = annotation.getId();
    }

    @Test
    void mentionedPersons_roundTripsTwoEntries() {
        // person_id is a real FK since V71 — the mentioned persons must exist.
        UUID auguste = personRepository.save(Person.builder().firstName("Auguste").lastName("Raddatz").build()).getId();
        UUID hermann = personRepository.save(Person.builder().firstName("Hermann").lastName("Müller").build()).getId();

        TranscriptionBlock saved = blockRepository.saveAndFlush(TranscriptionBlock.builder()
                .annotationId(annotationId)
                .documentId(documentId)
                .text("Liebe Tante @Auguste Raddatz, Onkel @Hermann Müller schreibt …")
                .sortOrder(0)
                .mentionedPersons(List.of(
                        new PersonMention(auguste, "Auguste Raddatz"),
                        new PersonMention(hermann, "Hermann Müller")
                ))
                .build());

        em.clear();

        TranscriptionBlock reloaded = blockRepository.findById(saved.getId()).orElseThrow();

        assertThat(reloaded.getMentionedPersons())
                .extracting(PersonMention::getPersonId, PersonMention::getDisplayName)
                .containsExactlyInAnyOrder(
                        org.assertj.core.groups.Tuple.tuple(auguste, "Auguste Raddatz"),
                        org.assertj.core.groups.Tuple.tuple(hermann, "Hermann Müller"));
    }

    @Test
    void mentionedPersons_defaultsToEmptyList_whenNotSet() {
        TranscriptionBlock saved = blockRepository.saveAndFlush(TranscriptionBlock.builder()
                .annotationId(annotationId)
                .documentId(documentId)
                .text("Plain text without mentions")
                .sortOrder(0)
                .build());

        em.clear();

        TranscriptionBlock reloaded = blockRepository.findById(saved.getId()).orElseThrow();
        assertThat(reloaded.getMentionedPersons()).isEmpty();
    }

    @Test
    void findByPersonIdWithMentionsFetched_returnsOnlyBlocksReferencingPerson_withMentionsLoaded() {
        // person_id is a real FK since V71 — the mentioned persons must exist.
        UUID augusteId = personRepository.save(Person.builder().firstName("Auguste").lastName("Raddatz").build()).getId();
        UUID hermannId = personRepository.save(Person.builder().firstName("Hermann").lastName("Müller").build()).getId();

        blockRepository.saveAndFlush(TranscriptionBlock.builder()
                .annotationId(annotationId).documentId(documentId)
                .text("Brief von @Auguste Raddatz an @Hermann Müller.")
                .sortOrder(0)
                .mentionedPersons(List.of(
                        new PersonMention(augusteId, "Auguste Raddatz"),
                        new PersonMention(hermannId, "Hermann Müller")))
                .build());
        blockRepository.saveAndFlush(TranscriptionBlock.builder()
                .annotationId(annotationId).documentId(documentId)
                .text("Unrelated block without Auguste.")
                .sortOrder(1)
                .mentionedPersons(List.of(new PersonMention(hermannId, "Hermann Müller")))
                .build());
        em.clear();

        List<TranscriptionBlock> result =
                blockRepository.findByPersonIdWithMentionsFetched(augusteId);

        assertThat(result).hasSize(1);
        assertThat(result.get(0).getMentionedPersons())
                .extracting(PersonMention::getPersonId, PersonMention::getDisplayName)
                .containsExactlyInAnyOrder(
                        org.assertj.core.groups.Tuple.tuple(augusteId, "Auguste Raddatz"),
                        org.assertj.core.groups.Tuple.tuple(hermannId, "Hermann Müller"));
    }
}
