"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.defaultAssertHasuraRetryableResponse = void 0;
exports.useHasuraClient = useHasuraClient;
const utils_1 = require("@finalytic/utils");
const gqty_1 = require("gqty");
const constants_1 = require("../constants");
const gqty_2 = require("../gqty");
const wrap_1 = require("../wrap");
const headers_1 = require("./headers");
const subscription_1 = require("./subscription");
const retryablesErrors = [
    'deadlock detected',
    'fetch failed',
    'Unexpected token',
    'operation exceeded the time limit',
];
function isRetryableResponse(json) {
    if (!json || typeof json !== 'object')
        return null;
    const message = JSON.stringify(json.errors || {});
    if (!message)
        return null;
    return retryablesErrors.find((e) => message?.includes(e));
}
const defaultAssertHasuraRetryableResponse = async (arg) => {
    const defaultResponse = await (0, utils_1.defaultAssertRetryableResponse)(arg);
    if (defaultResponse && 'retryable' in defaultResponse)
        return defaultResponse;
    const json = await (0, utils_1.formatResponse)(arg.response).catch(() => null);
    arg.response.json = () => json;
    const retryableResponse = isRetryableResponse(json);
    if (retryableResponse) {
        return {
            retryable: true,
            errorMessage: retryableResponse,
            errorDetails: json,
        };
    }
};
exports.defaultAssertHasuraRetryableResponse = defaultAssertHasuraRetryableResponse;
function useHasuraClient({ uri = constants_1.hasuraGraphqlUri, secret, auditUserId, accessToken, subscriptions, headers, credentials, ...retryableFetchArgs } = {}) {
    const getHeaders = (0, headers_1.createHeadersFactory)({
        accessToken,
        auditUserId,
        headers,
        secret,
    });
    // Create the subscriptions client if needed
    const subscriptionsClient = (0, subscription_1.createHasuraSubscriptionsClient)(uri, getHeaders, subscriptions !== false);
    const fetchFn = retryableFetchArgs.fetch || fetch;
    const attempts = retryableFetchArgs.attempts === undefined ? 3 : retryableFetchArgs.attempts;
    const retryableFetch = attempts > 1
        ? (0, utils_1.useRetryableFetch)({
            assertResponse: exports.defaultAssertHasuraRetryableResponse,
            ...retryableFetchArgs,
            attempts,
        })
        : undefined;
    // Create the GQty client
    const client = () => (0, gqty_1.createClient)({
        schema: gqty_2.generatedSchema,
        scalarsEnumsHash: gqty_2.scalarsEnumsHash,
        async queryFetcher(query, variables, fetchOptions) {
            const getRequest = async () => {
                const headers = await getHeaders({
                    'Content-Type': 'application/json',
                });
                if (fetchOptions?.headers) {
                    for (const key in fetchOptions.headers) {
                        headers[key] = fetchOptions.headers[key];
                    }
                }
                const isMutation = query.includes('mutation');
                headers[constants_1.hasuraQueryTypeHeader] = isMutation ? 'mutation' : 'query';
                return new Request(uri, {
                    method: 'POST',
                    credentials,
                    headers,
                    signal: fetchOptions?.signal,
                    body: JSON.stringify({
                        query,
                        variables,
                    }),
                });
            };
            const response = retryableFetch
                ? await retryableFetch(getRequest)
                : await fetchFn(await getRequest());
            const json = await response.json();
            return json;
        },
        subscriptionsClient,
        normalization: false,
        defaults: {
            resolved: {
                noCache: true,
                retry: false, // We're handling retries ourselves in queryFetcher
            },
        },
        retry: { maxRetries: 0 },
    });
    return (0, wrap_1.wrapGraphQLClient)(client, subscriptionsClient);
}
