// (C) 2019-2026 GoodData Corporation
import { useCallback, useEffect, useState } from "react";
import { areObjRefsEqual, isResultAttributeHeader, } from "@gooddata/sdk-model";
import { DataViewFacade } from "@gooddata/sdk-ui";
export function useAttributeValuesFromExecResults(execResult) {
    const [isResultLoading, setIsResultLoading] = useState(!execResult || execResult.isLoading);
    const [dataView, setDataView] = useState(null);
    useEffect(() => {
        if (execResult) {
            void execResult.executionResult?.readAll().then((data) => {
                setDataView(DataViewFacade.for(data));
                setIsResultLoading(false);
            });
        }
    }, [execResult]);
    const getAttributeValues = useCallback((attr) => {
        const header = findAttributeHeader(dataView, attr);
        const indexes = findDimIndexes(dataView, header);
        return findAttributeValues(dataView, indexes);
    }, [dataView]);
    const getMetricValue = useCallback((measure, attr, value) => {
        if (!measure || !dataView) {
            return undefined;
        }
        const data = Array.from(dataView.data().series().allForMeasure(measure));
        if (!attr && !value) {
            return calculatePredictedValue(data);
        }
        const header = findAttributeHeader2(dataView, attr);
        const indexes = findDimIndexes(dataView, header);
        const values = calculateValues(dataView, indexes, value);
        const result = calculatePredictedValue(data, values);
        return result === 0 ? undefined : result;
    }, [dataView]);
    return {
        isResultLoading,
        getAttributeValues,
        getMetricValue,
    };
}
function calculatePredictedValue(data, values) {
    return data.reduce((total, series) => {
        return (total +
            Array.from(series).reduce((acc, item) => {
                if (item.total) {
                    return acc;
                }
                if (!values ||
                    item.seriesDesc.scopeTitles().some((title) => title && values.includes(title))) {
                    return acc + parseFloat(String(item.rawValue || "0"));
                }
                return acc;
            }, 0));
    }, 0);
}
function calculateValues(dataView, indexes, value) {
    return findAttributeValues(dataView, indexes)
        .map((v) => v.title)
        .filter((v) => {
        if (value) {
            return v === value;
        }
        return true;
    });
}
function findAttributeHeader(dataView, attr) {
    if (!dataView) {
        return null;
    }
    return (dataView
        .meta()
        .attributeDescriptors()
        .find((descriptor) => {
        return (areObjRefsEqual(descriptor.attributeHeader.ref, attr.ref) ||
            attr.displayForms.some((displayForm) => {
                return areObjRefsEqual(descriptor.attributeHeader.ref, displayForm.ref);
            }));
    }) ?? null);
}
function findAttributeHeader2(dataView, attr) {
    if (!dataView || !attr) {
        return null;
    }
    return (dataView
        .meta()
        .attributeDescriptors()
        .find((descriptor) => {
        return areObjRefsEqual(descriptor.attributeHeader.ref, attr.attribute.displayForm);
    }) ?? null);
}
/**
 * This will find attribute elements array indexes for provided attribute descriptor in the execution results data view.
 * @param dataView - DataViewFacade object to work with execution results data
 * @param header - attribute header to find indexes for
 */
function findDimIndexes(dataView, header) {
    const def = [-1, -1];
    if (!dataView || !header) {
        return def;
    }
    return dataView.definition.dimensions.reduce((acc, dimension, i) => {
        const j = dimension.itemIdentifiers.findIndex((itemIdentifier) => {
            return itemIdentifier === header.attributeHeader.localIdentifier;
        });
        if (j !== -1) {
            return [i, j];
        }
        return acc;
    }, def);
}
/**
 * Based on found indexes in the execution results data view, this function will return attribute elements
 * that are present in the data view. Values are unique by their uri.
 * @param dataView - DataViewFacade object to work with execution results data
 * @param dimensionIndex - index of the dimension
 * @param elementsIndex - index of the item in the dimension
 */
function findAttributeValues(dataView, [dimensionIndex, elementsIndex]) {
    const headers = dataView?.meta().allHeaders() ?? [];
    const data = (headers[dimensionIndex] ?? [])[elementsIndex] ?? [];
    const values = data
        .map((item) => {
        if (isResultAttributeHeader(item)) {
            return {
                title: item.attributeHeaderItem.formattedName ?? item.attributeHeaderItem.name,
                value: item.attributeHeaderItem.uri,
                name: item.attributeHeaderItem.name,
            };
        }
        return null;
    })
        .filter(Boolean);
    return values.filter((value, index, self) => {
        return self.findIndex((v) => v.value === value.value) === index;
    });
}
//# sourceMappingURL=useAttributeValuesFromExecResults.js.map