package at.procon.dip.search.integration;

import at.procon.dip.domain.document.DocumentFamily;
import at.procon.dip.domain.document.DocumentType;
import at.procon.dip.domain.document.RepresentationType;
import at.procon.dip.search.api.SearchExecutionContext;
import at.procon.dip.search.dto.*;
import at.procon.dip.search.engine.trigram.PostgresTrigramSearchEngine;
import at.procon.dip.search.service.SearchOrchestrator;
import at.procon.dip.search.spi.SearchDocumentScope;
import at.procon.dip.testsupport.AbstractSearchIntegrationTest;
import at.procon.dip.testsupport.SearchTestDataFactory;
import java.util.List;
import java.util.Set;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.annotation.DirtiesContext;

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

//@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_CLASS)
class GenericSearchOrchestratorIntegrationTest extends AbstractSearchIntegrationTest {

    @Autowired
    private SearchTestDataFactory dataFactory;

    @Autowired
    private SearchOrchestrator searchOrchestrator;

    @Autowired
    private PostgresTrigramSearchEngine trigramSearchEngine;

    @Test
    void hybridSearch_should_collapse_document_hits_when_fulltext_and_trigram_match_same_document() {
        dataFactory.createDocumentWithPrimaryRepresentation(
                "Maintenance manual",
                "Factory maintenance manual",
                "Maintenance manual for calibration and preventive checks.",
                DocumentType.PDF,
                DocumentFamily.KNOWLEDGE,
                "en",
                RepresentationType.FULLTEXT);

        SearchRequest request = SearchRequest.builder()
                .queryText("Maintenance manual")
                .modes(Set.of(SearchMode.HYBRID))
                .collapseByDocument(true)
                .representationSelectionMode(SearchRepresentationSelectionMode.PRIMARY_ONLY)
                .build();

        SearchResponse response = searchOrchestrator.search(
                request,
                new SearchDocumentScope(Set.of(), null, null, null, null, null));

        assertThat(response.getHits()).hasSize(1);
        assertThat(response.getHits().getFirst().getTitle()).isEqualTo("Maintenance manual");
        assertThat(response.getEnginesUsed()).isNotEmpty();
        assertThat(response.getHits().getFirst().getFinalScore()).isGreaterThan(0.0d);
    }

    @Test
    void representationSelectionMode_should_control_chunk_visibility() {
        dataFactory.createDocumentWithPrimaryAndChunks(
                "Energy optimization strategy",
                "Strategy overview",
                "This primary representation only contains a high level overview.",
                "en",
                List.of(
                        "Chunk one is introductory and does not contain the target phrase.",
                        "District heating optimization strategy for municipal energy systems is described here."
                ));

        SearchRequest primaryOnly = SearchRequest.builder()
                .queryText("district heating optimization")
                .modes(Set.of(SearchMode.FULLTEXT))
                .representationSelectionMode(SearchRepresentationSelectionMode.PRIMARY_ONLY)
                .build();

        SearchRequest primaryAndChunks = SearchRequest.builder()
                .queryText("district heating optimization")
                .modes(Set.of(SearchMode.FULLTEXT))
                .representationSelectionMode(SearchRepresentationSelectionMode.PRIMARY_AND_CHUNKS)
                .build();

        SearchResponse primaryOnlyResponse = searchOrchestrator.search(
                primaryOnly,
                new SearchDocumentScope(Set.of(), Set.of(DocumentType.TEXT), Set.of(DocumentFamily.GENERIC), null, null, null));

        SearchResponse primaryAndChunksResponse = searchOrchestrator.search(
                primaryAndChunks,
                new SearchDocumentScope(Set.of(), Set.of(DocumentType.TEXT), Set.of(DocumentFamily.GENERIC), null, null, null));

        assertThat(primaryOnlyResponse.getHits()).isEmpty();
        assertThat(primaryAndChunksResponse.getHits()).hasSize(1);
        assertThat(primaryAndChunksResponse.getHits().getFirst().getTitle()).isEqualTo("Energy optimization strategy");
        assertThat(primaryAndChunksResponse.getHits().getFirst().getMatchedRepresentationCount()).isGreaterThanOrEqualTo(1);
        assertThat(primaryAndChunksResponse.getHits().getFirst().getRepresentationType()).isEqualTo(RepresentationType.CHUNK);
    }

    @Test
    void trigramMode_should_find_document_by_fuzzy_title() {
        dataFactory.createDocumentWithPrimaryAndChunks(
                "Energy optimization strategy",
                "Planning note",
                "This primary representation contains only generic background information.",
                "en",
                List.of(
                        "This chunk talks about municipal utilities and operations.",
                        "This chunk contains unrelated technical background."
                ));

        SearchRequest request = SearchRequest.builder()
                .queryText("Enegry optimiztion stratgy")
                .modes(Set.of(SearchMode.TRIGRAM))
                .build();

        SearchResponse response = searchOrchestrator.search(
                request,
                new SearchDocumentScope(
                        Set.of(),
                        Set.of(DocumentType.TEXT),
                        Set.of(DocumentFamily.GENERIC),
                        null,
                        null,
                        null
                )
        );

        assertThat(response.getHits()).isNotEmpty();
        assertThat(response.getHits()).hasSize(1);

        SearchHit first = response.getHits().getFirst();
        assertThat(first.getTitle()).isEqualTo("Energy optimization strategy");
        assertThat(first.getPrimaryEngine()).isEqualTo(SearchEngineType.POSTGRES_TRIGRAM);
        assertThat(first.getMatchedField()).isEqualTo(SearchMatchField.DOCUMENT_TITLE);
        assertThat(first.getFinalScore()).isGreaterThan(0.0);
    }

    @Test
    void trigramRepository_should_find_document_by_fuzzy_title() {
        dataFactory.createDocumentWithPrimaryAndChunks(
                "Energy optimization strategy",
                "Planning note",
                "This primary representation contains only generic background information.",
                "en",
                List.of(
                        "This chunk talks about municipal utilities and operations.",
                        "This chunk contains unrelated technical background."
                ));

        SearchRequest request = SearchRequest.builder()
                .queryText("Enegry optimiztion stratgy")
                .modes(Set.of(SearchMode.TRIGRAM))
                .build();

        SearchExecutionContext context = SearchExecutionContext.builder()
                .request(request)
                .scope(new SearchDocumentScope(
                        Set.of(),
                        Set.of(DocumentType.TEXT),
                        Set.of(DocumentFamily.GENERIC),
                        null,
                        null,
                        null
                ))
                .page(0)
                .size(10)
                .build();

        List<SearchHit> hits = trigramSearchEngine.execute(context);

        assertThat(hits).isNotEmpty();
        assertThat(hits.getFirst().getTitle()).isEqualTo("Energy optimization strategy");
        assertThat(hits.getFirst().getPrimaryEngine()).isEqualTo(SearchEngineType.POSTGRES_TRIGRAM);
    }
}
