import { useCallback } from 'react';
import { useLookupsStore } from '../stores/lookupsStore';
import { executeQueryInstance, executeQueryWithParameters, executeQueryInstanceWithApiMethodInstance, executeQueryAdHoc } from '../udp/utilities/methodUtils';
import { handleResponseErrors } from '../utilities/apiHelpers';
import QueryResult from '../models/QueryResult';
import { cloneDeep } from 'lodash-es';
export const useQueryExecutors = () => {
    const { lookupApiMethodId, lookupsDataMap, setLookupsDataMap } = useLookupsStore();
    const getLookupById = useCallback((lookupId) => {
        if (!lookupsDataMap || !lookupId) {
            return null;
        }
        return lookupsDataMap[lookupId];
    }, [lookupsDataMap]);
    const getMappedSearchResults = (lookups = {}, searchResults = {
        pageList: [],
        countable: false,
        total: 0,
        eagerLoad: false,
        aggregateResults: [],
        aliasMap: [],
        lookupsMap: []
    }) => {
        var _a, _b;
        const mapLookup = (item) => {
            const updatedItem = Object.assign({}, item);
            Object.keys(lookups).forEach((attribute) => {
                var _a;
                const lookup = lookups[attribute];
                const propertyValue = item[attribute];
                if (propertyValue !== null && propertyValue !== undefined) {
                    const matchingLookupRow = (_a = lookup === null || lookup === void 0 ? void 0 : lookup.data) === null || _a === void 0 ? void 0 : _a.find((row) => {
                        if (lookup.keyName && row[lookup.keyName]) {
                            return (row[lookup.keyName].toString() === propertyValue.toString());
                        }
                        return false;
                    });
                    if (matchingLookupRow && lookup.valueName) {
                        updatedItem[attribute] = matchingLookupRow[lookup.valueName];
                    }
                }
            });
            return updatedItem;
        };
        const updatedPageList = searchResults.pageList.map(mapLookup);
        const updatedAggregateResults = (_b = (_a = searchResults === null || searchResults === void 0 ? void 0 : searchResults.aggregateResults) === null || _a === void 0 ? void 0 : _a.map) === null || _b === void 0 ? void 0 : _b.call(_a, mapLookup);
        return Object.assign(Object.assign({}, searchResults), { pageList: updatedPageList, aggregateResults: updatedAggregateResults });
    };
    const processQueryResponseWithLookups = useCallback(async (lookupApiMethodId, response, replaceCache, showSnackbars, lookupDataMap) => {
        var _a;
        let resultData = new QueryResult();
        let lookupsMap = {};
        if ((response === null || response === void 0 ? void 0 : response.status) === 200) {
            lookupsMap = lookupDataMap || ((_a = response === null || response === void 0 ? void 0 : response.data) === null || _a === void 0 ? void 0 : _a.lookupsMap) || {};
            resultData = response.data;
        }
        else {
            showSnackbars && handleResponseErrors('Could not retrieve query data');
            return null;
        }
        // Keys are a list of Entity Properties
        const promises = [];
        const lookups = {};
        Object.keys(lookupsMap).forEach((key) => {
            const lookupConfig = lookupsMap[key];
            if (lookupConfig === null || lookupConfig === void 0 ? void 0 : lookupConfig.value) {
                const existingLookup = !replaceCache && getLookupById(lookupConfig.value);
                const lookupQueryData = { id: lookupConfig.value };
                if (!existingLookup) {
                    promises.push(executeQueryWithParameters({ data: lookupQueryData }, lookupApiMethodId)
                        .then((response) => {
                        if ((response === null || response === void 0 ? void 0 : response.status) === 200 && (response === null || response === void 0 ? void 0 : response.data)) {
                            const lookupConfig = lookupsMap[key];
                            lookups[key] = {
                                data: response.data.data,
                                keyName: lookupConfig.lookupKeyName || response.data.keyName,
                                valueName: lookupConfig.lookupValueName || response.data.valueName,
                                businessObjectKey: response.data.businessObjectKey
                            };
                            setLookupsDataMap({ [response.data.id]: response.data }, replaceCache);
                        }
                    })
                        .catch((e) => e));
                }
                else {
                    lookups[key] = {
                        data: existingLookup.data,
                        keyName: lookupConfig.lookupKeyName || existingLookup.keyName,
                        valueName: lookupConfig.lookupValueName || existingLookup.valueName,
                        businessObjectKey: existingLookup.businessObjectKey
                    };
                }
            }
        });
        await Promise.all(promises);
        resultData = getMappedSearchResults(lookups, resultData);
        return resultData;
    }, [getLookupById]);
    const executeQueryAdHocAndMapLookups = useCallback(async (searchObject = {}, apiMethodId, lookupsMap, replaceCache, showSnackbars = false) => {
        if (!lookupApiMethodId) {
            console.info('Udp Lookup Api Method Id NOT Set');
        }
        console.info('Udp Lookup Api Method Id IS Set');
        const response = await executeQueryAdHoc(searchObject || {}, apiMethodId);
        if (lookupApiMethodId) {
            return await processQueryResponseWithLookups(lookupApiMethodId, response, replaceCache, showSnackbars, lookupsMap);
        }
        return response === null || response === void 0 ? void 0 : response.data;
    }, [lookupApiMethodId, processQueryResponseWithLookups]);
    const executeQueryInstanceAndMapLookups = useCallback(async (queryParams = {}, apiMethodInstanceId, replaceCache, showSnackbars = false, urlQueryParams = '') => {
        if (!lookupApiMethodId) {
            console.info('Udp Lookup Api Method Id NOT Set');
            // return null;
        }
        console.info('Udp Lookup Api Method Id IS Set');
        const response = await executeQueryInstance({ data: queryParams || {} }, apiMethodInstanceId, urlQueryParams);
        if (lookupApiMethodId) {
            return await processQueryResponseWithLookups(lookupApiMethodId, response, replaceCache, showSnackbars, null);
        }
        return response === null || response === void 0 ? void 0 : response.data;
    }, [lookupApiMethodId, processQueryResponseWithLookups]);
    const executeQueryInstanceWithObjectAndMapLookups = useCallback(async (queryParams = {}, apiMethodInstance, replaceCache, showSnackbars = false, urlQueryParams = '') => {
        if (!lookupApiMethodId) {
            console.info('Udp Lookup Api Method Id NOT Set');
            // return null;
        }
        console.info('Udp Lookup Api Method Id IS Set');
        const response = await executeQueryInstanceWithApiMethodInstance({
            data: { queryParams: queryParams || {}, apiMethodInstance }
        }, urlQueryParams);
        if (lookupApiMethodId) {
            return await processQueryResponseWithLookups(lookupApiMethodId, response, replaceCache, showSnackbars, null);
        }
        return response === null || response === void 0 ? void 0 : response.data;
    }, [lookupApiMethodId, processQueryResponseWithLookups]);
    const getLookup = useCallback((lookupId) => {
        const cachedLookup = getLookupById(lookupId);
        if (cachedLookup) {
            return cachedLookup;
        }
        if (lookupApiMethodId) {
            const lookupQueryData = { id: lookupId };
            executeQueryWithParameters({ data: lookupQueryData }, lookupApiMethodId)
                .then((response) => {
                if ((response === null || response === void 0 ? void 0 : response.status) === 200 && (response === null || response === void 0 ? void 0 : response.data)) {
                    return response;
                }
            })
                .catch((e) => e);
        }
        return null;
    }, [lookupApiMethodId, getLookupById]);
    const getCleanData = useCallback((data, lookupsMap) => {
        // Un-Map lookup data
        let cleanData = cloneDeep(data);
        if (lookupsMap && cleanData) {
            Object.keys(lookupsMap).forEach((attribute) => {
                const lookupConfig = lookupsMap[attribute];
                const lookup = getLookup(lookupConfig.value);
                if (Array.isArray(cleanData)) {
                    // Data is an array of rows.
                    cleanData.forEach((row, index) => {
                        var _a;
                        let currentValue = row[attribute];
                        let temp = (_a = lookup === null || lookup === void 0 ? void 0 : lookup.data) === null || _a === void 0 ? void 0 : _a.find((item) => item[lookup.valueName] === currentValue);
                        if (temp != null)
                            cleanData[index][attribute] = temp[lookup.keyName];
                    });
                }
                else if (cleanData[attribute]) {
                    // Data is a single row
                    let currentValue = cleanData[attribute];
                    let temp = lookup.data.find((item) => item[lookup.valueName] === currentValue);
                    if (temp != null)
                        cleanData[attribute] = temp[lookup.keyName];
                }
            });
        }
        return cleanData;
    }, [getLookup]);
    return {
        executeQueryInstanceAndMapLookups: executeQueryInstanceAndMapLookups,
        executeQueryInstanceWithObjectAndMapLookups: executeQueryInstanceWithObjectAndMapLookups,
        executeQueryAdHocAndMapLookups: executeQueryAdHocAndMapLookups,
        getCleanData: getCleanData,
        getLookup: getLookup
    };
};
//# sourceMappingURL=useQueryExecutors.js.map