var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
import { useCallback, useRef } from 'react';
import { HTTP_METHOD, validateResponse } from '@darajs/ui-utils';
import { fetchTaskResult } from '../../api';
import { request } from '../../api/http';
import { handleAuthErrors } from '../../auth/auth';
import { UserError, } from '../../types';
import { normalizeRequest } from '../utils/normalization';
// eslint-disable-next-line import/no-cycle
import { cleanArgs } from './internal';
/**
 * Create necessary query parameters on a URL based on pagination settings
 *
 * @param path url path
 * @param pagination pagination object
 */
function createDataUrl(path, pagination) {
    const url = new URL(path, window.location.origin);
    if (pagination === null || pagination === void 0 ? void 0 : pagination.limit) {
        url.searchParams.set('limit', String(pagination.limit));
    }
    if (pagination === null || pagination === void 0 ? void 0 : pagination.offset) {
        url.searchParams.set('offset', String(pagination.offset));
    }
    if (pagination === null || pagination === void 0 ? void 0 : pagination.sort) {
        url.searchParams.set('order_by', (pagination.sort.desc ? '-' : '') + pagination.sort.id);
    }
    if (pagination === null || pagination === void 0 ? void 0 : pagination.index) {
        url.searchParams.set('index', String(pagination.index));
    }
    return url;
}
function validateTabularResponse(uid, response) {
    return __awaiter(this, void 0, void 0, function* () {
        if (response.status === 415) {
            let msg = `The requested variable ${uid} data is not tabular`;
            try {
                const data = yield response.json();
                if ('detail' in data) {
                    msg += `. ${data.detail}`;
                }
            }
            catch (_a) {
                // ignore
            }
            throw new UserError(msg);
        }
    });
}
export function isDataResponse(response) {
    return response && typeof response === 'object' && 'data' in response && 'count' in response;
}
export function fetchTabularServerVariable(_a) {
    return __awaiter(this, arguments, void 0, function* ({ variable, 
    // Explicitly unused, required for the callback dependency to ensure its identity changes
    // eslint-disable-next-line @typescript-eslint/no-unused-vars
    seqNumber, wsClient, extras, filters = null, pagination = null, }) {
        const url = createDataUrl(`/api/core/tabular-variable/${variable.uid}`, pagination);
        const body = {
            filters: filters !== null && filters !== void 0 ? filters : null,
            ws_channel: yield wsClient.getChannel(),
        };
        const response = yield request(url, { body: JSON.stringify(body), method: HTTP_METHOD.POST }, extras);
        yield handleAuthErrors(response, true);
        yield validateTabularResponse(variable.uid, response);
        yield validateResponse(response, 'Failed to fetch tabular data');
        return response.json();
    });
}
export function useFetchTabularServerVariable(variable, seqNumber, wsClient, extras) {
    return useCallback((filters, pagination) => __awaiter(this, void 0, void 0, function* () {
        return fetchTabularServerVariable({ variable, seqNumber, wsClient, extras, filters, pagination });
    }), [wsClient, variable, seqNumber, extras]);
}
export function useFetchTabularDerivedVariable(variable, dvResult, wsClient, taskContext, extras) {
    const previousResult = useRef({
        data: null,
        count: 0,
        schema: { fields: [], primaryKey: [] },
    });
    return useCallback((filters, pagination) => __awaiter(this, void 0, void 0, function* () {
        const url = createDataUrl(`/api/core/tabular-variable/${variable.uid}`, pagination);
        const body = {
            filters: filters !== null && filters !== void 0 ? filters : null,
            ws_channel: yield wsClient.getChannel(),
            dv_values: normalizeRequest(cleanArgs(dvResult.values), variable.variables),
        };
        const response = yield request(url, { body: JSON.stringify(body), method: HTTP_METHOD.POST }, extras);
        yield handleAuthErrors(response, true);
        yield validateTabularResponse(variable.uid, response);
        yield validateResponse(response, 'Failed to fetch tabular data');
        const responseJson = yield response.json();
        const variableTaskId = `${variable.uid}-filter`;
        // cancel previously running filter tasks
        taskContext.cleanupRunningTasks(variableTaskId);
        // normal data response
        if (!('task_id' in responseJson)) {
            previousResult.current = responseJson;
            return responseJson;
        }
        // Task response found, wait and fetch result
        const taskId = responseJson.task_id;
        // add task to currently running tasks
        taskContext.startTask(taskId, variableTaskId);
        try {
            yield wsClient.waitForTask(taskId);
        }
        catch (_a) {
            // If an error occurred (i.e. task was cancelled) return the previous result.
            // This would also cause the callback's identity to change so if the consuming component is
            // honouring the contract, it should execute the callback again
            return previousResult.current;
        }
        finally {
            taskContext.endTask(taskId);
        }
        const taskResult = yield fetchTaskResult(taskId, extras);
        if (taskResult.status === 'not_found') {
            throw new Error('Task result not found');
        }
        previousResult.current = taskResult.result;
        return taskResult.result;
    }), [variable.uid, variable.variables, dvResult, wsClient, taskContext, extras]);
}
//# sourceMappingURL=tabular-variable.js.map