var __assign = (this && this.__assign) || function () {
    __assign = Object.assign || function(t) {
        for (var s, i = 1, n = arguments.length; i < n; i++) {
            s = arguments[i];
            for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
                t[p] = s[p];
        }
        return t;
    };
    return __assign.apply(this, arguments);
};
var __rest = (this && this.__rest) || function (s, e) {
    var t = {};
    for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
        t[p] = s[p];
    if (s != null && typeof Object.getOwnPropertySymbols === "function")
        for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
            if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
                t[p[i]] = s[p[i]];
        }
    return t;
};
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
    if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
        if (ar || !(i in from)) {
            if (!ar) ar = Array.prototype.slice.call(from, 0, i);
            ar[i] = from[i];
        }
    }
    return to.concat(ar || Array.prototype.slice.call(from));
};
import { useContext, useEffect, useRef } from 'react';
import { CustomAction, initializeWebWorker, isEmptyValue } from '@reltio/mdm-sdk';
import { nanoid } from 'nanoid';
import { omit } from 'ramda';
import { useWorkflowCheckPermission } from '../../features/workflow';
import { SnackbarContext } from '../../contexts/SnackbarContext';
import { SandboxAPIContext } from '../../contexts/SandboxAPIContext';
import { InterceptHandlersContext } from '../../contexts/InterceptHandlersContext';
import { useMdmAction, useMdmApiPath, useMdmEntity, useMdmEntityUri, useMdmMetadata, useMdmReltioPath, useMdmSearchProviderData, useMdmServicesPath, useMdmTenant, useMdmUiPath, useMdmUser, useMdmWorkflowEnvironmentUrl, useMdmWorkflowPath } from '../../contexts/MdmModuleContext';
import { processRequest } from '../useAPI';
import { isValidCustomScript, isURLtoProcess, getProcessedTask, getRequestFakeUrl, getResponseFakeUrl, getWorkerURL } from '../../helpers/customScript';
var getCustomViewConfig = function (config) {
    var processApiResponse = config.processApiResponse, processApiRequest = config.processApiRequest, permissions = config.permissions, files = config.files, otherProps = __rest(config, ["processApiResponse", "processApiRequest", "permissions", "files"]);
    return __assign({ action: { processApiResponse: processApiResponse, processApiRequest: processApiRequest, permissions: permissions, files: files } }, otherProps);
};
export var useCustomScripts = function (config) {
    var _a;
    var customScripts = config.reduce(function (acc, customScript) {
        if (isValidCustomScript(customScript)) {
            return __spreadArray(__spreadArray([], acc, true), [__assign(__assign({}, customScript), { actionId: nanoid() })], false);
        }
        return acc;
    }, []);
    var showSnackbarMessage = useContext(SnackbarContext);
    var _b = useContext(InterceptHandlersContext), addInternalRequestInterceptor = _b.addInternalRequestInterceptor, addInternalResponseInterceptor = _b.addInternalResponseInterceptor, removeInternalRequestInterceptor = _b.removeInternalRequestInterceptor, removeInternalResponseInterceptor = _b.removeInternalResponseInterceptor;
    var qxApi = useContext(SandboxAPIContext);
    var openSearch = useMdmAction('openSearch');
    var metadata = useMdmMetadata();
    var entity = useMdmEntity();
    var uiPath = useMdmUiPath();
    var servicesPath = useMdmServicesPath();
    var reltioPath = useMdmReltioPath();
    var tenant = useMdmTenant();
    var workerUrl = getWorkerURL(uiPath, tenant);
    var apiPath = useMdmApiPath();
    var workflowPath = useMdmWorkflowPath();
    var user = useMdmUser();
    var entityUri = useMdmEntityUri();
    var environment = useMdmWorkflowEnvironmentUrl();
    var workflowCheckPermission = useWorkflowCheckPermission();
    var searchProviderData = useMdmSearchProviderData();
    var searchQuery = (searchProviderData === null || searchProviderData === void 0 ? void 0 : searchProviderData.type) === 'search' ? (_a = searchProviderData === null || searchProviderData === void 0 ? void 0 : searchProviderData.data) === null || _a === void 0 ? void 0 : _a.query : null;
    var requestListeners = useRef({});
    var responseListeners = useRef({});
    var workers = useRef({});
    var processMessageFromWorker = function (_a) {
        var task = _a.task, worker = _a.worker, config = _a.config;
        if (task) {
            switch (task.action) {
                case CustomAction.LOG: {
                    console.log(task.params); //eslint-disable-line no-console
                    break;
                }
                case CustomAction.MESSAGE: {
                    showSnackbarMessage(task.params);
                    break;
                }
                case CustomAction.REQUEST: {
                    var processedTask = getProcessedTask(task, apiPath, reltioPath, tenant);
                    processRequest(__assign({ params: processedTask.params, permissions: config.action.permissions, worker: worker, metadata: metadata, config: config, user: user, apiPath: reltioPath, servicesPath: servicesPath, tenant: tenant, workflowPath: workflowPath, entity: entity, entityUri: entityUri, environment: environment, query: searchQuery, openSearch: openSearch, workflowCheckPermission: workflowCheckPermission }, qxApi));
                    break;
                }
                case CustomAction.RETURN_PROCESSED_API_RESPONSE: {
                    var _b = task.params, id = _b.id, data = _b.data;
                    if (responseListeners.current[id]) {
                        responseListeners.current[id].next(data);
                        responseListeners.current = omit([id], responseListeners.current);
                    }
                    break;
                }
                case CustomAction.RETURN_PROCESSED_API_REQUEST: {
                    var _c = task.params, id = _c.id, data = _c.data;
                    if (requestListeners.current[id]) {
                        requestListeners.current[id].resolve(data);
                        requestListeners.current = omit([id], requestListeners.current);
                    }
                    break;
                }
            }
        }
    };
    useEffect(function () {
        if (metadata) {
            workers.current = customScripts.reduce(function (acc, customScript) {
                var _a;
                var customViewConfig = getCustomViewConfig(customScript);
                return __assign(__assign({}, acc), (_a = {}, _a[customScript.actionId] = initializeWebWorker(workerUrl, processMessageFromWorker, customViewConfig), _a));
            }, workers.current);
            return function () {
                Object.keys(workers.current).forEach(function (actionId) {
                    workers.current[actionId].terminate();
                });
            };
        }
    }, [config, metadata]);
    var customScriptRequestInterceptor = function (_a) {
        var _b;
        var url = _a.url, next = _a.next, resolve = _a.resolve, _c = _a.options, options = _c === void 0 ? {} : _c;
        var fakeURL = getRequestFakeUrl(url, apiPath, reltioPath, tenant);
        var customScript = customScripts.find(function (_a) {
            var processApiRequest = _a.processApiRequest;
            return isURLtoProcess(fakeURL, processApiRequest);
        });
        var actionId = customScript === null || customScript === void 0 ? void 0 : customScript.actionId;
        if (actionId) {
            var requestId = nanoid();
            requestListeners.current = __assign(__assign({}, requestListeners.current), (_b = {}, _b[requestId] = { options: options, next: next, id: requestId, resolve: resolve }, _b));
            workers.current[actionId].postMessage({
                action: 'apiRequest',
                id: requestId,
                url: fakeURL,
                method: options.method || 'GET',
                headers: __assign(__assign({}, options.headers), { actionId: actionId }),
                data: options.body || options.data
            });
        }
        else {
            next(url, options);
        }
    };
    var customScriptResponseInterceptor = function (_a) {
        var url = _a.url, response = _a.response, next = _a.next, _b = _a.options, options = _b === void 0 ? {} : _b, abort = _a.abort;
        var fakeURL = getResponseFakeUrl(url, apiPath, reltioPath);
        var customScript = customScripts.find(function (_a) {
            var processApiResponse = _a.processApiResponse;
            return isURLtoProcess(fakeURL, processApiResponse);
        });
        var actionId = customScript === null || customScript === void 0 ? void 0 : customScript.actionId;
        if (actionId) {
            var responseId_1 = nanoid();
            response
                .json()
                .then(function (data) {
                var _a;
                responseListeners.current = __assign(__assign({}, responseListeners.current), (_a = {}, _a[responseId_1] = { next: next }, _a));
                workers.current[actionId].postMessage({
                    action: 'apiResponse',
                    id: responseId_1,
                    url: fakeURL,
                    method: options.method || 'GET',
                    data: data
                });
            })
                .catch(function (error) {
                abort(error);
            });
        }
        else {
            next(response);
        }
    };
    useEffect(function () {
        if (isEmptyValue(customScripts) || !metadata) {
            return;
        }
        addInternalRequestInterceptor(customScriptRequestInterceptor);
        addInternalResponseInterceptor(customScriptResponseInterceptor);
        return function () {
            removeInternalRequestInterceptor(customScriptRequestInterceptor);
            removeInternalResponseInterceptor(customScriptResponseInterceptor);
        };
    }, [config, metadata]);
};
