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);
};
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { cond, pipe, prop, T, evolve, filter as filterFn, when, identity, times, length, ifElse, always } from 'ramda';
import i18n from 'ui-i18n';
import { ActivityFilter, addGlobalFilterToQuery, getRelationsForDataTenantEntity, getRelationsForEntity, isAvailableEntityTypeUri, isAvailableRelationTypeUri, isDataTenantEntity, getInOutRelationUri, isTempUri, Mode, wrapInArrayIfNeeded, hasRelationMasking, hasAttributeMasking, addRelationMaskingOptions } from '@reltio/mdm-sdk';
import { useSafePromise } from '../useSafePromise';
import { usePrevious } from '../usePrevious';
import { useMdmAction, useMdmDtssPath, useMdmGlobalSearchRequestOptions, useMdmMetadata, useMdmProfileLastLoadedTime, useMdmShowMasking, useMdmTenant } from '../../contexts/MdmModuleContext';
var buildSuggestedIds = when(identity, pipe(wrapInArrayIfNeeded, length, times(function (n) { return n + 1; })));
var isValidRequestConfig = function (config) {
    var _a;
    var entry = config;
    while (entry) {
        if (((_a = entry.entityTypes) === null || _a === void 0 ? void 0 : _a.length) === 0) {
            return false;
        }
        entry = entry.nextEntry;
    }
    return true;
};
export var useRelationsLoader = function (_a) {
    var sorting = _a.sorting, filter = _a.filter, page = _a.page, rowsPerPage = _a.rowsPerPage, config = _a.config, entity = _a.entity, relationActivityFilter = _a.relationActivityFilter, mode = _a.mode, _b = _a.searchByOv, searchByOv = _b === void 0 ? false : _b, searchRelationsWithFilter = _a.searchRelationsWithFilter, showSnackbarMessage = _a.showSnackbarMessage;
    var _c = useState(false), isLoading = _c[0], setIsLoading = _c[1];
    var relationsLoaded = useMdmAction('relationsLoaded');
    var tenant = useMdmTenant();
    var metadata = useMdmMetadata();
    var dtssPath = useMdmDtssPath();
    var _d = useMdmGlobalSearchRequestOptions() || {}, activityFilter = _d.activityFilter, globalFilter = _d.globalFilter;
    var lastLoadedTime = useMdmProfileLastLoadedTime();
    var showMasking = useMdmShowMasking();
    var safePromise = useSafePromise();
    var processContent = function (content) {
        var filterRelation = pipe(getInOutRelationUri, isAvailableRelationTypeUri(metadata));
        return evolve({
            entityTypes: filterFn(isAvailableEntityTypeUri(metadata)),
            inRelations: filterFn(filterRelation),
            outRelations: filterFn(filterRelation),
            nextEntry: processContent
        })(content);
    };
    var suggested = config.suggested;
    var options = useMemo(function () {
        var sendMasked = showMasking && (hasRelationMasking(metadata) || hasAttributeMasking(metadata)) && mode === Mode.Viewing;
        return addRelationMaskingOptions({ searchByOv: searchByOv, searchRelationsWithFilter: searchRelationsWithFilter }, sendMasked);
    }, [searchByOv, showMasking, metadata, mode, searchRelationsWithFilter]);
    var filters = useMemo(function () {
        var _a;
        return (_a = {},
            _a[searchRelationsWithFilter ? 'relationFilter' : 'filter'] = addGlobalFilterToQuery(globalFilter, filter) || undefined,
            _a);
    }, [searchRelationsWithFilter, globalFilter, filter]);
    var modeRef = useRef(mode);
    modeRef.current = mode;
    var loadRelations = useCallback(function () {
        if (entity === null || entity === void 0 ? void 0 : entity.uri) {
            var processedConfig = processContent(config.content);
            var requestConfig_1 = __assign(__assign(__assign({}, processedConfig), { sortBy: sorting === null || sorting === void 0 ? void 0 : sorting.field, order: sorting === null || sorting === void 0 ? void 0 : sorting.order, returnDates: true, returnObjects: true, activeness: {
                    relation: relationActivityFilter || ActivityFilter.ALL,
                    entity: activityFilter
                }, max: rowsPerPage, offset: page * rowsPerPage, suggested: buildSuggestedIds(suggested) }), filters);
            var configs_1 = [requestConfig_1].concat(ifElse(identity, pipe(wrapInArrayIfNeeded, function (suggested) {
                return suggested.map(function (config, i) { return (__assign(__assign({}, config), { id: requestConfig_1.suggested[i] })); });
            }), always([]))(suggested));
            var emptyResponsePromise_1 = Promise.resolve([{ total: 0 }]);
            var request = cond([
                [pipe(prop('uri'), isTempUri), function () { return emptyResponsePromise_1; }],
                [
                    always(!isValidRequestConfig(requestConfig_1)),
                    function () {
                        console.warn('Connections request config has "entityTypes": []. Request is blocked.');
                        return emptyResponsePromise_1;
                    }
                ],
                [
                    isDataTenantEntity,
                    function (entity) {
                        return getRelationsForDataTenantEntity({
                            entityUri: entity.uri,
                            configs: configs_1,
                            customerTenant: tenant,
                            dataTenant: entity.dataTenant,
                            dtssPath: dtssPath,
                            options: options
                        });
                    }
                ],
                [T, function (entity) { return getRelationsForEntity(entity.uri, configs_1, options); }]
            ]);
            setIsLoading(true);
            safePromise(request(entity))
                .then(function (result) {
                if (!Array.isArray(result)) {
                    throw Error(JSON.stringify(result));
                }
                var _a = result[0], connections = _a.connections, total = _a.total, dataSorted = _a.dataSorted;
                if (dataSorted === false && showSnackbarMessage) {
                    showSnackbarMessage(i18n.text('This profile contains a large number of relationships. We have disabled filtering and sorting to help optimize performance.'));
                }
                relationsLoaded({ id: config.id, connections: connections, total: total, mode: modeRef.current });
            })
                .catch(function (e) {
                console.warn('Failed to load relations data', e);
                relationsLoaded({ id: config.id, total: 0, connections: [], mode: modeRef.current });
            })
                .finally(function () {
                setIsLoading(false);
            });
        }
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [
        activityFilter,
        metadata,
        config,
        relationsLoaded,
        dtssPath,
        entity === null || entity === void 0 ? void 0 : entity.uri,
        entity === null || entity === void 0 ? void 0 : entity.dataTenant,
        filter,
        globalFilter,
        page,
        relationActivityFilter,
        rowsPerPage,
        safePromise,
        sorting,
        tenant,
        options,
        lastLoadedTime
    ]);
    var isRequestSentRef = useRef(false);
    isRequestSentRef.current = false;
    useEffect(function () {
        isRequestSentRef.current = true;
        loadRelations();
    }, [loadRelations]);
    var prevMode = usePrevious(mode);
    useEffect(function () {
        if (mode === Mode.Viewing && !isRequestSentRef.current && prevMode !== mode) {
            isRequestSentRef.current = true;
            loadRelations();
        }
    }, [loadRelations, mode, prevMode]);
    return { isLoading: isLoading, reload: loadRelations };
};
