// (C) 2021-2026 GoodData Corporation
import { compact, omit } from "lodash-es";
import { batchActions } from "redux-batched-actions";
import { all, call, put, select } from "redux-saga/effects";
import { generateDateFilterLocalIdentifier } from "@gooddata/sdk-backend-base";
import { dashboardFilterLocalIdentifier, filterLocalIdentifier, filterObjRef, idRef, insightFilters, isAbsoluteDateFilter, isAttributeFilter, isDashboardAttributeFilter, isDashboardAttributeFilterItem, isDashboardCommonDateFilter, isDashboardDateFilter, isDateFilter, isExportDefinitionDashboardRequestPayload, isExportDefinitionVisualizationObjectRequestPayload, isFilterContextItem, isInsightWidget, isRelativeDateFilter, isSingleSelectionFilter, } from "@gooddata/sdk-model";
import { convertError } from "@gooddata/sdk-ui";
import { dashboardFilterToFilterContextItem } from "../../../_staging/dashboard/dashboardFilterContext.js";
import { isDashboardFilter } from "../../../types.js";
import { changeFilterContextSelection, changeFilterContextSelectionByParams, } from "../../commands/filters.js";
import { switchDashboardTab } from "../../commands/tabs.js";
import { dispatchDashboardEvent } from "../../store/_infra/eventDispatcher.js";
import { selectAutomationsIsInitialized, selectAutomationsIsLoading, } from "../../store/automations/automationsSelectors.js";
import { automationsActions } from "../../store/automations/index.js";
import { selectEnableArbitraryFilterKD, selectEnableAutomations, selectEnableInPlatformNotifications, selectEnableMatchFilterKD, selectEnableNotificationChannelIdentifiers, selectExternalRecipient, selectFocusObject, selectIsExport, selectIsReadOnly, selectOpenAutomationOnLoad, } from "../../store/config/configSelectors.js";
import { selectInsightByWidgetRef } from "../../store/insights/insightsSelectors.js";
import { selectDashboardId } from "../../store/meta/metaSelectors.js";
import { notificationChannelsActions } from "../../store/notificationChannels/index.js";
import { selectCanManageWorkspace } from "../../store/permissions/permissionsSelectors.js";
import { selectIsInExportMode } from "../../store/renderMode/renderModeSelectors.js";
import { selectAttributeFilterConfigsSelectionTypeMap, selectAttributeFilterConfigsSelectionTypeMapByTab, } from "../../store/tabs/attributeFilterConfigs/attributeFilterConfigsSelectors.js";
import { selectFilterContextFilters, selectFiltersForTab, } from "../../store/tabs/filterContext/filterContextSelectors.js";
import { selectWidgetByRef } from "../../store/tabs/layout/layoutSelectors.js";
import { selectActiveTabLocalIdentifier } from "../../store/tabs/tabsSelectors.js";
import { uiActions } from "../../store/ui/index.js";
import { selectCurrentUser } from "../../store/user/userSelectors.js";
import { isFilterTypeCompatibleWithSelectionType } from "../dashboard/common/attributeFilterSelectionTypeCompatibility.js";
import { changeFilterContextSelectionHandler } from "../filterContext/changeFilterContextSelectionHandler.js";
import { switchDashboardTabHandler } from "../tabs/switchDashboardTabHandler.js";
import { loadDashboardUserAutomations, loadWorkspaceAutomationsCount } from "./loadAutomations.js";
import { loadNotificationChannels } from "./loadNotificationChannels.js";
export function* initializeAutomationsHandler(ctx, _cmd) {
    const dashboardId = yield select(selectDashboardId);
    const user = yield select(selectCurrentUser);
    const canManageAutomations = yield select(selectCanManageWorkspace);
    const enableAutomations = yield select(selectEnableAutomations);
    const enableInPlatformNotifications = yield select(selectEnableInPlatformNotifications);
    const enableArbitraryFilterKD = yield select(selectEnableArbitraryFilterKD);
    const enableMatchFilterKD = yield select(selectEnableMatchFilterKD);
    const enableNotificationChannelIdentifiers = yield select(selectEnableNotificationChannelIdentifiers);
    const automationsInitialized = yield select(selectAutomationsIsInitialized);
    const automationsIsLoading = yield select(selectAutomationsIsLoading);
    const isReadOnly = yield select(selectIsReadOnly);
    const isExport = yield select(selectIsExport);
    const isInExportMode = yield select(selectIsInExportMode);
    const { automationId } = yield select(selectFocusObject);
    const externalRecipient = yield select(selectExternalRecipient);
    const openAutomationOnLoad = yield select(selectOpenAutomationOnLoad);
    if (!dashboardId ||
        !user ||
        !enableAutomations ||
        automationsInitialized ||
        automationsIsLoading ||
        isReadOnly ||
        isExport ||
        isInExportMode) {
        return;
    }
    yield put(automationsActions.setAutomationsLoading(true));
    try {
        const [automations, allAutomationsCount, notificationChannels] = yield all([
            call(loadDashboardUserAutomations, ctx, dashboardId, user.login, !canManageAutomations, externalRecipient),
            call(loadWorkspaceAutomationsCount, ctx),
            call(loadNotificationChannels, ctx, enableInPlatformNotifications, enableNotificationChannelIdentifiers),
        ]);
        // Set filters according to provided automationId
        if (automationId) {
            const targetAutomation = automations.find((a) => a.id === automationId);
            const targetWidget = targetAutomation?.metadata?.widget;
            const targetTabIdentifier = targetAutomation?.metadata?.targetTabIdentifier;
            // Switch to the tab containing the target widget if necessary
            if (targetTabIdentifier) {
                const currentActiveTabId = yield select(selectActiveTabLocalIdentifier);
                // If widget is on a different tab, switch to it before continuing
                if (targetTabIdentifier !== currentActiveTabId) {
                    const switchTabCmd = switchDashboardTab(targetTabIdentifier);
                    const switchedEvent = yield call(switchDashboardTabHandler, ctx, switchTabCmd);
                    yield dispatchDashboardEvent(switchedEvent);
                }
            }
            const insight = yield select(selectInsightByWidgetRef(targetWidget ? idRef(targetWidget) : undefined));
            const filterContextFilters = yield select(selectFilterContextFilters);
            const commonDateFilter = filterContextFilters.find(isDashboardCommonDateFilter);
            const commonDateFilterLocalId = commonDateFilter?.dateFilter.localIdentifier ?? generateDateFilterLocalIdentifier(0);
            const activeTabLocalIdentifier = yield select(selectActiveTabLocalIdentifier);
            const selectionTypeMapByTab = yield select(selectAttributeFilterConfigsSelectionTypeMapByTab);
            const selectionTypeMap = yield select(selectAttributeFilterConfigsSelectionTypeMap);
            const effectiveActiveTabSelectionTypeMap = resolveSelectionTypeMapForActiveTab(selectionTypeMapByTab, selectionTypeMap, activeTabLocalIdentifier);
            const { targetAlertFilters, targetExportDefinition, targetExportDefinitionFilters, targetExportVisibleFilters, } = extractRelevantFilters(targetAutomation, insight, activeTabLocalIdentifier);
            // Set filters to the dashboard based on alert execution filters
            if (targetWidget && targetAlertFilters) {
                const widget = yield select(selectWidgetByRef(idRef(targetWidget)));
                const filtersToSet = insight && isInsightWidget(widget)
                    ? getDashboardFiltersOnly(targetAlertFilters, commonDateFilterLocalId, insight, widget)
                    : targetAlertFilters;
                const keepDateFilterDataSets = !!ctx.backend.capabilities.supportsMultipleDateFilters;
                const filtersToSetAsFilterContextItems = filtersToSet.map((filter) => dashboardFilterToFilterContextItem(filter, keepDateFilterDataSets));
                const compatibleFiltersToSet = filtersToSetAsFilterContextItems.filter((filter) => isFilterContextItemCompatibleWithSelectionType(filter, effectiveActiveTabSelectionTypeMap, enableArbitraryFilterKD, enableMatchFilterKD, filterContextFilters));
                // Empty alert execution filters = reset all filters (set them to all).
                // Empty sanitized filters = keep filters as they are, do not reset them (all alert execution filters are insight specific / ignored).
                // Non-empty sanitized filters = set them (some alert execution filters are originating from the dashboard).
                if (targetAlertFilters.length === 0 || compatibleFiltersToSet.length > 0) {
                    const cmd = changeFilterContextSelection(compatibleFiltersToSet, true, automationId);
                    yield call(changeFilterContextSelectionHandler, ctx, cmd);
                }
            }
            // Set filters to the dashboard based on export definition filters
            if (targetExportDefinition) {
                const exportContent = targetExportDefinition.requestPayload;
                if (isExportDefinitionDashboardRequestPayload(exportContent) &&
                    exportContent.content.filtersByTab) {
                    // Multi-tab path: apply each tab's filters with explicit tabLocalIdentifier
                    const filtersByTab = exportContent.content.filtersByTab;
                    for (const [tabId, tabFilters] of Object.entries(filtersByTab)) {
                        const tabCurrentFilters = yield select(selectFiltersForTab(tabId));
                        const tabCommonDateFilter = tabCurrentFilters.find(isDashboardCommonDateFilter);
                        const tabCommonDateFilterLocalId = tabCommonDateFilter?.dateFilter.localIdentifier ??
                            generateDateFilterLocalIdentifier(0);
                        const tabVisibleFilters = extractVisibleFiltersForTab(targetAutomation, tabId);
                        const compactedTabFilters = compact(tabFilters);
                        const filtersToSet = compactedTabFilters.filter((filter) => {
                            if (tabVisibleFilters) {
                                return tabVisibleFilters.some((f) => f.localIdentifier === dashboardFilterLocalIdentifier(filter));
                            }
                            return true;
                        });
                        const sanitizedFilters = sanitizeDateFilters(filtersToSet, tabCommonDateFilterLocalId);
                        const tabSelectionTypeMap = selectionTypeMapByTab[tabId];
                        const compatibleFilters = sanitizedFilters.filter((filter) => isFilterContextItemCompatibleWithSelectionType(filter, tabSelectionTypeMap, enableArbitraryFilterKD, enableMatchFilterKD, tabCurrentFilters));
                        // Empty tab filters = reset all filters (set them to all).
                        // Empty sanitized filters = keep filters as they are.
                        // Non-empty sanitized filters = set them.
                        if (compactedTabFilters.length === 0 || compatibleFilters.length > 0) {
                            const cmd = changeFilterContextSelectionByParams({
                                filters: compatibleFilters,
                                resetOthers: true,
                                correlationId: automationId,
                                tabLocalIdentifier: tabId,
                            });
                            yield call(changeFilterContextSelectionHandler, ctx, cmd);
                        }
                    }
                }
                else if (targetExportDefinitionFilters) {
                    // Flat filters path: backward compatibility for non-tab export definitions
                    const filtersToSet = targetExportDefinitionFilters?.filter((filter) => {
                        if (targetExportVisibleFilters) {
                            return targetExportVisibleFilters.some((f) => f.localIdentifier === dashboardFilterLocalIdentifier(filter));
                        }
                        return true;
                    }) ?? [];
                    const sanitizedFiltersToSet = sanitizeDateFilters(filtersToSet, commonDateFilterLocalId);
                    const compatibleFiltersToSet = sanitizedFiltersToSet.filter((filter) => isFilterContextItemCompatibleWithSelectionType(filter, effectiveActiveTabSelectionTypeMap, enableArbitraryFilterKD, enableMatchFilterKD, filterContextFilters));
                    // Empty schedule execution filters = reset all filters (set them to all).
                    // Empty sanitized filters = keep filters as they are, do not reset them (all schedule execution filters are ignored).
                    // Non-empty sanitized filters = set them (some schedule export definition filters are originating from the dashboard).
                    if (targetExportDefinitionFilters.length === 0 || compatibleFiltersToSet.length > 0) {
                        const cmd = changeFilterContextSelection(compatibleFiltersToSet, true, automationId);
                        yield call(changeFilterContextSelectionHandler, ctx, cmd);
                    }
                }
            }
            if (targetAutomation && openAutomationOnLoad) {
                const widgetRef = targetWidget && idRef(targetWidget);
                if (targetAutomation.alert) {
                    yield put(uiActions.openAlertingDialog({
                        widgetRef: widgetRef || undefined,
                        alert: targetAutomation,
                    }));
                }
                if (targetAutomation.schedule) {
                    yield put(uiActions.openScheduleEmailDialog({
                        ...(widgetRef
                            ? { widgetRef, openedFrom: "widget" }
                            : { openedFrom: "dashboard" }),
                        schedule: targetAutomation,
                    }));
                }
            }
        }
        yield put(batchActions([
            automationsActions.setAutomationsInitialized(),
            automationsActions.setAutomationsLoading(false),
            automationsActions.setUserAutomations(automations),
            automationsActions.setAllAutomationsCount(allAutomationsCount),
            notificationChannelsActions.setNotificationChannels(notificationChannels),
        ]));
    }
    catch (e) {
        yield put(batchActions([
            automationsActions.setAutomationsInitialized(),
            automationsActions.setAutomationsLoading(false),
            automationsActions.setAutomationsError(convertError(e)),
        ]));
    }
}
function extractRelevantFilters(targetAutomation, insight, activeTabLocalIdentifier) {
    //alert, widget
    const targetAlertFilters = targetAutomation?.alert?.execution?.filters;
    const sanitizedTargetAlertFilters = 
    // Remove filters that are applied in the insight
    targetAlertFilters && insight
        ? removeInsightAttributeFilters(targetAlertFilters, insight).filter(isDashboardFilter)
        : undefined;
    //export definition
    const targetExportDefinition = targetAutomation?.exportDefinitions?.[0];
    const targetExportDefinitionFilters = extractExportDefinitionFilters(targetExportDefinition?.requestPayload, activeTabLocalIdentifier);
    const targetExportVisibleFilters = extractVisibleFiltersForTab(targetAutomation, activeTabLocalIdentifier);
    return {
        targetAlertFilters: sanitizedTargetAlertFilters,
        targetExportDefinition,
        targetExportDefinitionFilters,
        targetExportVisibleFilters,
    };
}
/**
 * Extracts visible filters from automation metadata, handling both flat and per-tab structure.
 * When per-tab structure is present and activeTabLocalIdentifier is provided, extracts filters for that tab.
 */
function extractVisibleFiltersForTab(automation, activeTabLocalIdentifier) {
    if (!automation?.metadata) {
        return undefined;
    }
    const visibleFiltersByTab = automation.metadata.visibleFiltersByTab;
    // If per-tab visible filters exist and we have an active tab, use that tab's filters
    if (visibleFiltersByTab && activeTabLocalIdentifier) {
        return visibleFiltersByTab[activeTabLocalIdentifier];
    }
    // Fall back to flat visible filters
    return automation.metadata.visibleFilters;
}
function extractExportDefinitionFilters(content, activeTabLocalIdentifier) {
    if (isExportDefinitionDashboardRequestPayload(content)) {
        // Check if per-tab filters are provided and use the active tab's filters
        if (content.content.filtersByTab && activeTabLocalIdentifier) {
            const tabFilters = content.content.filtersByTab[activeTabLocalIdentifier];
            return tabFilters ? compact(tabFilters) : undefined;
        }
        // The filters in dashboard case may be undefined or an array depending
        // on whether they should override filter context or use live filter context.
        return content.content.filters ? compact(content.content.filters) : undefined;
    }
    if (isExportDefinitionVisualizationObjectRequestPayload(content)) {
        // There can either be execution filters or filter context items,
        // so we need to make sure we convert them to filter context items.
        return compact((content.content.filters ?? []).map((filter) => {
            if (isFilterContextItem(filter)) {
                return filter;
            }
            if (isDashboardFilter(filter)) {
                return dashboardFilterToFilterContextItem(filter, true);
            }
            return undefined;
        }));
    }
    return [];
}
/**
 * Sanitizes date filters by removing dataset information when needed.
 *
 * Automation filters may contain date filters with dataset information. However,
 * when applying these filters to the dashboard, the dataset needs to be removed
 * to properly match the dashboard's common date filter.
 *
 * This function removes the dataset from any date filter that matches the
 * dashboard's common date filter local identifier, or from filters that already
 * have no dataset (common date filters).
 *
 * @param filters - Filters to sanitize
 * @param commonDateFilterLocalId - Local identifier of the common date filter
 */
function sanitizeDateFilters(filters, commonDateFilterLocalId) {
    return filters.map((filter) => {
        if (isDashboardDateFilter(filter)) {
            // Primary match: by local identifier
            const matchesByLocalId = commonDateFilterLocalId && filter.dateFilter.localIdentifier === commonDateFilterLocalId;
            // Fallback: filters without datasets are common date filters
            const isCommonFilter = !filter.dateFilter.dataSet;
            if (matchesByLocalId || isCommonFilter) {
                // Remove dataset to ensure it's treated as common date filter
                return {
                    ...filter,
                    dateFilter: {
                        ...omit(filter.dateFilter, "dataSet"),
                    },
                };
            }
        }
        return filter;
    });
}
/**
 * Filter out insight and alert only filters from the list of filters
 *
 * @param filters - Filters to process
 * @param commonDateFilterLocalId - Local identifier of the common date filter
 * @param insight - Insight to check filters against
 * @param widget - Widget to check filters against
 *
 * @internal
 */
function getDashboardFiltersOnly(filters, commonDateFilterLocalId, insight, widget) {
    // Remove specific alert filters.
    const withoutAlertFilters = removeAlertFilters(filters);
    // Remove insight specific attribute filters from the list of filters.
    const withoutInsightAttributeFilters = removeInsightAttributeFilters(withoutAlertFilters, insight);
    // If widget has ignored date filter, remove date filter(s) - they originate from the insight, otherwise, it's the dashboard date filter, so keep it.
    const withoutInsightDateFilters = removeDateFiltersIfDateFilterIsIgnored(withoutInsightAttributeFilters, widget);
    // Find common date filter by local id or by absence of dataset
    const dateFilters = withoutInsightDateFilters.filter(isDateFilter);
    const foundCommonFilter = dateFilters.find((f) => {
        if (isRelativeDateFilter(f)) {
            const matchesByLocalId = commonDateFilterLocalId && f.relativeDateFilter.localIdentifier === commonDateFilterLocalId;
            const hasNoDataset = !f.relativeDateFilter.dataSet;
            return matchesByLocalId || hasNoDataset;
        }
        const matchesByLocalId = commonDateFilterLocalId && f.absoluteDateFilter.localIdentifier === commonDateFilterLocalId;
        const hasNoDataset = !f.absoluteDateFilter.dataSet;
        return matchesByLocalId || hasNoDataset;
    });
    // Remove dataSet from date filters, as it's not relevant for the dashboard date filter.
    return withoutInsightDateFilters.map((f) => {
        if (f === foundCommonFilter) {
            if (isRelativeDateFilter(f)) {
                return omit(f, "relativeDateFilter.dataSet");
            }
            else if (isAbsoluteDateFilter(f)) {
                return omit(f, "absoluteDateFilter.dataSet");
            }
        }
        return f;
    });
}
/**
 * Remove alert filters (these that are set during creation of the alert sliced by attribute) from the list of filters.
 * These filters can be recognized by the fact that they do not have filter objRef (they have localIdentifier only).
 * @internal
 */
function removeAlertFilters(filters) {
    return filters?.filter((f) => {
        const objRef = filterObjRef(f);
        return !!objRef;
    });
}
/**
 * Remove insight specific attribute filters from the list of filters
 * These filters can be recognized by matching them against insight filters and their local identifiers.
 */
function removeInsightAttributeFilters(filters, insight) {
    const insightAttributeFilters = insightFilters(insight).filter(isAttributeFilter);
    // Remove insight specific filters from the list of filters (by matching insight filter localIdentifier)
    return filters.filter((f) => {
        const insightFilter = insightAttributeFilters.find((f2) => {
            return filterLocalIdentifier(f) === filterLocalIdentifier(f2);
        });
        return !insightFilter;
    });
}
/**
 * Remove date filters if widget date filter is ignored.
 * If widget date filter is not ignored, date filter provided to the alert execution is the dashboard date filter.
 */
function removeDateFiltersIfDateFilterIsIgnored(filters, widget) {
    const isDateIgnored = !widget.dateDataSet;
    // If widget has ignored date filter, remove it
    return isDateIgnored ? filters.filter((f) => !isDateFilter(f)) : filters;
}
function isFilterContextItemCompatibleWithSelectionType(filter, selectionTypeMap, enableArbitraryFilterKD, enableMatchFilterKD, dashboardFilters) {
    if (!enableArbitraryFilterKD && !enableMatchFilterKD) {
        return true;
    }
    if (!isDashboardAttributeFilterItem(filter)) {
        return true;
    }
    const localIdentifier = dashboardFilterLocalIdentifier(filter);
    if (!localIdentifier) {
        return true;
    }
    const configuredSelectionType = selectionTypeMap?.get(localIdentifier);
    const filterType = isDashboardAttributeFilter(filter) ? "list" : "text";
    // Look up the corresponding filter in the dashboard's filter context to get its selection mode
    const dashboardFilter = dashboardFilters?.find((f) => dashboardFilterLocalIdentifier(f) === localIdentifier);
    const singleSelectionDefault = dashboardFilter &&
        isDashboardAttributeFilter(dashboardFilter) &&
        isSingleSelectionFilter(dashboardFilter)
        ? "list"
        : undefined;
    return isFilterTypeCompatibleWithSelectionType(filterType, configuredSelectionType, singleSelectionDefault);
}
function resolveSelectionTypeMapForActiveTab(selectionTypeMapByTab, selectionTypeMap, activeTabLocalIdentifier) {
    if (activeTabLocalIdentifier && selectionTypeMapByTab[activeTabLocalIdentifier]) {
        return selectionTypeMapByTab[activeTabLocalIdentifier];
    }
    return selectionTypeMap;
}
//# sourceMappingURL=initializeAutomationsHandler.js.map