package org.raddatz.familienarchiv.document;

import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.raddatz.familienarchiv.PostgresContainerConfig;
import org.raddatz.familienarchiv.audit.AuditLogQueryService;
import org.raddatz.familienarchiv.ocr.TrainingLabel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Import;
import org.springframework.data.domain.PageRequest;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.bean.override.mockito.MockitoBean;
import software.amazon.awssdk.services.s3.S3Client;

import java.util.HashSet;
import java.util.Set;

import static org.assertj.core.api.Assertions.assertThat;
import static org.raddatz.familienarchiv.document.SearchFiltersFixtures.noFilters;
import static org.assertj.core.api.Assertions.assertThatCode;

/**
 * AC #2: Document with trainingLabels does not cause LazyInitializationException in search.
 * AC #3: Detail API still returns trainingLabels after the Document.list graph change.
 */
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE)
@ActiveProfiles("test")
@Import(PostgresContainerConfig.class)
class DocumentListItemIntegrationTest {

    @MockitoBean
    S3Client s3Client;

    @MockitoBean
    AuditLogQueryService auditLogQueryService;

    @Autowired
    DocumentRepository documentRepository;

    @Autowired
    DocumentService documentService;

    @AfterEach
    void cleanup() {
        documentRepository.deleteAll();
    }

    @Test
    void search_doesNotThrow_whenDocumentHasTrainingLabels() {
        documentRepository.save(Document.builder()
                .title("Kurrent Brief")
                .originalFilename("kurrent.pdf")
                .status(DocumentStatus.UPLOADED)
                .trainingLabels(new HashSet<>(Set.of(TrainingLabel.KURRENT_RECOGNITION)))
                .build());

        assertThatCode(() -> documentService.searchDocuments(
                noFilters(),
                DocumentSort.DATE, "DESC", PageRequest.of(0, 50)))
            .doesNotThrowAnyException();
    }

    @Test
    void search_returns_list_item_without_sensitive_fields_when_document_has_training_labels() {
        documentRepository.save(Document.builder()
                .title("Kurrent Brief")
                .originalFilename("kurrent2.pdf")
                .status(DocumentStatus.UPLOADED)
                .trainingLabels(new HashSet<>(Set.of(TrainingLabel.KURRENT_RECOGNITION)))
                .build());

        DocumentSearchResult result = documentService.searchDocuments(
                noFilters(),
                DocumentSort.DATE, "DESC", PageRequest.of(0, 50));

        assertThat(result.totalElements()).isGreaterThan(0);
        DocumentListItem item = result.items().get(0);
        assertThat(item.id()).isNotNull();
        assertThat(item.title()).isEqualTo("Kurrent Brief");
    }

    @Test
    void search_listItem_carriesMetaDatePrecisionAndEnd() {
        documentRepository.save(Document.builder()
                .title("Range Brief")
                .originalFilename("range.pdf")
                .status(DocumentStatus.UPLOADED)
                .documentDate(java.time.LocalDate.of(1943, 1, 1))
                .metaDatePrecision(DatePrecision.RANGE)
                .metaDateEnd(java.time.LocalDate.of(1943, 12, 31))
                .build());

        DocumentSearchResult result = documentService.searchDocuments(
                noFilters(),
                DocumentSort.DATE, "DESC", PageRequest.of(0, 50));

        DocumentListItem item = result.items().stream()
                .filter(i -> i.title().equals("Range Brief")).findFirst().orElseThrow();
        assertThat(item.metaDatePrecision()).isEqualTo(DatePrecision.RANGE);
        assertThat(item.metaDateEnd()).isEqualTo(java.time.LocalDate.of(1943, 12, 31));
    }

    @Test
    void detail_stillReturnsTrainingLabels() {
        Document saved = documentRepository.save(Document.builder()
                .title("Detail Test")
                .originalFilename("detail_test.pdf")
                .status(DocumentStatus.UPLOADED)
                .trainingLabels(new HashSet<>(Set.of(TrainingLabel.KURRENT_RECOGNITION)))
                .build());

        // Document.full entity graph (used by getDocumentById) must still load trainingLabels
        Document loaded = documentService.getDocumentById(saved.getId());

        assertThat(loaded.getTrainingLabels()).containsExactly(TrainingLabel.KURRENT_RECOGNITION);
    }
}
