package at.procon.dip.search.repository;

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

import at.procon.dip.domain.document.DocumentFamily;
import at.procon.dip.domain.document.DocumentType;
import at.procon.dip.domain.document.DocumentAttributeValueType;
import at.procon.dip.search.api.SearchExecutionContext;
import at.procon.dip.search.dto.DocumentAttributeFilterOperator;
import at.procon.dip.search.dto.DocumentAttributeFilterRequest;
import at.procon.dip.search.dto.SearchRepresentationSelectionMode;
import at.procon.dip.search.dto.SearchRequest;
import at.procon.dip.search.spi.SearchDocumentScope;
import org.junit.jupiter.api.Test;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;

class SearchSqlFilterSupportTest {

    @Test
    void shouldAppendAttributeFilterSql() {
        SearchRequest request = SearchRequest.builder()
                .queryText("kitchen")
                .attributeFilters(java.util.List.of(
                        DocumentAttributeFilterRequest.builder()
                                .name("status")
                                .context("ted")
                                .type(DocumentAttributeValueType.STRING)
                                .operator(DocumentAttributeFilterOperator.EQ)
                                .stringValue("closed")
                                .build(),
                        DocumentAttributeFilterRequest.builder()
                                .name("version")
                                .type(DocumentAttributeValueType.INTEGER)
                                .operator(DocumentAttributeFilterOperator.GTE)
                                .integerValue(3L)
                                .build()
                ))
                .build();
        SearchExecutionContext context = SearchExecutionContext.builder()
                .request(request)
                .scope(new SearchDocumentScope(java.util.Set.of(), null, null, null, null, null))
                .page(0)
                .size(20)
                .build();

        StringBuilder sql = new StringBuilder("SELECT 1 FROM doc.doc_document d JOIN doc.doc_text_representation dtr ON dtr.document_id = d.id WHERE 1=1");
        MapSqlParameterSource params = new MapSqlParameterSource();
        SearchSqlFilterSupport.appendCommonFilters(sql, params, context, "d", "dtr", false);

        String rendered = sql.toString();
        assertThat(rendered).contains("doc.doc_document_attribute");
        assertThat(rendered).contains("attribute_context = :attributeContext0");
        assertThat(rendered).contains("integer_value >= :attributeValue1");
        assertThat(params.getValue("attributeName0")).isEqualTo("status");
        assertThat(params.getValue("attributeContext0")).isEqualTo("TED");
        assertThat(params.getValue("attributeValue0")).isEqualTo("closed");
        assertThat(params.getValue("attributeName1")).isEqualTo("version");
        assertThat(params.getValue("attributeValue1")).isEqualTo(3L);
    }

    @Test
    void shouldUseTypedEnumComparisonsForIndexedFilters() {
        SearchRequest request = SearchRequest.builder()
                .queryText("vertrieb")
                .documentTypes(java.util.Set.of(DocumentType.TIME_ENTRY))
                .documentFamilies(java.util.Set.of(DocumentFamily.TIME))
                .representationSelectionMode(SearchRepresentationSelectionMode.PRIMARY_AND_CHUNKS)
                .build();
        SearchExecutionContext context = SearchExecutionContext.builder()
                .request(request)
                .scope(new SearchDocumentScope(java.util.Set.of(), null, null, null, null, null))
                .page(0)
                .size(20)
                .build();

        StringBuilder sql = new StringBuilder("SELECT 1 FROM doc.doc_document d JOIN doc.doc_text_representation dtr ON dtr.document_id = d.id WHERE 1=1");
        MapSqlParameterSource params = new MapSqlParameterSource();
        SearchSqlFilterSupport.appendCommonFilters(sql, params, context, "d", "dtr", false);

        String rendered = sql.toString();
        assertThat(rendered).contains("CAST(d.document_type AS text) IN (:documentTypes)");
        assertThat(rendered).contains("CAST(d.document_family AS text) IN (:documentFamilies)");
        assertThat(rendered).contains("CAST(dtr.representation_type AS text) = 'CHUNK'");
        assertThat(params.getValue("documentTypes")).isEqualTo(java.util.List.of("TIME_ENTRY"));
        assertThat(params.getValue("documentFamilies")).isEqualTo(java.util.List.of("TIME"));
    }
}
