// (C) 2021-2026 GoodData Corporation
import { invariant } from "ts-invariant";
import { areObjRefsEqual, attributeElementsIsEmpty, dashboardAttributeFilterItemFilterElementsBy, dashboardAttributeFilterItemFilterElementsByDate, dashboardAttributeFilterItemLocalIdentifier, dashboardAttributeFilterItemValidateElementsBy, dashboardFilterLocalIdentifier, isAttributeElementsByRef, isDashboardArbitraryAttributeFilter, isDashboardAttributeFilter, isDashboardAttributeFilterItem, isDashboardCommonDateFilter, isDashboardDateFilter, isDashboardMatchAttributeFilter, isDashboardMeasureValueFilter, newAllTimeDashboardDateFilter, } from "@gooddata/sdk-model";
import { generateFilterLocalIdentifier } from "../../_infra/generators.js";
import { getActiveTab, getTabOrActive } from "../tabsState.js";
import { filterContextInitialState } from "./filterContextState.js";
import { applyFilterContext, initializeFilterContext } from "./filterContextUtils.js";
const setFilterContext = (state, action) => {
    const activeTab = getActiveTab(state);
    if (!activeTab) {
        return;
    }
    const { filterContextDefinition, originalFilterContextDefinition, filterContextIdentity, attributeFilterDisplayForms, } = action.payload;
    // Use the helper function to initialize the filter context
    activeTab.filterContext = initializeFilterContext(filterContextDefinition, originalFilterContextDefinition, attributeFilterDisplayForms, filterContextIdentity);
};
const updateFilterContextIdentity = (state, action) => {
    const activeTab = getActiveTab(state);
    if (!activeTab) {
        return;
    }
    if (!activeTab.filterContext) {
        activeTab.filterContext = { ...filterContextInitialState };
    }
    activeTab.filterContext.filterContextIdentity = action.payload.filterContextIdentity;
};
/**
 * Updates filter context identity for a specific tab after a dashboard save.
 * This ensures that the filter context gets the correct identity from the backend.
 *
 * @param state - The tabs state
 * @param action - Object containing tabId and the filter context identity
 */
const updateFilterContextIdentityForTab = (state, action) => {
    if (!state.tabs) {
        return;
    }
    const { tabId, filterContextIdentity } = action.payload;
    const tab = state.tabs.find((t) => t.localIdentifier === tabId);
    if (!tab) {
        return;
    }
    if (!tab.filterContext) {
        tab.filterContext = { ...filterContextInitialState };
    }
    tab.filterContext.filterContextIdentity = filterContextIdentity;
};
//
//
//
const removeAttributeFilterDisplayForms = (state, action) => {
    const activeTab = getActiveTab(state);
    if (!activeTab) {
        return;
    }
    if (!activeTab.filterContext) {
        activeTab.filterContext = { ...filterContextInitialState };
    }
    invariant(activeTab.filterContext.attributeFilterDisplayForms, "attempting to work with uninitialized state");
    activeTab.filterContext.attributeFilterDisplayForms =
        activeTab.filterContext.attributeFilterDisplayForms.filter((df) => {
            return !areObjRefsEqual(df, action.payload);
        });
};
const addAttributeFilterDisplayForm = (state, action) => {
    // Handle both old and new payload formats for backward compatibility
    const displayForm = "displayForm" in action.payload ? action.payload.displayForm : action.payload;
    const tabLocalIdentifier = "tabLocalIdentifier" in action.payload ? action.payload.tabLocalIdentifier : undefined;
    const targetTab = getTabOrActive(state, tabLocalIdentifier);
    if (!targetTab) {
        return;
    }
    if (!targetTab.filterContext) {
        targetTab.filterContext = { ...filterContextInitialState };
    }
    invariant(targetTab.filterContext.attributeFilterDisplayForms, "attempting to work with uninitialized state");
    // if there is already a display form with the same ref, replace it
    const existing = targetTab.filterContext.attributeFilterDisplayForms.find((df) => areObjRefsEqual(df, displayForm.ref));
    if (existing) {
        targetTab.filterContext.attributeFilterDisplayForms =
            targetTab.filterContext.attributeFilterDisplayForms.filter((df) => !areObjRefsEqual(df, displayForm));
    }
    targetTab.filterContext.attributeFilterDisplayForms.push(displayForm);
};
//
//
//
const setPreloadedAttributesWithReferences = (state, action) => {
    // Store attributesWithReferences at TabsState level (shared across all tabs)
    // The payload already contains merged attributes from all filters across all tabs
    state.attributesWithReferences = action.payload;
};
const upsertDateFilter = (state, action) => {
    const targetTab = getTabOrActive(state, action.payload.tabLocalIdentifier);
    if (!targetTab) {
        return;
    }
    if (!targetTab.filterContext) {
        targetTab.filterContext = { ...filterContextInitialState };
    }
    const filterContextDefinition = action.payload.isWorkingSelectionChange
        ? targetTab.filterContext.workingFilterContextDefinition
        : targetTab.filterContext.filterContextDefinition;
    invariant(filterContextDefinition?.filters, "Attempt to edit uninitialized filter context");
    const dateDataSet = action.payload.dataSet;
    let existingFilterIndex = -1;
    if (dateDataSet) {
        existingFilterIndex = filterContextDefinition.filters.findIndex((item) => isDashboardDateFilter(item) && areObjRefsEqual(item.dateFilter.dataSet, dateDataSet));
    }
    else {
        existingFilterIndex = filterContextDefinition.filters.findIndex((item) => isDashboardCommonDateFilter(item));
    }
    if (action.payload.isWorkingSelectionChange && action.payload.type === "allTime") {
        // we need to allways set working filter to distinguish between "not changed" and "all time" filter
        if (existingFilterIndex >= 0) {
            const dateFilter = filterContextDefinition.filters[existingFilterIndex];
            if (isDashboardDateFilter(dateFilter)) {
                filterContextDefinition.filters[existingFilterIndex] = newAllTimeDashboardDateFilter(dateFilter.dateFilter.dataSet, dateFilter.dateFilter.localIdentifier, action.payload.emptyValueHandling);
            }
        }
        else {
            filterContextDefinition.filters.unshift(newAllTimeDashboardDateFilter(action.payload.dataSet, action.payload.localIdentifier, action.payload.emptyValueHandling));
        }
    }
    else if (action.payload.type === "allTime") {
        if (existingFilterIndex >= 0) {
            if (dateDataSet) {
                const dateFilter = filterContextDefinition.filters[existingFilterIndex];
                if (isDashboardDateFilter(dateFilter)) {
                    filterContextDefinition.filters[existingFilterIndex] = newAllTimeDashboardDateFilter(dateFilter.dateFilter.dataSet, dateFilter.dateFilter.localIdentifier, action.payload.emptyValueHandling);
                }
            }
            else {
                if (action.payload.emptyValueHandling) {
                    // Preserve all-time common DF when it carries additional config (e.g. emptyValueHandling).
                    filterContextDefinition.filters[existingFilterIndex] = newAllTimeDashboardDateFilter(undefined, action.payload.localIdentifier, action.payload.emptyValueHandling);
                }
                else {
                    // if allTime common DF remove the date filter altogether
                    filterContextDefinition.filters.splice(existingFilterIndex, 1);
                }
            }
        }
        else if (!dateDataSet && action.payload.emptyValueHandling) {
            // No common date filter existed (all time was represented by absence); create it to preserve extra config.
            filterContextDefinition.filters.unshift(newAllTimeDashboardDateFilter(undefined, action.payload.localIdentifier, action.payload.emptyValueHandling));
        }
    }
    else if (existingFilterIndex >= 0) {
        const { type, granularity, from, to, localIdentifier, boundedFilter, emptyValueHandling } = action.payload;
        const dateFilter = filterContextDefinition.filters[existingFilterIndex];
        if (isDashboardDateFilter(dateFilter)) {
            dateFilter.dateFilter.type = type;
            dateFilter.dateFilter.granularity = granularity;
            dateFilter.dateFilter.from = from;
            dateFilter.dateFilter.to = to;
            if (localIdentifier) {
                dateFilter.dateFilter.localIdentifier = localIdentifier;
            }
            if (boundedFilter) {
                dateFilter.dateFilter.boundedFilter = boundedFilter;
            }
            else {
                delete dateFilter.dateFilter.boundedFilter;
            }
            if (emptyValueHandling) {
                dateFilter.dateFilter.emptyValueHandling = emptyValueHandling;
            }
            else {
                delete dateFilter.dateFilter.emptyValueHandling;
            }
        }
    }
    else {
        const { type, granularity, from, to, dataSet, localIdentifier, boundedFilter, emptyValueHandling } = action.payload;
        filterContextDefinition.filters.unshift({
            dateFilter: {
                granularity,
                type,
                from,
                to,
                ...(dataSet ? { dataSet } : {}),
                ...(localIdentifier ? { localIdentifier } : {}),
                ...(boundedFilter ? { boundedFilter } : {}),
                ...(emptyValueHandling ? { emptyValueHandling } : {}),
            },
        });
    }
};
const updateAttributeFilterSelection = (state, action) => {
    const targetTab = getTabOrActive(state, action.payload.tabLocalIdentifier);
    if (!targetTab) {
        return;
    }
    if (!targetTab.filterContext) {
        targetTab.filterContext = { ...filterContextInitialState };
    }
    const { elements, filterLocalId, negativeSelection, isWorkingSelectionChange, enableImmediateAttributeFilterDisplayAsLabelMigration, isResultOfMigration, isSelectionInvalid, } = action.payload;
    const filterContextDefinition = isWorkingSelectionChange
        ? targetTab.filterContext.workingFilterContextDefinition
        : targetTab.filterContext.filterContextDefinition;
    invariant(filterContextDefinition?.filters, "Attempt to edit uninitialized filter context");
    const existingFilterIndex = filterContextDefinition.filters.findIndex((item) => isDashboardAttributeFilter(item) && item.attributeFilter.localIdentifier === filterLocalId);
    invariant(existingFilterIndex >= 0 || isWorkingSelectionChange, "Attempt to update non-existing filter");
    if (isWorkingSelectionChange && existingFilterIndex >= 0) {
        filterContextDefinition.filters[existingFilterIndex] = {
            attributeFilter: {
                localIdentifier: filterLocalId,
                attributeElements: elements,
                negativeSelection,
            },
        };
    }
    else if (isWorkingSelectionChange) {
        filterContextDefinition.filters.push({
            attributeFilter: {
                localIdentifier: filterLocalId,
                attributeElements: elements,
                negativeSelection,
            },
        });
    }
    else if (existingFilterIndex >= 0) {
        filterContextDefinition.filters[existingFilterIndex] = {
            attributeFilter: {
                ...filterContextDefinition.filters[existingFilterIndex]
                    .attributeFilter,
                attributeElements: elements,
                negativeSelection,
            },
        };
    }
    // update original filters to not show "reset filters" button, that will revert filter to the wrong state
    if (enableImmediateAttributeFilterDisplayAsLabelMigration && isResultOfMigration) {
        const originalFilter = targetTab.filterContext.originalFilterContextDefinition?.filters.find((item) => isDashboardAttributeFilter(item) && item.attributeFilter.localIdentifier === filterLocalId);
        if (isDashboardAttributeFilter(originalFilter)) {
            originalFilter.attributeFilter = {
                ...originalFilter.attributeFilter,
                attributeElements: elements,
                negativeSelection,
            };
        }
    }
    // Handle isSelectionInvalid flag to update filtersWithInvalidSelection array
    if (isSelectionInvalid) {
        // Add filterLocalId to the array if not already present
        if (!targetTab.filterContext.filtersWithInvalidSelection.includes(filterLocalId)) {
            targetTab.filterContext.filtersWithInvalidSelection.push(filterLocalId);
        }
    }
    else {
        // Remove filterLocalId from the array if present
        targetTab.filterContext.filtersWithInvalidSelection =
            targetTab.filterContext.filtersWithInvalidSelection.filter((id) => id !== filterLocalId);
    }
};
/**
 * Carries over filterElementsBy, filterElementsByDate, and validateElementsBy from the existing filter
 * to the replacement filter, so that parent filter dependencies are not lost
 * when filter selection/params change.
 */
function preserveFilterDependencies(existing, replacement) {
    const filterElementsBy = dashboardAttributeFilterItemFilterElementsBy(existing);
    const filterElementsByDate = dashboardAttributeFilterItemFilterElementsByDate(existing);
    const validateElementsBy = dashboardAttributeFilterItemValidateElementsBy(existing);
    if (!filterElementsBy?.length && !filterElementsByDate?.length && !validateElementsBy?.length) {
        return replacement;
    }
    const preserved = {
        ...(filterElementsBy?.length ? { filterElementsBy } : {}),
        ...(filterElementsByDate?.length ? { filterElementsByDate } : {}),
        ...(validateElementsBy?.length ? { validateElementsBy } : {}),
    };
    if (isDashboardAttributeFilter(replacement)) {
        return {
            attributeFilter: {
                ...replacement.attributeFilter,
                ...preserved,
            },
        };
    }
    if (isDashboardArbitraryAttributeFilter(replacement)) {
        return {
            arbitraryAttributeFilter: {
                ...replacement.arbitraryAttributeFilter,
                ...preserved,
            },
        };
    }
    // Match filters do not support parent dependencies
    return replacement;
}
const replaceAttributeFilterItem = (state, action) => {
    const targetTab = getTabOrActive(state, action.payload.tabLocalIdentifier);
    if (!targetTab) {
        return;
    }
    if (!targetTab.filterContext) {
        targetTab.filterContext = { ...filterContextInitialState };
    }
    const { filterLocalId, filter, isWorkingSelectionChange, isSelectionInvalid } = action.payload;
    const filterContextDefinition = isWorkingSelectionChange
        ? targetTab.filterContext.workingFilterContextDefinition
        : targetTab.filterContext.filterContextDefinition;
    invariant(filterContextDefinition?.filters, "Attempt to edit uninitialized filter context");
    const existingFilterIndex = filterContextDefinition.filters.findIndex((item) => isDashboardAttributeFilterItem(item) &&
        dashboardAttributeFilterItemLocalIdentifier(item) === filterLocalId);
    // Preserve parent filter relationships from the existing filter when replacing.
    // The replacement filter typically only carries selection data, not dependency configuration.
    const replacementFilter = existingFilterIndex >= 0
        ? preserveFilterDependencies(filterContextDefinition.filters[existingFilterIndex], filter)
        : filter;
    // Type assertion: filterContextDefinition.filters is either FilterContextItem[] or
    // WorkingFilterContextItem[] depending on isWorkingSelectionChange. We cast to FilterContextItem[]
    // since DashboardAttributeFilterItem is a subtype of FilterContextItem.
    const filters = filterContextDefinition.filters;
    if (isWorkingSelectionChange && existingFilterIndex >= 0) {
        filters[existingFilterIndex] = replacementFilter;
    }
    else if (isWorkingSelectionChange) {
        filters.push(replacementFilter);
    }
    else if (existingFilterIndex >= 0) {
        filters[existingFilterIndex] = replacementFilter;
    }
    // Handle isSelectionInvalid flag to update filtersWithInvalidSelection array
    if (isSelectionInvalid) {
        if (!targetTab.filterContext.filtersWithInvalidSelection.includes(filterLocalId)) {
            targetTab.filterContext.filtersWithInvalidSelection.push(filterLocalId);
        }
    }
    else {
        targetTab.filterContext.filtersWithInvalidSelection =
            targetTab.filterContext.filtersWithInvalidSelection.filter((id) => id !== filterLocalId);
    }
};
const addAttributeFilter = (state, action) => {
    const activeTab = getActiveTab(state);
    if (!activeTab) {
        return;
    }
    if (!activeTab.filterContext) {
        activeTab.filterContext = { ...filterContextInitialState };
    }
    invariant(activeTab.filterContext.filterContextDefinition, "Attempt to edit uninitialized filter context");
    const { displayForm, index, initialIsNegativeSelection, initialSelection, parentFilters, selectionMode, localIdentifier, title, } = action.payload;
    // Filters are indexed just for attribute filters, if DateFilter is present should be always first item
    const isDateFilterPresent = activeTab.filterContext.filterContextDefinition.filters.findIndex(isDashboardDateFilter) >= 0;
    const hasSelection = initialSelection && !attributeElementsIsEmpty(initialSelection);
    const isNegative = selectionMode !== "single" && (initialIsNegativeSelection || !hasSelection);
    // If DateFilter is present we have to move index by 1 because index of filter is calculated just for AttributeFilers array
    const attributeFilterIndex = isDateFilterPresent ? index + 1 : index;
    const filter = {
        attributeFilter: {
            attributeElements: initialSelection ?? { uris: [] },
            displayForm,
            negativeSelection: isNegative,
            localIdentifier: localIdentifier ??
                generateFilterLocalIdentifier(displayForm, Math.max(0, attributeFilterIndex)),
            filterElementsBy: parentFilters ? [...parentFilters] : undefined,
            ...(selectionMode === undefined ? {} : { selectionMode }),
            title,
        },
    };
    if (index === -1) {
        activeTab.filterContext.filterContextDefinition.filters.push(filter);
    }
    else {
        activeTab.filterContext.filterContextDefinition.filters.splice(attributeFilterIndex, 0, filter);
    }
};
const addTextAttributeFilter = (state, action) => {
    const activeTab = getActiveTab(state);
    if (!activeTab) {
        return;
    }
    if (!activeTab.filterContext) {
        activeTab.filterContext = { ...filterContextInitialState };
    }
    invariant(activeTab.filterContext.filterContextDefinition, "Attempt to edit uninitialized filter context");
    const { filter, index } = action.payload;
    // Filters are indexed just for attribute filters, if DateFilter is present should be always first item
    const isDateFilterPresent = activeTab.filterContext.filterContextDefinition.filters.findIndex(isDashboardDateFilter) >= 0;
    const attributeFilterIndex = isDateFilterPresent ? index + 1 : index;
    const generatedLocalIdentifierIndex = Math.max(0, attributeFilterIndex);
    const filterWithLocalIdentifier = isDashboardArbitraryAttributeFilter(filter)
        ? {
            arbitraryAttributeFilter: {
                ...filter.arbitraryAttributeFilter,
                localIdentifier: filter.arbitraryAttributeFilter.localIdentifier ??
                    generateFilterLocalIdentifier(filter.arbitraryAttributeFilter.displayForm, generatedLocalIdentifierIndex),
            },
        }
        : isDashboardMatchAttributeFilter(filter)
            ? {
                matchAttributeFilter: {
                    ...filter.matchAttributeFilter,
                    localIdentifier: filter.matchAttributeFilter.localIdentifier ??
                        generateFilterLocalIdentifier(filter.matchAttributeFilter.displayForm, generatedLocalIdentifierIndex),
                },
            }
            : filter;
    if (index === -1) {
        activeTab.filterContext.filterContextDefinition.filters.push(filterWithLocalIdentifier);
    }
    else {
        activeTab.filterContext.filterContextDefinition.filters.splice(attributeFilterIndex, 0, filterWithLocalIdentifier);
    }
};
const removeAttributeFilter = (state, action) => {
    const activeTab = getActiveTab(state);
    if (!activeTab) {
        return;
    }
    if (!activeTab.filterContext) {
        activeTab.filterContext = { ...filterContextInitialState };
    }
    invariant(activeTab.filterContext.filterContextDefinition, "Attempt to edit uninitialized filter context");
    const { filterLocalId } = action.payload;
    const newFilters = activeTab.filterContext.filterContextDefinition.filters.filter((item) => isDashboardDateFilter(item) ||
        !isDashboardAttributeFilterItem(item) ||
        dashboardAttributeFilterItemLocalIdentifier(item) !== filterLocalId);
    activeTab.filterContext.filterContextDefinition = {
        ...activeTab.filterContext.filterContextDefinition,
        filters: newFilters,
    };
};
const moveAttributeFilter = (state, action) => {
    const activeTab = getActiveTab(state);
    if (!activeTab) {
        return;
    }
    if (!activeTab.filterContext) {
        activeTab.filterContext = { ...filterContextInitialState };
    }
    invariant(activeTab.filterContext.filterContextDefinition, "Attempt to edit uninitialized filter context");
    const { filterLocalId, index } = action.payload;
    const currentFilterIndex = activeTab.filterContext.filterContextDefinition.filters.findIndex((item) => isDashboardAttributeFilterItem(item) &&
        dashboardAttributeFilterItemLocalIdentifier(item) === filterLocalId);
    invariant(currentFilterIndex >= 0, "Attempt to move non-existing filter");
    const filter = activeTab.filterContext.filterContextDefinition.filters[currentFilterIndex];
    activeTab.filterContext.filterContextDefinition.filters.splice(currentFilterIndex, 1);
    // Filters are indexed just for attribute filters, if DateFilter is present should be always first item
    const isDateFilterPresent = activeTab.filterContext.filterContextDefinition.filters.findIndex(isDashboardDateFilter) >= 0;
    if (index === -1) {
        activeTab.filterContext.filterContextDefinition.filters.push(filter);
    }
    else {
        // If DateFilter is present we have to move index by 1 because index of filter is calculated just for AttributeFilers array
        const attributeFilterIndex = isDateFilterPresent ? index + 1 : index;
        activeTab.filterContext.filterContextDefinition.filters.splice(attributeFilterIndex, 0, filter);
    }
};
const setAttributeFilterParents = (state, action) => {
    const activeTab = getActiveTab(state);
    if (!activeTab) {
        return;
    }
    if (!activeTab.filterContext) {
        activeTab.filterContext = { ...filterContextInitialState };
    }
    invariant(activeTab.filterContext.filterContextDefinition, "Attempt to edit uninitialized filter context");
    const { filterLocalId, parentFilters } = action.payload;
    const currentFilterIndex = activeTab.filterContext.filterContextDefinition.filters.findIndex((item) => isDashboardAttributeFilterItem(item) &&
        dashboardAttributeFilterItemLocalIdentifier(item) === filterLocalId);
    invariant(currentFilterIndex >= 0, "Attempt to set parent of a non-existing filter");
    // silently ignore when targeting match filter, will have no effect
    const filter = activeTab.filterContext.filterContextDefinition.filters[currentFilterIndex];
    if (isDashboardAttributeFilter(filter)) {
        filter.attributeFilter.filterElementsBy = [...parentFilters];
    }
    else if (isDashboardArbitraryAttributeFilter(filter)) {
        filter.arbitraryAttributeFilter.filterElementsBy = [...parentFilters];
    }
};
const setAttributeFilterDependentDateFilters = (state, action) => {
    const activeTab = getActiveTab(state);
    if (!activeTab) {
        return;
    }
    if (!activeTab.filterContext) {
        activeTab.filterContext = { ...filterContextInitialState };
    }
    invariant(activeTab.filterContext.filterContextDefinition, "Attempt to edit uninitialized filter context");
    const { filterLocalId, dependentDateFilters } = action.payload;
    const currentFilterIndex = activeTab.filterContext.filterContextDefinition.filters.findIndex((item) => isDashboardAttributeFilterItem(item) &&
        dashboardAttributeFilterItemLocalIdentifier(item) === filterLocalId);
    invariant(currentFilterIndex >= 0, "Attempt to set dependent date filter of a non-existing filter");
    const filter = activeTab.filterContext.filterContextDefinition.filters[currentFilterIndex];
    if (isDashboardAttributeFilter(filter)) {
        filter.attributeFilter.filterElementsByDate = [...dependentDateFilters];
    }
    else if (isDashboardArbitraryAttributeFilter(filter)) {
        filter.arbitraryAttributeFilter.filterElementsByDate = [...dependentDateFilters];
    }
    // Match filters do not support filterElementsByDate
};
const clearAttributeFiltersSelection = (state, action) => {
    const targetTab = getTabOrActive(state, action.payload.tabLocalIdentifier);
    if (!targetTab) {
        return;
    }
    if (!targetTab.filterContext) {
        targetTab.filterContext = { ...filterContextInitialState };
    }
    const { filterLocalIds } = action.payload;
    filterLocalIds.forEach((filterLocalId) => {
        invariant(targetTab.filterContext?.filterContextDefinition, "Attempt to edit uninitialized filter context");
        const currentFilterIndex = targetTab.filterContext.filterContextDefinition.filters.findIndex((item) => isDashboardAttributeFilter(item) && item.attributeFilter.localIdentifier === filterLocalId);
        invariant(currentFilterIndex >= 0, "Attempt to clear selection of a non-existing filter");
        const currentFilter = targetTab.filterContext.filterContextDefinition.filters[currentFilterIndex];
        currentFilter.attributeFilter.negativeSelection =
            currentFilter.attributeFilter.selectionMode !== "single";
        currentFilter.attributeFilter.attributeElements = isAttributeElementsByRef(currentFilter.attributeFilter.attributeElements)
            ? { uris: [] }
            : { values: [] };
    });
};
/**
 * Changes the display form for the filter given by its local identifier.
 */
const changeAttributeDisplayForm = (state, action) => {
    const targetTab = getTabOrActive(state, action.payload.tabLocalIdentifier);
    if (!targetTab) {
        return;
    }
    if (!targetTab.filterContext) {
        targetTab.filterContext = { ...filterContextInitialState };
    }
    const { filterLocalId, displayForm, isWorkingSelectionChange, enableImmediateAttributeFilterDisplayAsLabelMigration, isResultOfMigration, } = action.payload;
    const filterContextDefinition = isWorkingSelectionChange
        ? targetTab.filterContext.workingFilterContextDefinition
        : targetTab.filterContext.filterContextDefinition;
    invariant(filterContextDefinition?.filters, "Attempt to edit uninitialized filter context");
    const currentFilterIndex = filterContextDefinition.filters.findIndex((item) => isDashboardAttributeFilter(item) && item.attributeFilter.localIdentifier === filterLocalId);
    invariant(currentFilterIndex >= 0 || isWorkingSelectionChange, "Attempt to set parent of a non-existing filter");
    if (isWorkingSelectionChange && currentFilterIndex < 0) {
        filterContextDefinition.filters.push({
            attributeFilter: {
                displayForm,
                attributeElements: isAttributeElementsByRef(displayForm) ? { uris: [] } : { values: [] },
                negativeSelection: false,
            },
        });
        return;
    }
    const currentFilter = filterContextDefinition.filters[currentFilterIndex];
    currentFilter.attributeFilter.displayForm = { ...displayForm };
    // update original filters to not show "reset filters" button, that will revert filter to wrong state
    if (enableImmediateAttributeFilterDisplayAsLabelMigration && isResultOfMigration) {
        const originalFilter = targetTab.filterContext.originalFilterContextDefinition?.filters.find((item) => isDashboardAttributeFilter(item) && item.attributeFilter.localIdentifier === filterLocalId);
        if (isDashboardAttributeFilter(originalFilter)) {
            originalFilter.attributeFilter.displayForm = { ...displayForm };
        }
    }
};
/**
 * Updates the displayForm on a text filter (arbitrary or match) definition.
 * This is needed when displayAsLabel changes on a text filter, because the label
 * must be written to the filter's own definition, not only to the filter config.
 */
const changeTextFilterDisplayForm = (state, action) => {
    const targetTab = getTabOrActive(state, action.payload.tabLocalIdentifier);
    if (!targetTab?.filterContext) {
        return;
    }
    const { filterLocalId, displayForm } = action.payload;
    const filterContextDefinition = targetTab.filterContext.filterContextDefinition;
    if (!filterContextDefinition?.filters) {
        return;
    }
    const currentFilterIndex = filterContextDefinition.filters.findIndex((item) => isDashboardAttributeFilterItem(item) &&
        !isDashboardAttributeFilter(item) &&
        dashboardAttributeFilterItemLocalIdentifier(item) === filterLocalId);
    if (currentFilterIndex < 0) {
        return;
    }
    const filter = filterContextDefinition.filters[currentFilterIndex];
    if (isDashboardArbitraryAttributeFilter(filter)) {
        filter.arbitraryAttributeFilter.displayForm = { ...displayForm };
    }
    else if (isDashboardMatchAttributeFilter(filter)) {
        filter.matchAttributeFilter.displayForm = { ...displayForm };
    }
};
/**
 * Changes the title for the filter given by its local identifier.
 */
const changeAttributeTitle = (state, action) => {
    const activeTab = getActiveTab(state);
    if (!activeTab) {
        return;
    }
    if (!activeTab.filterContext) {
        activeTab.filterContext = { ...filterContextInitialState };
    }
    invariant(activeTab.filterContext.filterContextDefinition, "Attempt to edit uninitialized filter context");
    const { filterLocalId, title } = action.payload;
    const findFilter = activeTab.filterContext.filterContextDefinition.filters.find((item) => isDashboardAttributeFilterItem(item) &&
        dashboardAttributeFilterItemLocalIdentifier(item) === filterLocalId);
    invariant(findFilter, "Attempt to change title of a non-existing filter");
    if (isDashboardAttributeFilter(findFilter)) {
        findFilter.attributeFilter.title = title;
    }
    else if (isDashboardArbitraryAttributeFilter(findFilter)) {
        findFilter.arbitraryAttributeFilter.title = title;
    }
    else if (isDashboardMatchAttributeFilter(findFilter)) {
        findFilter.matchAttributeFilter.title = title;
    }
};
/**
 * Changes the selection mode for the filter given by its local identifier.
 */
const changeSelectionMode = (state, action) => {
    const activeTab = getActiveTab(state);
    if (!activeTab) {
        return;
    }
    if (!activeTab.filterContext) {
        activeTab.filterContext = { ...filterContextInitialState };
    }
    invariant(activeTab.filterContext.filterContextDefinition, "Attempt to edit uninitialized filter context");
    const { filterLocalId, selectionMode } = action.payload;
    const findFilter = activeTab.filterContext.filterContextDefinition.filters.find((item) => isDashboardAttributeFilterItem(item) &&
        dashboardAttributeFilterItemLocalIdentifier(item) === filterLocalId);
    invariant(findFilter, "Attempt to change selection mode of a non-existing filter");
    // Text filters (arbitrary, match) do not have selectionMode; no-op for them
    if (isDashboardAttributeFilter(findFilter)) {
        findFilter.attributeFilter.selectionMode = selectionMode;
    }
};
const addDateFilter = (state, action) => {
    const activeTab = getActiveTab(state);
    if (!activeTab) {
        return;
    }
    if (!activeTab.filterContext) {
        activeTab.filterContext = { ...filterContextInitialState };
    }
    invariant(activeTab.filterContext.filterContextDefinition, "Attempt to edit uninitialized filter context");
    const { index, dateDataset } = action.payload;
    const filter = {
        dateFilter: {
            dataSet: dateDataset,
            type: "relative",
            granularity: "GDC.time.date",
        },
    };
    // Only draggable filters are indexed, if DateFilter is present should be always first item
    const isCommonDateFilterPresent = activeTab.filterContext.filterContextDefinition.filters.findIndex(isDashboardCommonDateFilter) >= 0;
    if (index === -1) {
        activeTab.filterContext.filterContextDefinition.filters.push(filter);
    }
    else {
        // If CommonDateFilter is present we have to move index by 1 because index of filter is calculated just for AttributeFilers array
        const newFilterIndex = isCommonDateFilterPresent ? index + 1 : index;
        activeTab.filterContext.filterContextDefinition.filters.splice(newFilterIndex, 0, filter);
    }
};
//
//
//
const addMeasureValueFilter = (state, action) => {
    const activeTab = getActiveTab(state);
    if (!activeTab) {
        return;
    }
    if (!activeTab.filterContext) {
        activeTab.filterContext = { ...filterContextInitialState };
    }
    invariant(activeTab.filterContext.filterContextDefinition, "Attempt to edit uninitialized filter context");
    const { index, measure, localIdentifier, title } = action.payload;
    const filter = {
        dashboardMeasureValueFilter: {
            measure,
            localIdentifier: localIdentifier ?? generateFilterLocalIdentifier(measure, Math.max(0, index)),
            title,
        },
    };
    const isCommonDateFilterPresent = activeTab.filterContext.filterContextDefinition.filters.findIndex(isDashboardCommonDateFilter) >= 0;
    if (index === -1) {
        activeTab.filterContext.filterContextDefinition.filters.push(filter);
    }
    else {
        const newFilterIndex = isCommonDateFilterPresent ? index + 1 : index;
        activeTab.filterContext.filterContextDefinition.filters.splice(newFilterIndex, 0, filter);
    }
};
const removeMeasureValueFilter = (state, action) => {
    const activeTab = getActiveTab(state);
    if (!activeTab) {
        return;
    }
    if (!activeTab.filterContext) {
        activeTab.filterContext = { ...filterContextInitialState };
    }
    invariant(activeTab.filterContext.filterContextDefinition, "Attempt to edit uninitialized filter context");
    activeTab.filterContext.filterContextDefinition = {
        ...activeTab.filterContext.filterContextDefinition,
        filters: activeTab.filterContext.filterContextDefinition.filters.filter((item) => !(isDashboardMeasureValueFilter(item) &&
            dashboardFilterLocalIdentifier(item) === action.payload.localIdentifier)),
    };
};
const moveMeasureValueFilter = (state, action) => {
    const activeTab = getActiveTab(state);
    if (!activeTab) {
        return;
    }
    if (!activeTab.filterContext) {
        activeTab.filterContext = { ...filterContextInitialState };
    }
    invariant(activeTab.filterContext.filterContextDefinition, "Attempt to edit uninitialized filter context");
    const { localIdentifier, index } = action.payload;
    const filters = activeTab.filterContext.filterContextDefinition.filters;
    const currentFilterIndex = filters.findIndex((item) => isDashboardMeasureValueFilter(item) && dashboardFilterLocalIdentifier(item) === localIdentifier);
    invariant(currentFilterIndex >= 0, "Attempt to move non-existing measure value filter");
    const filter = filters[currentFilterIndex];
    filters.splice(currentFilterIndex, 1);
    const isCommonDateFilterPresent = filters.findIndex(isDashboardCommonDateFilter) >= 0;
    if (index === -1) {
        filters.push(filter);
    }
    else {
        const newFilterIndex = isCommonDateFilterPresent ? index + 1 : index;
        filters.splice(newFilterIndex, 0, filter);
    }
};
const removeDateFilter = (state, action) => {
    const activeTab = getActiveTab(state);
    if (!activeTab) {
        return;
    }
    if (!activeTab.filterContext) {
        activeTab.filterContext = { ...filterContextInitialState };
    }
    invariant(activeTab.filterContext.filterContextDefinition, "Attempt to edit uninitialized filter context");
    const { dataSet } = action.payload;
    const newFilters = activeTab.filterContext.filterContextDefinition.filters.filter((item) => !isDashboardDateFilter(item) || !areObjRefsEqual(item.dateFilter.dataSet, dataSet));
    activeTab.filterContext.filterContextDefinition = {
        ...activeTab.filterContext.filterContextDefinition,
        filters: newFilters,
    };
};
const moveDateFilter = (state, action) => {
    const activeTab = getActiveTab(state);
    if (!activeTab) {
        return;
    }
    if (!activeTab.filterContext) {
        activeTab.filterContext = { ...filterContextInitialState };
    }
    invariant(activeTab.filterContext.filterContextDefinition, "Attempt to edit uninitialized filter context");
    const { dataSet, index } = action.payload;
    const currentFilterIndex = activeTab.filterContext.filterContextDefinition.filters.findIndex((item) => isDashboardDateFilter(item) && areObjRefsEqual(item.dateFilter.dataSet, dataSet));
    invariant(currentFilterIndex >= 0, "Attempt to move non-existing filter");
    const filter = activeTab.filterContext.filterContextDefinition.filters[currentFilterIndex];
    activeTab.filterContext.filterContextDefinition.filters.splice(currentFilterIndex, 1);
    // Filters are indexed just for attribute filters, if DateFilter is present should be always first item
    const isCommonDateFilterPresent = activeTab.filterContext.filterContextDefinition.filters.findIndex(isDashboardCommonDateFilter) >= 0;
    if (index === -1) {
        activeTab.filterContext.filterContextDefinition.filters.push(filter);
    }
    else {
        // If DateFilter is present we have to move index by 1 because index of filter is calculated just for DraggableFilters array
        const dateFilterIndex = isCommonDateFilterPresent ? index + 1 : index;
        activeTab.filterContext.filterContextDefinition.filters.splice(dateFilterIndex, 0, filter);
    }
};
/**
 * Changes the element limiting items for the filter given by its local identifier.
 */
const changeLimitingItems = (state, action) => {
    const activeTab = getActiveTab(state);
    if (!activeTab) {
        return;
    }
    if (!activeTab.filterContext) {
        activeTab.filterContext = { ...filterContextInitialState };
    }
    invariant(activeTab.filterContext.filterContextDefinition, "Attempt to edit uninitialized filter context");
    const { filterLocalId, limitingItems } = action.payload;
    const findFilter = activeTab.filterContext.filterContextDefinition.filters.find((item) => isDashboardAttributeFilterItem(item) &&
        dashboardAttributeFilterItemLocalIdentifier(item) === filterLocalId);
    invariant(findFilter, "Attempt to change limiting items of a non-existing filter");
    if (isDashboardAttributeFilter(findFilter)) {
        findFilter.attributeFilter.validateElementsBy = limitingItems;
    }
    else if (isDashboardArbitraryAttributeFilter(findFilter)) {
        findFilter.arbitraryAttributeFilter.validateElementsBy = limitingItems;
    }
    // Match filters do not support validateElementsBy
};
const applyWorkingSelection = (state, action) => {
    const activeTab = getActiveTab(state);
    if (!activeTab) {
        return;
    }
    if (!activeTab.filterContext) {
        activeTab.filterContext = { ...filterContextInitialState };
    }
    invariant(activeTab.filterContext.filterContextDefinition, "Attempt to edit uninitialized filter context");
    const { enableImmediateAttributeFilterDisplayAsLabelMigration } = action.payload;
    activeTab.filterContext.filterContextDefinition = applyFilterContext(activeTab.filterContext.filterContextDefinition, activeTab.filterContext.workingFilterContextDefinition, enableImmediateAttributeFilterDisplayAsLabelMigration);
    activeTab.filterContext.workingFilterContextDefinition = { filters: [] };
};
//
//
//
const resetWorkingSelection = (state) => {
    const activeTab = getActiveTab(state);
    if (!activeTab) {
        return;
    }
    if (!activeTab.filterContext) {
        activeTab.filterContext = { ...filterContextInitialState };
    }
    invariant(activeTab.filterContext.workingFilterContextDefinition, "Attempt to edit uninitialized working filter context");
    activeTab.filterContext.workingFilterContextDefinition = { filters: [] };
};
//
//
//
const setDefaultFilterOverrides = (state, action) => {
    const activeTab = getActiveTab(state);
    if (!activeTab) {
        return;
    }
    if (!activeTab.filterContext) {
        activeTab.filterContext = { ...filterContextInitialState };
    }
    activeTab.filterContext.defaultFilterOverrides = action.payload;
};
const changeMeasureValueFilterCondition = (state, action) => {
    const activeTab = getActiveTab(state);
    if (!activeTab) {
        return;
    }
    if (!activeTab.filterContext) {
        activeTab.filterContext = { ...filterContextInitialState };
    }
    const { localIdentifier, conditions, isWorkingSelectionChange } = action.payload;
    const filterContextDefinition = isWorkingSelectionChange
        ? activeTab.filterContext?.workingFilterContextDefinition
        : activeTab.filterContext?.filterContextDefinition;
    invariant(filterContextDefinition?.filters, "Attempt to edit uninitialized filter context");
    const filters = filterContextDefinition.filters;
    const index = filters.findIndex((item) => isDashboardMeasureValueFilter(item) && dashboardFilterLocalIdentifier(item) === localIdentifier);
    const hasConditions = !!conditions && conditions.length > 0;
    invariant(index >= 0 || isWorkingSelectionChange, `Attempt to change condition of measure value filter ${localIdentifier} that does not exist`);
    if (isWorkingSelectionChange && index < 0) {
        const workingFilter = {
            dashboardMeasureValueFilter: {
                localIdentifier,
                conditions: hasConditions ? conditions : undefined,
            },
        };
        activeTab.filterContext.workingFilterContextDefinition.filters.push(workingFilter);
        return;
    }
    const filter = filters[index];
    filters[index] = {
        dashboardMeasureValueFilter: {
            ...filter.dashboardMeasureValueFilter,
            conditions: hasConditions ? conditions : undefined,
        },
    };
};
const changeMeasureValueFilterTitle = (state, action) => {
    const activeTab = getActiveTab(state);
    if (!activeTab) {
        return;
    }
    invariant(activeTab.filterContext?.filterContextDefinition?.filters, "Attempt to edit uninitialized filter context");
    const filters = activeTab.filterContext.filterContextDefinition.filters;
    const index = filters.findIndex((item) => isDashboardMeasureValueFilter(item) &&
        dashboardFilterLocalIdentifier(item) === action.payload.filterLocalId);
    invariant(index >= 0, `Attempt to change title of measure value filter ${action.payload.filterLocalId} that does not exist`);
    const filter = filters[index];
    filters[index] = {
        dashboardMeasureValueFilter: {
            ...filter.dashboardMeasureValueFilter,
            title: action.payload.title,
        },
    };
};
//
//
//
export const filterContextReducers = {
    setFilterContext,
    updateFilterContextIdentity,
    updateFilterContextIdentityForTab,
    removeAttributeFilterDisplayForms,
    addAttributeFilterDisplayForm,
    addAttributeFilter,
    addTextAttributeFilter,
    addMeasureValueFilter,
    removeMeasureValueFilter,
    moveMeasureValueFilter,
    removeAttributeFilter,
    moveAttributeFilter,
    addDateFilter,
    removeDateFilter,
    moveDateFilter,
    updateAttributeFilterSelection,
    replaceAttributeFilterItem,
    setAttributeFilterParents,
    setAttributeFilterDependentDateFilters,
    clearAttributeFiltersSelection,
    upsertDateFilter,
    changeAttributeDisplayForm,
    changeTextFilterDisplayForm,
    changeAttributeTitle,
    changeSelectionMode,
    changeLimitingItems,
    setPreloadedAttributesWithReferences,
    applyWorkingSelection,
    resetWorkingSelection,
    setDefaultFilterOverrides,
    changeMeasureValueFilterCondition,
    changeMeasureValueFilterTitle,
};
//# sourceMappingURL=filterContextReducers.js.map