import { Document } from "@langchain/core/documents";
import { getEnvironmentVariable } from "@langchain/core/utils/env";
import { BaseDocumentLoader } from "@langchain/core/document_loaders/base";
/**
 * Class representing a document loader for loading search results from
 * the SerpAPI. It extends the BaseDocumentLoader class.
 * @example
 * ```typescript
 * const loader = new SerpAPILoader({ q: "{query}", apiKey: "{apiKey}" });
 * const docs = await loader.load();
 * ```
 */
export class SerpAPILoader extends BaseDocumentLoader {
    constructor(params) {
        super();
        Object.defineProperty(this, "apiKey", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: void 0
        });
        Object.defineProperty(this, "searchQuery", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: void 0
        });
        const { apiKey = getEnvironmentVariable("SERPAPI_API_KEY"), q } = params;
        if (!apiKey) {
            throw new Error("SerpAPI API key not set. You can set it as SERPAPI_API_KEY in your .env file, or pass it to SerpAPI.");
        }
        this.apiKey = apiKey;
        this.searchQuery = q;
    }
    /**
     * Builds the URL for the SerpAPI search request.
     * @returns The URL for the search request.
     */
    buildUrl() {
        const params = new URLSearchParams();
        params.append("api_key", this.apiKey);
        params.append("q", this.searchQuery);
        return `https://serpapi.com/search?${params.toString()}`;
    }
    /**
     * Extracts documents from the provided output.
     * @param output - The output to extract documents from.
     * @param responseType - The type of the response to extract documents from.
     * @returns An array of Documents.
     */
    extractDocuments(output, responseType) {
        const documents = [];
        const results = Array.isArray(output) ? output : [output];
        for (const result of results) {
            const pageContent = JSON.stringify(result);
            const metadata = {
                source: "SerpAPI",
                responseType,
            };
            documents.push(new Document({ pageContent, metadata }));
        }
        return documents;
    }
    /**
     * Processes the response data from the SerpAPI search request and converts it into an array of Documents.
     * @param data - The response data from the SerpAPI search request.
     * @returns An array of Documents.
     */
    processResponseData(data) {
        const documents = [];
        const responseTypes = [
            "answer_box",
            "sports_results",
            "shopping_results",
            "knowledge_graph",
            "organic_results",
        ];
        for (const responseType of responseTypes) {
            if (responseType in data) {
                documents.push(...this.extractDocuments(data[responseType], responseType));
            }
        }
        return documents;
    }
    /**
     * Fetches the data from the provided URL and returns it as a JSON object.
     * If an error occurs during the fetch operation, an exception is thrown with the error message.
     * @param url - The URL to fetch data from.
     * @returns A promise that resolves to the fetched data as a JSON object.
     * @throws An error if the fetch operation fails.
     */
    async fetchData(url) {
        const response = await fetch(url);
        const data = await response.json();
        if (data.error) {
            throw new Error(`Failed to load search results from SerpAPI due to: ${data.error}`);
        }
        return data;
    }
    /**
     * Loads the search results from the SerpAPI.
     * @returns An array of Documents representing the search results.
     * @throws An error if the search results could not be loaded.
     */
    async load() {
        const url = this.buildUrl();
        const data = await this.fetchData(url);
        try {
            return this.processResponseData(data);
        }
        catch (error) {
            console.error(error);
            throw new Error(`Failed to process search results from SerpAPI: ${error}`);
        }
    }
}
