/* eslint-disable react-hooks/rules-of-hooks */
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());
    });
};
/* eslint-disable react-hooks/exhaustive-deps */
import { useContext, useEffect, useMemo, useState } from 'react';
import { useRecoilValue, useRecoilValueLoadable } from 'recoil';
// eslint-disable-next-line import/no-cycle
import { VariableCtx, WebSocketCtx, useRequestExtras, useTaskContext } from '../../shared/context';
import { UserError, isServerVariable, isSingleVariable, isVariable, } from '../../types';
import { normalizeRequest } from '../utils/normalization';
import { createFetcher } from './filtering';
// eslint-disable-next-line import/no-cycle
import { cleanArgs, fetchDerivedVariable, getOrRegisterDerivedVariableResult, isTaskResponse, resolveVariable, useVariable, } from './internal';
import { getOrRegisterServerVariable } from './server-variable';
import { fetchTabularServerVariable, useFetchTabularDerivedVariable, useFetchTabularServerVariable, } from './tabular-variable';
/**
 * Helper hook which turns any variable into a callback to return DataFrame.
 * Can be used in components that only work with tabular data.
 *
 * Optionally pass in filters, pagination, and other options to fetch data.
 *
 * The callback identity changes whenever a refetch should be triggered.
 *
 * @param variable data variable
 */
export function useTabularVariable(variable) {
    const extras = useRequestExtras();
    const { client: wsClient } = useContext(WebSocketCtx);
    if (!isVariable(variable) || isSingleVariable(variable)) {
        const [data] = useVariable(variable);
        return useMemo(() => createFetcher(data), [data]);
    }
    // Synchronously register subscription to the underlying DV, clean up on unmount
    const variablesContext = useContext(VariableCtx);
    variablesContext === null || variablesContext === void 0 ? void 0 : variablesContext.variables.current.add(variable.uid);
    useEffect(() => {
        return () => {
            variablesContext === null || variablesContext === void 0 ? void 0 : variablesContext.variables.current.delete(variable.uid);
        };
    }, []);
    if (isServerVariable(variable)) {
        const serverAtom = getOrRegisterServerVariable(variable, extras);
        const atomCount = useRecoilValue(serverAtom);
        return useFetchTabularServerVariable(variable, atomCount, wsClient, extras);
    }
    const taskContext = useTaskContext();
    const dvResultSelector = getOrRegisterDerivedVariableResult(variable, wsClient, taskContext, extras);
    const dvResultLoadable = useRecoilValueLoadable(dvResultSelector);
    const [dvResult, setDvResult] = useState(() => dvResultLoadable.getValue());
    useEffect(() => {
        // Whenever loadable changes value, update the result
        // The result selector is synchronous so we don't have to worry about suspending
        if (dvResultLoadable.state === 'hasValue') {
            setDvResult(dvResultLoadable.getValue());
        }
    }, [dvResultLoadable]);
    return useFetchTabularDerivedVariable(variable, dvResult, wsClient, taskContext, extras);
}
/**
 * Return the entire tabular variable as a DataFrame
 * */
export function getTabularVariableValue(variable, ctx) {
    return __awaiter(this, void 0, void 0, function* () {
        if (!isVariable(variable)) {
            return variable;
        }
        if (isSingleVariable(variable)) {
            return resolveVariable(variable, ctx.client, ctx.taskContext, ctx.extras, (v) => ctx.snapshot.getLoadable(v).toPromise());
        }
        if (isServerVariable(variable)) {
            const response = yield fetchTabularServerVariable({
                variable,
                // doesn't matter for fetching, will get up to date anyway
                seqNumber: 0,
                wsClient: ctx.client,
                extras: ctx.extras,
            });
            return response.data;
        }
        const resolved = (yield resolveVariable(variable, ctx.client, ctx.taskContext, ctx.extras, (v) => ctx.snapshot.getLoadable(v).toPromise()));
        // derived variable
        const result = yield fetchDerivedVariable({
            cache: variable.cache,
            extras: ctx.extras,
            force_key: null,
            /**
             * In this case we're not concerned about different selectors fetching the value so just use the uid
             */
            selectorKey: resolved.uid,
            values: normalizeRequest(cleanArgs(resolved.values), variable.variables),
            variableUid: resolved.uid,
            wsClient: ctx.client,
        });
        // This is really only used in DownloadVariable currently; we can add support for task
        if (isTaskResponse(result)) {
            throw new UserError('Task DerivedVariables are not supported in this context');
        }
        const response = result.value;
        return response.data;
    });
}
//# sourceMappingURL=use-tabular-variable.js.map