package com.arms.egovframework.javaservice.esframework.custom.client;

import static org.springframework.util.CollectionUtils.isEmpty;

import lombok.extern.slf4j.Slf4j;
import org.opensearch.action.search.SearchRequest;
import org.opensearch.action.search.SearchResponse;
import org.opensearch.client.RequestOptions;
import org.opensearch.client.RestHighLevelClient;
import org.opensearch.data.client.orhlc.OpenSearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.data.elasticsearch.core.query.Query;

/**
 * OpenSearchRestTemplate 확장
 * _source = false 와 docValueFields를 지원안하는 사유로 인해
 * search 메소드 부분 customRequestFactory 별도로 커스터마이징 해서 사용 하고 그외 로직 동일
 * customRequestFactory 는 prepareSearchRequest 만 _source = false 및 docValueFields 필드 처리하는 부분만 추가 그외 로직 동일 하여
 * 영향도 최소화
 *
 * 추가 변경:
 * - CustomSearchDocumentResponseBuilder 사용으로 배열 필드 정상 처리
 */
@Slf4j
public class CustomOpenSearchRestTemplate extends OpenSearchRestTemplate {

    private final CustomRequestFactory customRequestFactory;

    public CustomOpenSearchRestTemplate(RestHighLevelClient client, ElasticsearchConverter elasticsearchConverter) {
        super(client, elasticsearchConverter);
        customRequestFactory = new CustomRequestFactory(elasticsearchConverter);
    }

    @Override
    public <T> SearchHits<T> search(Query query, Class<T> clazz, IndexCoordinates index) {

        // docValueFields가 없으면 원본 search 메서드 사용
        if (isEmpty(query.getDocValueFields())) {
            return super.search(query, clazz, index);
        }

        // docValueFields가 있을 때만 커스텀 로직 실행
        SearchRequest searchRequest = customRequestFactory.searchRequest(query, routingResolver.getRouting(), clazz, index);
        SearchResponse response = execute(client -> client.search(searchRequest, RequestOptions.DEFAULT));

        ReadDocumentCallback<T> documentCallback = new ReadDocumentCallback<>(elasticsearchConverter, clazz, index);
        SearchDocumentResponseCallback<SearchHits<T>> callback = new ReadSearchDocumentResponseCallback<>(clazz, index);

        return callback.doWith(CustomSearchDocumentResponseBuilder.from(response, getEntityCreator(documentCallback)));
    }
}
