// (C) 2021-2026 GoodData Corporation
import { invariant } from "ts-invariant";
import { areObjRefsEqual, isDashboardAttributeFilterReference, isDashboardDateFilterReference, isDashboardLayout, isDashboardLayoutItem, isDashboardMeasureValueFilterReference, isInsightWidget, isKpiWidget, isRichTextWidget, isVisualizationSwitcherWidget, } from "@gooddata/sdk-model";
import { findItem, findSection, findSections, getItemIndex, } from "../../../../_staging/layout/coordinates.js";
import { newMapForObjectWithIdentity } from "../../../../_staging/metadata/objRefMap.js";
import { setOrDelete } from "../../../../_staging/objectUtils/setOrDelete.js";
import { isCustomWidget, } from "../../../types/layoutTypes.js";
import { addArrayElements, removeArrayElement } from "../../../utils/arrayOps.js";
import { resetUndoReducer, undoReducer, withUndo } from "../../_infra/undoEnhancer.js";
import { layoutInitialState } from "./layoutState.js";
import { getWidgetCoordinatesAndItem, resizeInsightWidget } from "./layoutUtils.js";
/**
 * Adapts a core layout reducer (for LayoutState) to a tabs reducer (for TabsState).
 * Automatically applies the reducer to the active tab's layout state.
 */
function adaptLayoutReducer(coreLayoutReducer) {
    return (state, action) => {
        const activeTab = state.tabs?.find((tab) => tab.localIdentifier === state.activeTabLocalIdentifier);
        if (!activeTab)
            return;
        const layoutState = activeTab.layout;
        if (!layoutState)
            return;
        // Call the reducer - it may mutate the draft or return a new state (e.g., when wrapped with withUndo)
        const result = coreLayoutReducer(layoutState, action);
        // If the reducer returns a new state (like withUndo does), replace the layout
        if (result !== undefined) {
            activeTab.layout = result;
        }
    };
}
/**
 * Helper function to get the active tab's layout state.
 * Initializes the layout if it doesn't exist.
 * Returns undefined if no active tab is found.
 */
function getActiveTabLayout(state) {
    if (!state.tabs || !state.activeTabLocalIdentifier) {
        return undefined;
    }
    const activeTab = state.tabs.find((tab) => tab.localIdentifier === state.activeTabLocalIdentifier);
    if (!activeTab) {
        return undefined;
    }
    // Initialize layout state if it doesn't exist
    if (!activeTab.layout) {
        activeTab.layout = { ...layoutInitialState };
    }
    return activeTab.layout;
}
//
//
//
const setLayout = (state, action) => {
    const layoutState = getActiveTabLayout(state);
    if (!layoutState) {
        return;
    }
    layoutState.layout = action.payload;
    resetUndoReducer(layoutState);
};
//
//
//
function recurseLayoutAndUpdateWidgetIds(layout, mapping) {
    layout.sections.forEach((section) => {
        section.items.forEach((item) => {
            const widget = item.widget;
            if (isDashboardLayout(widget)) {
                return recurseLayoutAndUpdateWidgetIds(widget, mapping);
            }
            if (!isInsightWidget(widget) && !isKpiWidget(widget)) {
                return;
            }
            const { updated: newIdentity } = mapping.get(widget.ref) ?? {};
            if (!newIdentity) {
                return;
            }
            widget.ref = newIdentity.ref;
            widget.uri = newIdentity.uri;
            widget.identifier = newIdentity.identifier;
        });
    });
}
const updateWidgetIdentities = (state, action) => {
    const layoutState = getActiveTabLayout(state);
    invariant(layoutState?.layout);
    recurseLayoutAndUpdateWidgetIds(layoutState.layout, action.payload);
};
/**
 * Updates widget identities for a specific tab after a dashboard save.
 * This ensures that temporary widget IDs are replaced with persistent IDs
 * for widgets in the specified tab's layout.
 *
 * @param state - The tabs state
 * @param action - Object containing tabId and the identity mapping for that tab's widgets
 */
const updateWidgetIdentitiesForTab = (state, action) => {
    if (!state.tabs) {
        return;
    }
    const { tabId, mapping } = action.payload;
    const tab = state.tabs.find((t) => t.localIdentifier === tabId);
    if (!tab?.layout?.layout) {
        return;
    }
    recurseLayoutAndUpdateWidgetIds(tab.layout.layout, mapping);
};
// Core reducer that operates directly on LayoutState (which extends UndoEnhancedState)
const addSectionCore = (state, action) => {
    invariant(state.layout);
    const { index, section, usedStashes } = action.payload;
    const sections = findSections(state.layout, index);
    addArrayElements(sections, index.sectionIndex, [section]);
    usedStashes.forEach((stashIdentifier) => {
        delete state.stash[stashIdentifier];
    });
};
// Wrap with undo and adapt to TabsState
const addSection = adaptLayoutReducer(withUndo(addSectionCore));
const removeSectionCore = (state, action) => {
    invariant(state.layout);
    const { index, stashIdentifier } = action.payload;
    if (stashIdentifier) {
        state.stash[stashIdentifier] = findSection(state.layout, index).items;
    }
    const sections = findSections(state.layout, index);
    removeArrayElement(sections, index.sectionIndex);
};
// Wrap with undo and adapt to TabsState
const removeSection = adaptLayoutReducer(withUndo(removeSectionCore));
const changeSectionHeaderCore = (state, action) => {
    invariant(state.layout);
    const { index, header } = action.payload;
    findSection(state.layout, index).header = header;
};
// Wrap with undo and adapt to TabsState
const changeSectionHeader = adaptLayoutReducer(withUndo(changeSectionHeaderCore));
const toggleLayoutSectionHeadersCore = (state, action) => {
    invariant(state.layout);
    const { layoutPath, enableSectionHeaders } = action.payload;
    const layout = layoutPath === undefined ? state.layout : findItem(state.layout, layoutPath);
    if (isDashboardLayoutItem(layout) && isDashboardLayout(layout.widget)) {
        layout.widget = {
            ...layout.widget,
            configuration: {
                ...(layout.widget.configuration ?? {}),
                sections: {
                    ...(layout.widget.configuration?.sections ?? {}),
                    enableHeader: enableSectionHeaders,
                },
            },
        };
    }
};
// Wrap with undo and adapt to TabsState
const toggleLayoutSectionHeaders = adaptLayoutReducer(withUndo(toggleLayoutSectionHeadersCore));
const toggleLayoutDirectionCore = (state, action) => {
    invariant(state.layout);
    const { layoutPath, direction } = action.payload;
    const layout = layoutPath === undefined ? state.layout : findItem(state.layout, layoutPath);
    if (isDashboardLayoutItem(layout) && isDashboardLayout(layout.widget)) {
        layout.widget = {
            ...layout.widget,
            configuration: {
                ...(layout.widget.configuration ?? {}),
                direction,
            },
        };
    }
};
// Wrap with undo and adapt to TabsState
const toggleLayoutDirection = adaptLayoutReducer(withUndo(toggleLayoutDirectionCore));
const changeItemsHeight = (state, action) => {
    const layoutState = getActiveTabLayout(state);
    invariant(layoutState?.layout);
    const { sectionIndex, itemIndexes, height } = action.payload;
    const section = findSection(layoutState.layout, sectionIndex);
    itemIndexes.forEach((itemIndex) => {
        const item = section.items[itemIndex];
        if (isCustomWidget(item.widget)) {
            return;
        }
        item.size = {
            ...item.size,
            xl: {
                ...item.size.xl,
                gridHeight: height,
            },
        };
    });
};
const updateHeightOfMultipleItems = (state, action) => {
    const layoutState = getActiveTabLayout(state);
    invariant(layoutState?.layout);
    const rootLayout = layoutState.layout;
    const { itemsWithSizes } = action.payload;
    itemsWithSizes.forEach(({ itemPath, height }) => {
        const item = findItem(rootLayout, itemPath);
        if (isCustomWidget(item.widget)) {
            return;
        }
        item.size = {
            ...item.size,
            xl: {
                ...item.size.xl,
                gridHeight: height,
            },
        };
    });
};
const updateWidthOfMultipleItems = (state, action) => {
    const layoutState = getActiveTabLayout(state);
    invariant(layoutState?.layout);
    const rootLayout = layoutState.layout;
    const { itemsWithSizes } = action.payload;
    itemsWithSizes.forEach(({ itemPath, width }) => {
        const item = findItem(rootLayout, itemPath);
        if (isCustomWidget(item.widget)) {
            return;
        }
        item.size = {
            ...item.size,
            xl: {
                ...item.size.xl,
                gridWidth: width,
            },
        };
    });
};
const changeItemWidth = (state, action) => {
    const layoutState = getActiveTabLayout(state);
    invariant(layoutState?.layout);
    const { layoutPath, width } = action.payload;
    const item = findItem(layoutState.layout, layoutPath);
    item.size = {
        ...item.size,
        xl: {
            ...item.size.xl,
            gridWidth: width,
        },
    };
};
const moveSectionCore = (state, action) => {
    invariant(state.layout);
    const { sectionIndex, toIndex } = action.payload;
    const originalSections = findSections(state.layout, sectionIndex);
    const movedSection = removeArrayElement(originalSections, sectionIndex.sectionIndex);
    const targetSections = findSections(state.layout, toIndex);
    addArrayElements(targetSections, toIndex.sectionIndex, [movedSection]);
};
// Wrap with undo and adapt to TabsState
const moveSection = adaptLayoutReducer(withUndo(moveSectionCore));
const addSectionItemsCore = (state, action) => {
    invariant(state.layout);
    const { layoutPath, items, usedStashes } = action.payload;
    const section = findSection(state.layout, layoutPath);
    invariant(section);
    const itemIndexAtTargetSection = getItemIndex(layoutPath);
    addArrayElements(section.items, itemIndexAtTargetSection, items);
    usedStashes.forEach((stashIdentifier) => {
        delete state.stash[stashIdentifier];
    });
};
// Wrap with undo and adapt to TabsState
const addSectionItems = adaptLayoutReducer(withUndo(addSectionItemsCore));
const moveSectionItemCore = (state, action) => {
    invariant(state.layout);
    const { itemIndex, toItemIndex } = action.payload;
    const fromSection = findSection(state.layout, itemIndex);
    const toSection = findSection(state.layout, toItemIndex);
    invariant(fromSection);
    invariant(toSection);
    const itemIndexAtSourceSection = getItemIndex(itemIndex);
    const item = removeArrayElement(fromSection.items, itemIndexAtSourceSection);
    invariant(item);
    const itemIndexAtTargetSection = getItemIndex(toItemIndex);
    addArrayElements(toSection.items, itemIndexAtTargetSection, [item]);
};
// Wrap with undo and adapt to TabsState
const moveSectionItem = adaptLayoutReducer(withUndo(moveSectionItemCore));
const removeSectionItemCore = (state, action) => {
    invariant(state.layout);
    const { itemIndex, stashIdentifier } = action.payload;
    const section = findSection(state.layout, itemIndex);
    invariant(section);
    const item = removeArrayElement(section.items, getItemIndex(itemIndex));
    invariant(item);
    if (stashIdentifier) {
        state.stash[stashIdentifier] = [item];
    }
};
// Wrap with undo and adapt to TabsState
const removeSectionItem = adaptLayoutReducer(withUndo(removeSectionItemCore));
const replaceSectionItemCore = (state, action) => {
    invariant(state.layout);
    const { layoutPath, newItems, stashIdentifier, usedStashes } = action.payload;
    const section = findSection(state.layout, layoutPath);
    invariant(section);
    const itemIndexAtSourceSection = getItemIndex(layoutPath);
    const item = removeArrayElement(section.items, itemIndexAtSourceSection);
    invariant(item);
    if (stashIdentifier) {
        state.stash[stashIdentifier] = [item];
    }
    addArrayElements(section.items, itemIndexAtSourceSection, newItems);
    usedStashes.forEach((usedStash) => {
        /*
         * It is a valid case that the new item is taken from a stash and the replaced item is then
         * used to replace the same stash.
         */
        if (stashIdentifier !== undefined && usedStash === stashIdentifier) {
            return;
        }
        delete state.stash[usedStash];
    });
};
//
// Wrap with undo and adapt to TabsState
const replaceSectionItem = adaptLayoutReducer(withUndo(replaceSectionItemCore));
//
//
//
// Layout-widget specific reducers
//
const processSection = (section) => {
    return section.items.flatMap((item) => {
        let result = [];
        const widget = item.widget;
        if (widget === undefined) {
            return [];
        }
        if (isVisualizationSwitcherWidget(widget)) {
            result = [widget, ...widget.visualizations];
            return result;
        }
        else if (isDashboardLayout(widget)) {
            result = [widget, ...widget.sections.flatMap(processSection)];
            return result;
        }
        return [widget];
    });
};
const getWidgetByRef = (state, widgetRef) => {
    const allWidgets = state?.layout?.sections.flatMap(processSection) ?? [];
    const widgets = allWidgets.filter(Boolean);
    return newMapForObjectWithIdentity(widgets).get(widgetRef);
};
const replaceWidgetHeaderCore = (state, action) => {
    invariant(state.layout);
    const { header, ref } = action.payload;
    const widget = getWidgetByRef(state, ref);
    // this means command handler did not correctly validate that the widget exists before dispatching the
    // reducer action
    invariant(widget && (isKpiWidget(widget) || isInsightWidget(widget)));
    widget.title = header.title ?? "";
};
// Wrap with undo and adapt to TabsState
const replaceWidgetHeader = adaptLayoutReducer(withUndo(replaceWidgetHeaderCore));
const replaceWidgetDescriptionCore = (state, action) => {
    invariant(state.layout);
    const { description, ref } = action.payload;
    const widget = getWidgetByRef(state, ref);
    // this means command handler did not correctly validate that the widget exists before dispatching the
    // reducer action
    invariant(widget && (isKpiWidget(widget) || isInsightWidget(widget)));
    widget.description = description.description ?? "";
};
// Wrap with undo and adapt to TabsState
const replaceWidgetDescription = adaptLayoutReducer(withUndo(replaceWidgetDescriptionCore));
const replaceWidgetDrill = (state, action) => {
    const layoutState = getActiveTabLayout(state);
    invariant(layoutState?.layout);
    const { drillDefinitions, ref } = action.payload;
    const widget = getWidgetByRef(layoutState, ref);
    // this means command handler did not correctly validate that the widget exists before dispatching the
    // reducer action
    invariant(widget && (isKpiWidget(widget) || isInsightWidget(widget)));
    widget.drills = drillDefinitions ?? [];
};
const replaceWidgetDrillCore = (state, action) => {
    invariant(state.layout);
    const { drillDefinitions, ref } = action.payload;
    const widget = getWidgetByRef(state, ref);
    // this means command handler did not correctly validate that the widget exists before dispatching the
    // reducer action
    invariant(widget && (isKpiWidget(widget) || isInsightWidget(widget)));
    widget.drills = drillDefinitions ?? [];
};
const replaceWidgetDrills = adaptLayoutReducer(withUndo(replaceWidgetDrillCore));
//
const replaceWidgetBlacklistHierarchiesCore = (state, action) => {
    invariant(state.layout);
    const { blacklistHierarchies, ref } = action.payload;
    const widget = getWidgetByRef(state, ref);
    invariant(widget && (isKpiWidget(widget) || isInsightWidget(widget)));
    widget.ignoredDrillDownHierarchies = blacklistHierarchies ?? [];
};
// Wrap with undo and adapt to TabsState
const replaceWidgetBlacklistHierarchies = adaptLayoutReducer(withUndo(replaceWidgetBlacklistHierarchiesCore));
//
const replaceWidgetBlacklistAttributesCore = (state, action) => {
    invariant(state.layout);
    const { blacklistAttributes, ref } = action.payload;
    const widget = getWidgetByRef(state, ref);
    invariant(widget && (isKpiWidget(widget) || isInsightWidget(widget)));
    widget.ignoredDrillToUrlAttributes = blacklistAttributes ?? [];
};
// Wrap with undo and adapt to TabsState
const replaceWidgetBlacklistAttributes = adaptLayoutReducer(withUndo(replaceWidgetBlacklistAttributesCore));
//
const replaceWidgetDrillDownIntersectionIgnoredAttributesCore = (state, action) => {
    invariant(state.layout);
    const { ignoredDrillDownIntersectionIgnoredAttributes, ref } = action.payload;
    const widget = getWidgetByRef(state, ref);
    invariant(widget && (isKpiWidget(widget) || isInsightWidget(widget)));
    widget.drillDownIntersectionIgnoredAttributes = ignoredDrillDownIntersectionIgnoredAttributes ?? [];
};
// Wrap with undo and adapt to TabsState
const replaceWidgetDrillDownIntersectionIgnoredAttributes = adaptLayoutReducer(withUndo(replaceWidgetDrillDownIntersectionIgnoredAttributesCore));
const replaceInsightWidgetVisPropertiesCore = (state, action) => {
    invariant(state.layout);
    const { properties, ref } = action.payload;
    const widget = getWidgetByRef(state, ref);
    invariant(widget && isInsightWidget(widget));
    setOrDelete(widget, "properties", properties);
};
// Wrap with undo and adapt to TabsState
const replaceInsightWidgetVisProperties = adaptLayoutReducer(withUndo(replaceInsightWidgetVisPropertiesCore));
const replaceInsightWidgetVisConfigurationCore = (state, action) => {
    invariant(state.layout);
    const { config, ref } = action.payload;
    const widget = getWidgetByRef(state, ref);
    invariant(widget && isInsightWidget(widget));
    setOrDelete(widget, "configuration", config);
};
// Wrap with undo and adapt to TabsState
const replaceInsightWidgetVisConfiguration = adaptLayoutReducer(withUndo(replaceInsightWidgetVisConfigurationCore));
const replaceInsightWidgetInsightCore = (state, action) => {
    invariant(state.layout);
    const { insightRef, properties, ref, header, newSize } = action.payload;
    const widget = getWidgetByRef(state, ref);
    const data = getWidgetCoordinatesAndItem(state.layout, ref);
    invariant(isInsightWidget(widget), "IInsightWidget is missing in state");
    if (properties) {
        widget.properties = properties;
    }
    if (header?.title) {
        widget.title = header.title;
    }
    widget.insight = insightRef;
    if (newSize && data?.item) {
        data.item.size.xl = resizeInsightWidget(data.item.size.xl, newSize);
    }
};
// Wrap with undo and adapt to TabsState
const replaceInsightWidgetInsight = adaptLayoutReducer(withUndo(replaceInsightWidgetInsightCore));
const replaceWidgetFilterSettingsCore = (state, action) => {
    invariant(state.layout);
    const { ignoreDashboardFilters, dateDataSet, ref } = action.payload;
    const widget = getWidgetByRef(state, ref);
    invariant(widget && (isInsightWidget(widget) || isKpiWidget(widget) || isRichTextWidget(widget)));
    widget.dateDataSet = dateDataSet;
    widget.ignoreDashboardFilters = ignoreDashboardFilters ?? [];
};
// Wrap with undo and adapt to TabsState
const replaceWidgetFilterSettings = adaptLayoutReducer(withUndo(replaceWidgetFilterSettingsCore));
const removeIgnoredAttributeFilterFromLayout = (layout, displayFormRefs) => {
    layout.sections.forEach((section) => {
        section.items.forEach((item) => {
            const widget = item.widget;
            if (isInsightWidget(widget) || isKpiWidget(widget)) {
                widget.ignoreDashboardFilters = widget.ignoreDashboardFilters.filter((filter) => {
                    if (isDashboardDateFilterReference(filter) ||
                        isDashboardMeasureValueFilterReference(filter)) {
                        return true;
                    }
                    return (displayFormRefs.find((removed) => areObjRefsEqual(removed, filter.displayForm)) ===
                        undefined);
                });
            }
            else if (isDashboardLayout(widget)) {
                removeIgnoredAttributeFilterFromLayout(widget, displayFormRefs);
            }
        });
    });
};
const removeIgnoredAttributeFilter = (state, action) => {
    const layoutState = getActiveTabLayout(state);
    invariant(layoutState?.layout);
    removeIgnoredAttributeFilterFromLayout(layoutState.layout, action.payload.displayFormRefs);
};
const replaceWidgetDateDatasetCore = (state, action) => {
    invariant(state.layout);
    const { dateDataSet, ref } = action.payload;
    const widget = getWidgetByRef(state, ref);
    invariant(widget && (isInsightWidget(widget) || isKpiWidget(widget)));
    widget.dateDataSet = dateDataSet;
};
// Wrap with undo and adapt to TabsState
const replaceWidgetDateDataset = adaptLayoutReducer(withUndo(replaceWidgetDateDatasetCore));
const removeIgnoredDateFilterFromLayout = (layout, dateDataSets) => {
    layout.sections.forEach((section) => {
        section.items.forEach((item) => {
            const widget = item.widget;
            if (isInsightWidget(widget) || isKpiWidget(widget)) {
                widget.ignoreDashboardFilters = widget.ignoreDashboardFilters.filter((filter) => {
                    if (isDashboardAttributeFilterReference(filter) ||
                        isDashboardMeasureValueFilterReference(filter)) {
                        return true;
                    }
                    return (dateDataSets.find((removed) => areObjRefsEqual(removed, filter.dataSet)) === undefined);
                });
            }
            else if (isDashboardLayout(widget)) {
                removeIgnoredDateFilterFromLayout(widget, dateDataSets);
            }
        });
    });
};
const removeIgnoredDateFilter = (state, action) => {
    const layoutState = getActiveTabLayout(state);
    invariant(layoutState?.layout);
    removeIgnoredDateFilterFromLayout(layoutState.layout, action.payload.dateDataSets);
};
const replaceKpiWidgetMeasureCore = (state, action) => {
    invariant(state.layout);
    const { ref, measureRef } = action.payload;
    const widget = getWidgetByRef(state, ref);
    invariant(widget && isKpiWidget(widget));
    widget.kpi.metric = measureRef;
};
// Wrap with undo and adapt to TabsState
const replaceKpiWidgetMeasure = adaptLayoutReducer(withUndo(replaceKpiWidgetMeasureCore));
const replaceKpiWidgetComparisonCore = (state, action) => {
    invariant(state.layout);
    const { ref, comparisonType, comparisonDirection } = action.payload;
    const widget = getWidgetByRef(state, ref);
    invariant(widget && isKpiWidget(widget));
    widget.kpi.comparisonType = comparisonType;
    widget.kpi.comparisonDirection = comparisonDirection;
};
// Wrap with undo and adapt to TabsState
const replaceKpiWidgetComparison = adaptLayoutReducer(withUndo(replaceKpiWidgetComparisonCore));
const replaceKpiWidgetDrillCore = (state, action) => {
    invariant(state.layout);
    const { ref, drill } = action.payload;
    const widget = getWidgetByRef(state, ref);
    invariant(widget && isKpiWidget(widget));
    widget.drills = drill ? [drill] : [];
};
// Wrap with undo and adapt to TabsState
const replaceKpiWidgetDrill = adaptLayoutReducer(withUndo(replaceKpiWidgetDrillCore));
const replaceKpiWidgetConfigurationCore = (state, action) => {
    invariant(state.layout);
    const { config, ref } = action.payload;
    const widget = getWidgetByRef(state, ref);
    invariant(widget && isKpiWidget(widget));
    setOrDelete(widget, "configuration", config);
};
// Wrap with undo and adapt to TabsState
const replaceKpiWidgetConfiguration = adaptLayoutReducer(withUndo(replaceKpiWidgetConfigurationCore));
const replaceRichTextWidgetContentCore = (state, action) => {
    invariant(state.layout);
    const { content, ref } = action.payload;
    const widget = getWidgetByRef(state, ref);
    invariant(widget && isRichTextWidget(widget));
    setOrDelete(widget, "content", content);
};
// Wrap with undo and adapt to TabsState
const replaceRichTextWidgetContent = adaptLayoutReducer(withUndo(replaceRichTextWidgetContentCore));
const changeWidgetIgnoreCrossFilteringCore = (state, action) => {
    invariant(state.layout);
    const { ignoreCrossFiltering, ref } = action.payload;
    const widget = getWidgetByRef(state, ref);
    invariant(widget && (isInsightWidget(widget) || isKpiWidget(widget)));
    widget.ignoreCrossFiltering = ignoreCrossFiltering;
};
// Wrap with undo and adapt to TabsState
const changeWidgetIgnoreCrossFiltering = adaptLayoutReducer(withUndo(changeWidgetIgnoreCrossFilteringCore));
const addVisualizationSwitcherWidgetVisualizationCore = (state, action) => {
    invariant(state.layout);
    const { visualization, ref, newSize } = action.payload;
    const widgetRef = getWidgetByRef(state, ref);
    const data = getWidgetCoordinatesAndItem(state.layout, ref);
    invariant(widgetRef && isVisualizationSwitcherWidget(widgetRef));
    widgetRef.visualizations.push(visualization);
    if (newSize && data?.item) {
        data.item.size.xl = resizeInsightWidget(data.item.size.xl, newSize);
    }
};
// Wrap with undo and adapt to TabsState
const addVisualizationSwitcherWidgetVisualization = adaptLayoutReducer(withUndo(addVisualizationSwitcherWidgetVisualizationCore));
const updateVisualizationSwitcherWidgetVisualizationsCore = (state, action) => {
    invariant(state.layout);
    const { visualizations, ref } = action.payload;
    const widgetRef = getWidgetByRef(state, ref);
    invariant(widgetRef && isVisualizationSwitcherWidget(widgetRef));
    widgetRef.visualizations = visualizations;
};
// Wrap with undo and adapt to TabsState
const updateVisualizationSwitcherWidgetVisualizations = adaptLayoutReducer(withUndo(updateVisualizationSwitcherWidgetVisualizationsCore));
const resizeVisualizationSwitcherOnInsightChangedCore = (state, action) => {
    invariant(state.layout);
    const { ref, newSize } = action.payload;
    const widgetRef = getWidgetByRef(state, ref);
    const data = getWidgetCoordinatesAndItem(state.layout, ref);
    invariant(widgetRef && isVisualizationSwitcherWidget(widgetRef));
    if (newSize && data?.item) {
        data.item.size.xl = resizeInsightWidget(data.item.size.xl, newSize);
    }
};
// Wrap with undo and adapt to TabsState
const resizeVisualizationSwitcherOnInsightChanged = adaptLayoutReducer(withUndo(resizeVisualizationSwitcherOnInsightChangedCore));
const setScreen = (state, action) => {
    // Update screen for all tabs, not just the active one
    // Screen size is a global property that affects all tabs
    state.tabs?.forEach((tab) => {
        if (tab.layout) {
            tab.layout.screen = action.payload.screen;
        }
    });
};
export const layoutReducers = {
    setLayout,
    setScreen,
    updateWidgetIdentities,
    updateWidgetIdentitiesForTab,
    removeIgnoredAttributeFilter,
    removeIgnoredDateFilter,
    addSection,
    removeSection,
    moveSection,
    changeSectionHeader,
    addSectionItems,
    moveSectionItem,
    removeSectionItem,
    replaceSectionItem,
    replaceWidgetHeader,
    replaceWidgetDescription,
    replaceWidgetDrillWithoutUndo: replaceWidgetDrill, // useful in internal sanitization use cases
    replaceWidgetDrills,
    replaceWidgetBlacklistHierarchies,
    replaceWidgetBlacklistAttributes,
    replaceWidgetDrillDownIntersectionIgnoredAttributes,
    replaceInsightWidgetVisProperties,
    replaceInsightWidgetVisConfiguration,
    replaceInsightWidgetInsight,
    replaceWidgetFilterSettings,
    replaceWidgetDateDataset,
    replaceKpiWidgetMeasure,
    replaceKpiWidgetComparison,
    replaceKpiWidgetDrillWithoutUndo: replaceWidgetDrill, // useful in internal sanitization use cases
    replaceKpiWidgetDrill,
    replaceKpiWidgetConfiguration,
    replaceRichTextWidgetContent,
    addVisualizationSwitcherWidgetVisualization,
    updateVisualizationSwitcherWidgetVisualizations,
    undoLayout: adaptLayoutReducer(undoReducer),
    clearLayoutHistory: adaptLayoutReducer((state, _action) => {
        resetUndoReducer(state);
    }),
    changeItemsHeight,
    changeItemWidth,
    changeWidgetIgnoreCrossFiltering,
    resizeVisualizationSwitcherOnInsightChanged,
    toggleLayoutSectionHeaders,
    toggleLayoutDirection,
    updateHeightOfMultipleItems,
    updateWidthOfMultipleItems,
};
//# sourceMappingURL=layoutReducers.js.map