/*
* Copyright (c) 2020-present SMC Treviso s.r.l. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
import React from "react";
import Keycloak from "keycloak-js";
export const OpenK9ClientContext = React.createContext(null /* must break app if not provided */);
export function useOpenK9Client() {
    return React.useContext(OpenK9ClientContext);
}
export function OpenK9Client({ onAuthenticated, tenant, useKeycloak = true, waitKeycloackForToken, callback, }) {
    const keycloak = new Keycloak({
        url: window.KEYCLOAK_URL,
        realm: window.KEYCLOAK_REALM || "openk9",
        clientId: window.KEYCLOAK_CLIENT_ID || "openk9",
    });
    const appendToBody = { token: "" };
    const setToken = (newToken) => {
        appendToBody.token = newToken;
    };
    async function waitForToken() {
        let count = 0;
        while (appendToBody.token === "" || count < 5) {
            count++;
            await new Promise((resolve) => setTimeout(resolve, 500));
        }
    }
    const keycloakInit = useKeycloak
        ? keycloak.init({
            onLoad: "check-sso",
            checkLoginIframe: false,
        })
        : null;
    if (keycloakInit)
        keycloakInit.then(() => {
            onAuthenticated();
        });
    async function authFetch(route, init = {}) {
        await keycloakInit;
        if (keycloak.authenticated) {
            await keycloak.updateToken(30);
        }
        if (callback) {
            callback();
        }
        let headers = init.headers;
        if (useKeycloak && keycloak.authenticated) {
            headers = {
                Authorization: `Bearer ${keycloak.token}`,
                ...init.headers,
            };
        }
        else if (!useKeycloak && waitKeycloackForToken) {
            if (!keycloak.authenticated && appendToBody.token === "") {
                await waitForToken();
            }
            headers = {
                Authorization: `Bearer ${appendToBody.token}`,
                ...init.headers,
            };
        }
        return fetch(tenant + route, {
            ...init,
            headers,
        });
    }
    return {
        authInit: keycloakInit,
        async authenticate({ token = "" }) {
            if (useKeycloak) {
                await keycloak.login();
            }
            else {
                setToken(token || "");
            }
        },
        async deauthenticate() {
            await keycloak.logout();
        },
        async getUserProfile() {
            return await keycloak.loadUserInfo();
        },
        async getGenerateResponse({ searchQuery, controller, }) {
            const url = "/api/rag/generate";
            const data = await authFetch(url, {
                method: "POST",
                headers: {
                    accept: "application/json",
                    "Content-Type": "application/json",
                },
                body: JSON.stringify(searchQuery),
                signal: controller.signal,
            });
            return data;
        },
        async getServiceStatus() {
            const response = await fetch(tenant + `/api/status`);
            if (response.ok)
                return "up";
            else
                return "down";
        },
        async doSearch(searchRequest) {
            const response = await authFetch(`/api/searcher/v1/search`, {
                method: "POST",
                body: JSON.stringify(searchRequest),
                headers: {
                    Accept: "application/json",
                    "Content-Type": "application/json",
                },
            });
            const data = await response.json();
            return data;
        },
        async generateResponse(searchRequest) {
            const response = await authFetch(`/api/rag/generate`, {
                method: "POST",
                body: JSON.stringify(searchRequest),
                headers: {
                    Accept: "application/json",
                    "Content-Type": "application/json",
                },
            });
            const data = await response.json();
            return data;
        },
        async getDateFilterFields() {
            const response = await authFetch(`/api/datasource/v1/date-filter`, {
                method: "GET",
                headers: { Accept: "application/json" },
            });
            if (!response.ok) {
                throw new Error();
            }
            const data = await response.json();
            return data;
        },
        async getLabelSort() {
            const response = await authFetch(`/api/datasource/buckets/current/doc-type-fields-sortable`, {
                method: "GET",
                headers: { Accept: "application/json" },
            });
            if (!response.ok) {
                throw new Error();
            }
            const data = await response.json();
            return data;
        },
        async getLanguages() {
            const response = await authFetch("/api/datasource/buckets/current/availableLanguage", {
                method: "GET",
                headers: { Accept: "application/json" },
            });
            if (!response.ok) {
                throw new Error();
            }
            const data = await response.json();
            return data;
        },
        async getSortingInfo() {
            const response = await authFetch("/api/datasource/buckets/current/sortings", {
                method: "GET",
                headers: { Accept: "application/json" },
            });
            if (!response.ok) {
                throw new Error();
            }
            const data = await response.json();
            return data;
        },
        async getRefreshFilters() {
            const response = await authFetch("/api/datasource/buckets/current", {
                method: "GET",
                headers: { Accept: "application/json" },
            });
            if (!response.ok) {
                throw new Error();
            }
            const data = await response.json();
            return {
                ...data,
                retrieveType: data.retrieveType,
            };
        },
        async getLanguageDefault() {
            const response = await authFetch(`/api/datasource/buckets/current/defaultLanguage`, {
                method: "GET",
                headers: { Accept: "application/json" },
            });
            if (!response.ok) {
                throw new Error();
            }
            const data = await response.json();
            return data;
        },
        async getSuggestions({ searchQuery, suggestionCategoryId, range, afterKey, suggestKeyword, order, language, }) {
            const request = await authFetch(`/api/searcher/v1/suggestions`, {
                method: "POST",
                body: JSON.stringify({
                    searchQuery,
                    range,
                    afterKey,
                    suggestionCategoryId,
                    suggestKeyword,
                    order,
                    language,
                }),
                headers: {
                    Accept: "application/json",
                    "Content-Type": "application/json",
                },
            });
            const response = await request.json();
            return response;
        },
        async getAutocompletes({ searchText, }) {
            const res = await authFetch(`/api/searcher/v1/autocomplete`, {
                method: "POST",
                body: JSON.stringify({ queryText: searchText }),
                headers: {
                    Accept: "application/json",
                    "Content-Type": "application/json",
                },
            });
            if (!res.ok) {
                const errorText = await res.text().catch(() => "");
                throw new Error(`Autocomplete failed (${res.status}): ${errorText}`);
            }
            const data = (await res.json());
            if (!Array.isArray(data)) {
                throw new Error("Autocomplete response is not an array");
            }
            return data;
        },
        async handle_dynamic_filters() {
            const response = await authFetch(`/api/datasource/buckets/current`, {
                method: "GET",
                headers: { Accept: "application/json" },
            });
            if (!response.ok) {
                throw new Error();
            }
            const data = await response.json();
            return data;
        },
        async getSuggestionCategories() {
            const response = await authFetch(`/api/datasource/buckets/current/suggestionCategories`, {
                headers: {
                    Accept: "application/json",
                },
            });
            const data = await response.json();
            return data;
        },
        async getTabsByVirtualHost() {
            const response = await authFetch(`/api/datasource/buckets/current/tabs`, {
                headers: {
                    Accept: "application/json",
                },
            });
            const data = await response.json();
            return data;
        },
        async getTemplatesByVirtualHost() {
            const response = await authFetch(`/api/datasource/buckets/current/templates`, {
                headers: {
                    Accept: "application/json",
                },
            });
            const data = await response.json();
            return data.map(({ id }) => id);
        },
        async loadTemplate(id) {
            try {
                const jsURL = tenant + `/api/datasource/templates/${id}/compiled`;
                // @ts-ignore
                const code = await import(/* @vite-ignore */ /* webpackIgnore: true */ jsURL);
                return code.exports.template;
            }
            catch (err) {
                console.warn(err);
                return null;
            }
        },
        async fetchQueryAnalysis(request) {
            const mock = false;
            const isActiveQueryAnalysis = true;
            if (!isActiveQueryAnalysis)
                return null;
            if (request.searchText === "")
                return null;
            if (mock)
                return {
                    searchText: "Questo Ã¨ un esempio di testo per l'analisi",
                    analysis: [
                        {
                            text: "Questo Ã¨ un nuovo",
                            start: 0,
                            end: 5,
                            tokens: [
                                {
                                    label: "",
                                    tokenType: "FILTER",
                                    value: "ciao",
                                    score: 0.8,
                                },
                            ],
                        },
                        {
                            text: "ancora",
                            start: 0,
                            end: 5,
                            tokens: [
                                {
                                    label: "test di prova",
                                    tokenType: "FILTER",
                                    value: "bella",
                                    score: 0.8,
                                },
                            ],
                        },
                        {
                            text: "Questo",
                            start: 0,
                            end: 5,
                            tokens: [
                                {
                                    label: "",
                                    tokenType: "FILTER",
                                    value: "prova",
                                    keywordKey: "test",
                                    score: 0.8,
                                },
                            ],
                        },
                    ],
                };
            const response = await authFetch("/api/searcher/v1/query-analysis", {
                method: "POST",
                body: JSON.stringify(request),
                headers: {
                    Accept: "application/json",
                    "Content-Type": "application/json",
                },
            });
            if (!response.ok) {
                throw new Error();
            }
            const data = await response.json();
            return data;
        },
    };
}
