package at.procon.dip.search.repository;

import at.procon.dip.search.api.SearchExecutionContext;
import at.procon.dip.search.dto.SearchEngineType;
import at.procon.dip.search.dto.SearchHit;
import at.procon.dip.search.dto.SearchMatchField;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.stereotype.Repository;

@Repository
@RequiredArgsConstructor
public class DocumentTrigramSearchRepositoryImpl implements DocumentTrigramSearchRepository {

    private final NamedParameterJdbcTemplate jdbcTemplate;

    @Override
    public List<SearchHit> search(SearchExecutionContext context, int limit, double threshold) {
        String scoreExpr = "GREATEST(" +
                "doc.similarity(COALESCE(d.title, ''), :queryText), " +
                "doc.similarity(COALESCE(d.summary, ''), :queryText), " +
                "doc.similarity(COALESCE(dtr.text_body, ''), :queryText))";

        StringBuilder sql = new StringBuilder("SELECT " +
                "d.id AS document_id, " +
                "dtr.id AS representation_id, " +
                "CAST(d.document_type AS text) AS document_type, " +
                "CAST(d.document_family AS text) AS document_family, " +
                "CAST(d.visibility AS text) AS visibility, " +
                "d.title AS title, " +
                "d.summary AS summary, " +
                "COALESCE(dtr.language_code, d.language_code) AS language_code, " +
                "d.mime_type AS mime_type, " +
                "d.created_at AS created_at, " +
                "d.updated_at AS updated_at, " +
                "LEFT(COALESCE(dtr.text_body, COALESCE(d.summary, d.title, '')), 400) AS snippet, " +
                scoreExpr + " AS score, " +
                "CASE " +
                "WHEN doc.similarity(COALESCE(d.title, ''), :queryText) >= doc.similarity(COALESCE(d.summary, ''), :queryText) " +
                " AND doc.similarity(COALESCE(d.title, ''), :queryText) >= doc.similarity(COALESCE(dtr.text_body, ''), :queryText) THEN 'DOCUMENT_TITLE' " +
                "WHEN doc.similarity(COALESCE(d.summary, ''), :queryText) >= doc.similarity(COALESCE(dtr.text_body, ''), :queryText) THEN 'DOCUMENT_SUMMARY' " +
                "ELSE 'REPRESENTATION_TEXT' END AS matched_field " +
                "FROM doc.doc_text_representation dtr " +
                "JOIN doc.doc_document d ON d.id = dtr.document_id " +
                "LEFT JOIN doc.doc_tenant dt ON dt.id = d.owner_tenant_id " +
                "WHERE " + scoreExpr + " >= :threshold");

        MapSqlParameterSource params = new MapSqlParameterSource();
        params.addValue("queryText", context.getRequest().getQueryText());
        params.addValue("threshold", threshold);
        SearchSqlFilterSupport.appendCommonFilters(sql, params, context, "d", "dtr", true);
        sql.append(" ORDER BY score DESC, d.updated_at DESC LIMIT :limit");
        params.addValue("limit", limit);

        return jdbcTemplate.query(sql.toString(), params,
                new SearchHitRowMapper(SearchEngineType.POSTGRES_TRIGRAM, SearchMatchField.REPRESENTATION_TEXT));
    }
}
