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 { useCallback, useEffect, useMemo, useState } from 'react';
import { getEntityUriForLink } from '@reltio/mdm-sdk';
import { map, pipe, prop, reject } from 'ramda';
import { useActionsHook } from '../contexts/ActionsHookContext';
import { useEntityLoadingIndication } from '../contexts/EntityLoadingIndicationContext';
import { useMdmApiPath, useMdmDtssPath, useMdmGlobalSearchRequestOptions, useMdmSearchNavigationData, useMdmSearchProviderData, useMdmTenant, useMdmAction, useMdmListener } from '../contexts/MdmModuleContext';
import { useSafePromise } from '../hooks/useSafePromise';
import { getSearchProvider } from './helpers';
import { REQUEST_PAGE_SIZE } from './constants';
var getNewUris = function (entities, cache) {
    return pipe(map(prop('uri')), reject(function (uri) { return cache.includes(uri); }))(entities);
};
export var useSearchNavigation = function () {
    var safeCheckEntityPromise = useSafePromise();
    var safeRequestTotalPromise = useSafePromise();
    var safeRequestEntitiesPromise = useSafePromise();
    var searchNavigationListener = useMdmListener('searchNavigationListener');
    var updateSearchNavigationDataFields = useMdmAction('updateSearchNavigationDataFields');
    var mdmOpenEntity = useMdmAction('openEntity');
    var openPerspective = useMdmAction('openPerspective');
    var _a = useMdmSearchNavigationData() || {}, uri = _a.uri, index = _a.index, total = _a.total, searchTenant = _a.tenant, cache = _a.cache;
    var _b = useMdmSearchProviderData() || {}, type = _b.type, data = _b.data;
    var tenant = useMdmTenant();
    var apiPath = useMdmApiPath();
    var dtssPath = useMdmDtssPath();
    var globalSearchRequestOptions = useMdmGlobalSearchRequestOptions(['ovOnly']);
    var updateEntitiesNavigationLoadingState = useEntityLoadingIndication().updateEntitiesNavigationLoadingState;
    var _c = useState(false), loading = _c[0], setLoading = _c[1];
    var searchProvider = useMemo(function () { return getSearchProvider(type, { data: data, tenant: tenant, searchTenant: searchTenant, apiPath: apiPath, dtssPath: dtssPath, globalSearchRequestOptions: globalSearchRequestOptions }); }, [type, data, tenant, searchTenant, apiPath, dtssPath, globalSearchRequestOptions]);
    var updateNavigationData = useCallback(function (data) {
        updateSearchNavigationDataFields(data);
    }, [updateSearchNavigationDataFields]);
    var openEntity = useCallback(function (uri) {
        var preparedUri = tenant !== searchTenant ? getEntityUriForLink({ uri: uri, dataTenant: searchTenant }) : uri;
        mdmOpenEntity({ uri: preparedUri, source: 'navigation' });
    }, [mdmOpenEntity, tenant, searchTenant]);
    var onSearchResultsClick = useCallback(function () {
        openPerspective(type);
    }, [openPerspective, type]);
    useEffect(function () {
        if (total !== 0 && index >= total) {
            updateNavigationData({
                index: total - 1
            });
        }
        else if (index < 0) {
            updateNavigationData({
                index: 0
            });
        }
    }, [total, index, updateNavigationData]);
    var listenToActions = useActionsHook();
    useEffect(function () {
        var stopListeningActions = listenToActions(searchNavigationListener);
        return function () { return stopListeningActions(); };
    }, [listenToActions, updateNavigationData, searchNavigationListener]);
    var requestNextPage = useCallback(function (cache, total, index) {
        setLoading(true);
        safeRequestTotalPromise(searchProvider.requestTotal())
            .then(function (total) { return updateNavigationData({ total: total }); })
            .catch(function (error) {
            console.warn('Failed to load total count of entities', error);
        });
        var newIndex = index + 1;
        return safeRequestEntitiesPromise(searchProvider.requestEntities(REQUEST_PAGE_SIZE, newIndex))
            .then(function (entities) {
            if (!entities) {
                return;
            }
            if (entities.length) {
                var newUris = getNewUris(entities, cache);
                if (newUris.length > 0) {
                    updateNavigationData({
                        cache: cache.concat(newUris),
                        uri: newUris[0],
                        index: newIndex + entities.length - newUris.length
                    });
                    openEntity(newUris[0]);
                    return;
                }
                else if (index + entities.length < total - 1) {
                    return requestNextPage(cache, total - entities.length, index + entities.length);
                }
            }
            updateNavigationData({
                index: newIndex
            });
        })
            .finally(function () {
            setLoading(false);
        });
    }, [searchProvider, updateNavigationData, openEntity]);
    var requestPrevPage = useCallback(function (cache, index) {
        setLoading(true);
        safeRequestTotalPromise(searchProvider.requestTotal())
            .then(function (total) { return updateNavigationData({ total: total }); })
            .catch(function (error) {
            console.warn('Failed to load total count of entities', error);
        });
        var newIndex = index - 1;
        var offset = Math.max(0, index - REQUEST_PAGE_SIZE);
        var max = REQUEST_PAGE_SIZE + Math.min(0, index - REQUEST_PAGE_SIZE);
        return safeRequestEntitiesPromise(searchProvider.requestEntities(max, offset))
            .then(function (entities) {
            if (!entities) {
                return;
            }
            if (entities.length) {
                var newUris = getNewUris(entities, cache);
                if (newUris.length > 0) {
                    updateNavigationData({
                        cache: newUris.concat(cache),
                        uri: newUris[newUris.length - 1],
                        index: newIndex - (entities.length - newUris.length)
                    });
                    openEntity(newUris[newUris.length - 1]);
                    return;
                }
                else if (index - entities.length > 0) {
                    return requestPrevPage(cache, index - entities.length);
                }
            }
            updateNavigationData({
                index: 0
            });
        })
            .finally(function () {
            setLoading(false);
        });
    }, [searchProvider, updateNavigationData, openEntity]);
    var stepForwardWithCheck = useCallback(function (cache, cacheIndex, total, index) {
        if (cacheIndex < cache.length) {
            var uri_1 = cache[cacheIndex];
            setLoading(true);
            return safeCheckEntityPromise(searchProvider.checkEntity(uri_1))
                .then(function (isExists) {
                if (isExists) {
                    updateNavigationData({
                        index: index + 1,
                        uri: uri_1,
                        cache: cache,
                        total: total
                    });
                    openEntity(uri_1);
                }
                else {
                    var clearedCache = __spreadArray([], cache, true);
                    clearedCache.splice(cacheIndex, 1);
                    return stepForwardWithCheck(clearedCache, cacheIndex, total - 1, index);
                }
            })
                .finally(function () {
                setLoading(false);
            });
        }
        else if (index >= total - 1) {
            updateNavigationData({
                cache: cache,
                total: total,
                index: total - 1
            });
            return Promise.resolve();
        }
        else {
            return requestNextPage(cache, total, index);
        }
    }, [searchProvider, updateNavigationData, openEntity, requestNextPage]);
    var stepBackWithCheck = useCallback(function (cache, cacheIndex, total, index) {
        if (cacheIndex > -1) {
            var uri_2 = cache[cacheIndex];
            setLoading(true);
            return safeCheckEntityPromise(searchProvider.checkEntity(uri_2))
                .then(function (isExists) {
                if (isExists) {
                    updateNavigationData({
                        index: index - 1,
                        uri: uri_2,
                        cache: cache,
                        total: total
                    });
                    openEntity(uri_2);
                }
                else {
                    var clearedCache = __spreadArray([], cache, true);
                    clearedCache.splice(cacheIndex, 1);
                    return stepBackWithCheck(clearedCache, cacheIndex - 1, total - 1, index - 1);
                }
            })
                .finally(function () {
                setLoading(false);
            });
        }
        else if (index <= 0) {
            updateNavigationData({
                index: 0,
                cache: cache,
                total: total
            });
            return Promise.resolve();
        }
        else {
            return requestPrevPage(cache, index);
        }
    }, [searchProvider, updateNavigationData, openEntity, requestPrevPage]);
    var onPrev = useCallback(function () {
        if (cache && uri) {
            var cacheIndex = cache.indexOf(uri) - 1;
            stepBackWithCheck(cache, cacheIndex, total, index).catch(function (error) {
                console.warn("Can't load previous page of search", error);
            });
        }
    }, [stepBackWithCheck, cache, uri, total, index]);
    var onNext = useCallback(function () {
        if (cache && uri) {
            var cacheIndex = cache.indexOf(uri) + 1;
            stepForwardWithCheck(cache, cacheIndex, total, index).catch(function (error) {
                console.warn("Can't load next page of search", error);
            });
        }
    }, [stepForwardWithCheck, cache, uri, total, index]);
    useEffect(function () {
        updateEntitiesNavigationLoadingState(loading);
    }, [updateEntitiesNavigationLoadingState, loading]);
    useEffect(function () {
        return function () { return updateEntitiesNavigationLoadingState(false); };
    }, []);
    var isPrevDisabled = loading || index <= 0;
    var isNextDisabled = loading || index >= total - 1;
    return { total: total, onPrev: onPrev, onNext: onNext, onSearchResultsClick: onSearchResultsClick, isPrevDisabled: isPrevDisabled, isNextDisabled: isNextDisabled };
};
