import { HttpService } from "@nestjs/axios";
import { GatewayTimeoutException, Injectable } from "@nestjs/common";
import { map, take } from "rxjs";
import { EsResponseDto } from "src/core/domain/dtos";
import { EsQueryDto } from "src/core/domain/dtos/es-query.dto";
import { SearchResultDto } from "src/core/domain/dtos/search-result.dto";
import { EsTime } from "src/core/domain/enums/es-time.enum";
import { EsPit } from "src/core/domain/interfaces/es-pit.interface";

/**
 * 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;
    
    /**
     * Finds a paper by its own ID
     * @param uuid 
     * @returns Elasticsearch hits or an error object
     */
    async findByID(uuid: string): Promise<SearchResultDto> { // 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://localhost:${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) {
                        throw new GatewayTimeoutException;
                        // reject(new SearchResultDto(504, {message: 'Timed Out'}));
                    }

                    resolve(new SearchResultDto(200, res));
                });
            } catch (error) {
                reject(new SearchResultDto(700, 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<SearchResultDto> {
        console.log(`SEARCH|SERVICE: ${JSON.stringify(es_query, null, 2)}`);
        return new Promise((resolve, reject) => {
            try {
                (this.httpService.get<EsResponseDto>(`http://localhost:${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) {
                        throw new GatewayTimeoutException;
                        // reject(new SearchResultDto(504, {status: 504, message: 'Timed Out'}));
                    }

                    resolve(new SearchResultDto(200, res));
                });
            } catch (error) {
                reject(new SearchResultDto(700, error));
            }
        });
    }
}

// let ESQ: EsQueryDto = new EsQueryDto;

        // if (limit) ESQ.size = limit;
        // ESQ.query = {
        //     query_string: {
        //         query: query_str,
        //         default_field: 'content',
        //     }
        // }
        // this.getPIT(1).then((pit) => {
        //     ESQ.pit = pit;
        // });

/**
 * Context
 *      // let es_query = { // DTO
        //     query: { // Interface
        //         query_string: { // Interface
        //             query: query_str,
        //             default_field: "content"
        //         }
        //     },
        // }
 */

/**
 * Single
 *      // let es_query = {
        //     query: {
        //         query_string: {
        //             query: 'id:' + uuid
        //         }
        //     },
        // }
 */