import { HttpService } from "@nestjs/axios";
import { GatewayTimeoutException, HttpException, Injectable } from "@nestjs/common";
import { map, take } from "rxjs";
import { EsResponseDto} from "../../domain/dtos";
import { EsQueryDto } from "../../domain/dtos/elastic/es-query.dto";

/**
 * Search service provider
 */
@Injectable()
export class SearchService {
    /**
     * Constructs the service with injection of
     * HTTPService instance
     * @param httpService 
     */
    constructor(private readonly httpService: HttpService) {}

    /**
     * Elastichsearch server port-number
     */
    private readonly ES_PORT = process.env.ES_PORT;
    
    /**
     * Elasticsearch IP address
     */
    private readonly ES_IP = process.env.ES_CONTAINER_NAME;
    
    /**
     * Finds a paper by its own ID
     * @param uuid 
     * @returns Elasticsearch hits or an error object
     */
    async findByID(uuid: string): Promise<EsResponseDto> { // Should I change 'object' to specific DTO?
        let ESQ: EsQueryDto = new EsQueryDto;

        ESQ.size = 1;
        ESQ.query = {
            query_string: {
                query: ('id:' + uuid),
            }
        }

        return new Promise((resolve, reject) => {
            try {
                (this.httpService.get<EsResponseDto>(`http://${this.ES_IP}:${this.ES_PORT}/_search`, {
                    data: ESQ,
                    headers: {'Content-Type': 'application/json'},
                }))
                ?.pipe(take(1), map(axiosRes => axiosRes.data))
                .subscribe((res: EsResponseDto) => {
                    if (res.timed_out) {
                        reject(new GatewayTimeoutException('Elasticsearch Timed Out'));
                    }
                    resolve(res);
                });
            } catch (error) {
                reject(error);
            }
        });
    }

    /**
     * Finds relevant documents by context using the given query string
     * @param query, <EsQueryDto> 
     * @returns Elasticsearch hits or an error object
     */
    async findByContext(es_query: EsQueryDto): Promise<EsResponseDto> {
        return new Promise((resolve, reject) => {
            try {
                (this.httpService.get<EsResponseDto>(`http://${this.ES_IP}:${this.ES_PORT}/_search`, {
                    data: es_query,
                    headers: {'Content-Type': 'application/json'},
                }))
                ?.pipe(take(1), map(axiosRes => axiosRes.data))
                .subscribe((res: EsResponseDto) => {
                    if (res.timed_out) {
                        reject(new GatewayTimeoutException('Elasticsearch Timed Out'));
                    }

                    resolve(res);
                });
            } catch (error) {
                reject(error);
            }
        });
    }
}