// (C) 2021-2026 GoodData Corporation
import { createSelector } from "@reduxjs/toolkit";
import { union } from "lodash-es";
import { areObjRefsEqual, objRefToString } from "@gooddata/sdk-model";
import { ObjRefMap } from "../../../_staging/metadata/objRefMap.js";
import { createMemoizedSelector } from "../_infra/selectors.js";
import { selectConfig, selectEnableDashboardDensitySetting } from "../config/configSelectors.js";
import { selectIsInEditMode } from "../renderMode/renderModeSelectors.js";
import { selectWidgetsMap } from "../tabs/layout/layoutSelectors.js";
const selectSelf = createSelector((state) => state, (state) => state.ui);
/**
 * @alpha
 */
export const selectIsScheduleEmailDialogOpen = createSelector(selectSelf, (state) => state.scheduleEmailDialog.open);
/**
 * @alpha
 */
export const selectIsScheduleEmailDialogContext = createSelector(selectSelf, (state) => state.scheduleEmailDialog.context ?? {});
/**
 * @alpha
 */
export const selectScheduleEmailDialogDefaultAttachment = createSelector(selectSelf, (state) => state.scheduleEmailDialog.defaultAttachmentRef ?? undefined);
/**
 * @internal
 */
export const selectScheduleEmailDialogReturnFocusTo = createSelector(selectSelf, (state) => state.scheduleEmailDialog.returnFocusTo ?? undefined);
/**
 * @alpha
 */
export const selectIsScheduleEmailManagementDialogOpen = createSelector(selectSelf, (state) => state.scheduleEmailManagementDialog.open);
/**
 * @alpha
 */
export const selectIsScheduleEmailManagementDialogContext = createSelector(selectSelf, (state) => state.scheduleEmailManagementDialog.context ?? {});
/**
 * @alpha
 */
export const selectIsAlertingManagementDialogContext = createSelector(selectSelf, (state) => state.alertsManagementDialog.context ?? {});
/**
 * @alpha
 */
export const selectIsAlertingDialogOpen = createSelector(selectSelf, (state) => {
    return state.alertsDialog.open;
});
/**
 * @alpha
 */
export const selectAlertingDialogContext = createSelector(selectSelf, (state) => state.alertsDialog.context ?? {});
/**
 * @internal
 */
export const selectAlertingDialogReturnFocusTo = createSelector(selectSelf, (state) => state.alertsDialog.returnFocusTo ?? undefined);
/**
 * @alpha
 */
export const selectIsAlertsManagementDialogOpen = createSelector(selectSelf, (state) => state.alertsManagementDialog.open);
/**
 * @alpha
 */
export const selectIsSaveAsDialogOpen = createSelector(selectSelf, (state) => state.saveAsDialog.open);
/**
 * @alpha
 */
export const selectIsShareDialogOpen = createSelector(selectSelf, (state) => state.shareDialog.open);
/**
 * @alpha
 */
export const selectIsSettingsDialogOpen = createSelector(selectSelf, (state) => state.settingsDialog.open);
/**
 * @alpha
 */
export const selectIsDensityDialogOpen = createSelector(selectSelf, (state) => state.densityDialog.open);
/**
 * Returns the current dashboard density setting.
 *
 * @remarks
 * The value reflects either the theme-enforced density or the user's local preference.
 * Defaults to "comfortable".
 *
 * @alpha
 */
export const selectDashboardDensity = createSelector(selectSelf, selectEnableDashboardDensitySetting, selectIsInEditMode, (state, isEnabled, isInEditMode) => (isEnabled && !isInEditMode ? state.density : "comfortable"));
/**
 * @internal
 */
export const selectIsDeleteDialogOpen = createSelector(selectSelf, (state) => state.deleteDialog.open);
/**
 * @internal
 */
export const selectIsWidgetDeleteDialogOpen = createSelector(selectSelf, (state) => state.widgetDeleteDialog.open);
/**
 * @internal
 */
export const selectWidgetDeleteDialogWidgetRef = createSelector(selectSelf, (state) => state.widgetDeleteDialog.widgetRef);
/**
 * @internal
 */
export const selectIsKpiDeleteDialogOpen = createSelector(selectSelf, (state) => !!state.kpiDeleteDialog.widgetCoordinates);
/**
 * @internal
 */
export const selectIsCancelEditModeDialogOpen = createSelector(selectSelf, (state) => !!state.cancelEditModeDialog.open);
/**
 * @internal
 */
export const selectKpiDeleteDialogWidgetLayoutPath = createSelector(selectSelf, (state) => state.kpiDeleteDialog.widgetCoordinates);
/**
 * @internal
 *
 * @deprecated The selector returns coordinates in its parent layout. The information is not useful on its
 *  own when dashboard uses nested layout. For this case use {@link selectKpiDeleteDialogWidgetLayoutPath} instead.
 *
 *  TODO LX-648: remove this selector, exported only for backward compatible reasons.
 */
export const selectKpiDeleteDialogWidgetCoordinates = createSelector(selectSelf, (state) => {
    const coordinates = state.kpiDeleteDialog.widgetCoordinates;
    return coordinates === undefined ? undefined : coordinates[coordinates.length - 1];
});
/**
 * @alpha
 */
export const selectFilterBarExpanded = createSelector(selectSelf, (state) => state.filterBar.expanded);
const selectHighlightedKpiWidgetRef = createSelector(selectSelf, (state) => state.kpiAlerts.highlightedWidgetRef);
const selectOpenedKpiWidgetRef = createSelector(selectSelf, (state) => state.kpiAlerts.openedWidgetRef ?? undefined);
/**
 * @alpha
 */
export const selectIsKpiAlertOpenedByWidgetRef = createMemoizedSelector((ref) => {
    return createSelector(selectWidgetsMap, selectOpenedKpiWidgetRef, (widgets, openedWidgetRef) => {
        if (!ref) {
            return false;
        }
        const openedWidget = openedWidgetRef && widgets.get(openedWidgetRef);
        if (!openedWidget) {
            return false;
        }
        const targetWidget = widgets.get(ref);
        if (!targetWidget) {
            return false;
        }
        return targetWidget.identifier === openedWidget.identifier;
    });
});
/**
 * @alpha
 */
export const selectIsKpiAlertHighlightedByWidgetRef = createMemoizedSelector((ref) => {
    return createSelector(selectWidgetsMap, selectHighlightedKpiWidgetRef, (widgets, highlightedWidgetRef) => {
        if (!ref) {
            return false;
        }
        const highlightedWidget = highlightedWidgetRef && widgets.get(highlightedWidgetRef);
        if (!highlightedWidget) {
            return false;
        }
        const targetWidget = widgets.get(ref);
        if (!targetWidget) {
            return false;
        }
        return targetWidget.identifier === highlightedWidget.identifier;
    });
});
/**
 * @alpha
 */
export const selectMenuButtonItemsVisibility = createSelector(selectSelf, (state) => state.menuButton.itemsVisibility ?? {});
/**
 * @internal
 *
 * This selector provides selected widget on dashboard. It DOES NOT provide selected widget inside of selected visualization switcher.
 */
export const selectSelectedWidgetRef = createSelector(selectSelf, (state) => state.selectedWidgetRef);
/**
 * @internal
 */
export const selectConfigurationPanelOpened = createSelector(selectSelf, (state) => state.configurationPanelOpened);
/**
 * @internal
 */
export const selectWidgetDateDatasetAutoSelect = createSelector(selectSelf, (state) => state.widgetDateDatasetAutoSelect);
/**
 * @internal
 */
export const selectInsightListLastUpdateRequested = createSelector(selectSelf, (state) => state.insightListLastUpdateRequested);
const selectWidgetsLoadingAdditionalData = createSelector(selectSelf, (state) => state.widgetsLoadingAdditionalData);
/**
 * @internal
 */
export const selectIsWidgetLoadingAdditionalDataByWidgetRef = createMemoizedSelector((ref) => createSelector(selectWidgetsLoadingAdditionalData, (widgetsLoading) => {
    return widgetsLoading.some((loadingRef) => areObjRefsEqual(loadingRef, ref));
}));
/**
 * @alpha
 */
export const selectIsFilterAttributeSelectionOpen = createSelector(selectSelf, (state) => state.filterAttributeSelectionOpen);
/**
 * @alpha
 */
export const selectSelectedFilterIndex = createSelector(selectSelf, (state) => state.selectedFilterIndex);
/**
 * @internal
 */
export const selectIsDraggingWidget = createSelector(selectSelf, (state) => state.draggingWidgetSource !== undefined);
/**
 * The selector returns index of active section.
 *
 * @internal
 * @deprecated The selector returns index in its parent section layout. The information is not useful on its
 *  own when dashboard uses nested layout. For this case use {@link selectActiveSection} instead.
 *
 *  TODO LX-648: remove this selector, exported only for backward compatible reasons.
 */
export const selectActiveSectionIndex = createSelector(selectSelf, (state) => state.activeSection?.sectionIndex);
/**
 * The selector returns layout path of active section.
 *
 * @internal
 */
export const selectActiveSection = createSelector(selectSelf, (state) => state.activeSection);
/**
 * @internal
 */
export const selectInvalidDrillWidgetRefs = createSelector(selectSelf, (state) => state.drillValidationMessages.invalidDrillWidgetRefs);
/**
 * @internal
 */
export const selectSanitizedDrillWidgetRefs = createSelector(selectSelf, (state) => state.drillValidationMessages.sanitizedDrillWidgetRefs);
const selectInvalidCustomUrlDrillParameterWidgets = createSelector(selectSelf, (state) => state.drillValidationMessages.invalidCustomUrlDrillParameterWidgets);
/**
 * @internal
 */
export const selectInvalidUrlDrillParameterWidgetRefs = createSelector(selectInvalidCustomUrlDrillParameterWidgets, (invalidCustomUrlDrillParameterWidgets) => invalidCustomUrlDrillParameterWidgets.map((i) => i.widgetRef));
/**
 * @internal
 */
export const selectInvalidUrlDrillParameterWidgetWarnings = createSelector(selectInvalidCustomUrlDrillParameterWidgets, (invalidCustomUrlDrillParameterWidgets) => invalidCustomUrlDrillParameterWidgets.filter((item) => item.showMessage).map((i) => i.widgetRef));
const selectInvalidUrlDrillParameterWidgetsMap = createSelector(selectInvalidCustomUrlDrillParameterWidgets, (invalidCustomUrlDrillParameterWidgets) => new ObjRefMap({
    idExtract: (i) => i.widgetId,
    refExtract: (i) => i.widgetRef,
    uriExtract: (i) => i.widgetUri,
    strictTypeCheck: false,
}).fromItems(invalidCustomUrlDrillParameterWidgets));
/**
 * @internal
 */
export const selectInvalidUrlDrillParameterDrillLocalIdsByWidgetRef = createMemoizedSelector((ref) => createSelector(selectInvalidUrlDrillParameterWidgetsMap, (invalidParameterWidgetsMap) => invalidParameterWidgetsMap.get(ref)?.drillsWithInvalidParametersLocalIds ?? []));
/**
 * @internal
 */
export const selectDraggingWidgetSource = createSelector(selectSelf, (state) => state.draggingWidgetSource);
/**
 * @internal
 */
export const selectDraggingWidgetTargetLayoutPath = createSelector(selectSelf, (state) => state.draggingWidgetTarget);
/**
 * @internal
 */
export const selectDraggingWidgetTriggeringDropZoneType = createSelector(selectSelf, (state) => state.draggingWidgetTriggeringDropZoneType);
/**
 * @internal
 *
 * @deprecated The selector returns coordinates in its parent section layout. The information is not useful on its
 *  own when dashboard uses nested layout. For this case use {@link selectDraggingWidgetTargetLayoutPath} instead.
 *
 *  TODO LX-648: remove this selector, exported only for backward compatible reasons.
 */
export const selectDraggingWidgetTarget = createSelector(selectSelf, (state) => state.draggingWidgetTarget === undefined
    ? undefined
    : state.draggingWidgetTarget[state.draggingWidgetTarget.length - 1]);
/**
 * @internal
 */
export const selectWidgetsOverlay = createSelector(selectSelf, (state) => state.widgetsOverlay);
/**
 * @internal
 */
export const selectWidgetsOverlayState = createMemoizedSelector((refs) => createSelector(selectWidgetsOverlay, (overlay) => {
    return refs.every((ref) => {
        return (ref && overlay[objRefToString(ref)]?.showOverlay) ?? false;
    });
}));
/**
 * @internal
 */
export const selectWidgetsModification = createMemoizedSelector((refs) => createSelector(selectWidgetsOverlay, (overlay) => {
    return refs.reduce((modification, ref) => {
        const item = ref && overlay[objRefToString(ref)];
        if (item?.modification) {
            return union(modification, [item.modification]);
        }
        return modification;
    }, []);
}));
/**
 * @internal
 */
export const selectSectionModification = createMemoizedSelector((refs) => createSelector(selectWidgetsOverlay, (overlay) => {
    if (refs.length === 0) {
        return [];
    }
    const modifications = refs.map((ref) => {
        const item = ref && overlay[objRefToString(ref)];
        return item?.modification;
    });
    const inserted = modifications.filter((a) => a === "insertedByPlugin");
    const modified = modifications.filter((a) => a === "modifiedByPlugin");
    return [
        ...(inserted.length === refs.length ? ["insertedByPlugin"] : []),
        ...(modified.length === refs.length ? ["modifiedByPlugin"] : []),
    ];
}));
/**
 * @internal
 */
export const selectIsSectionInsertedByPlugin = createMemoizedSelector((refs) => createSelector(selectSectionModification(refs), 
// When all the widgets in the section were inserted by the plugin,
// the section was added by the plugin as well (empty section(s) cannot be added)
(modifications) => modifications.length > 0 && modifications.every((m) => m === "insertedByPlugin")));
/**
 * @internal
 */
export const selectIsFilterViewsDialogOpen = createSelector(selectSelf, (state) => state.filterViews.open ?? false);
/**
 * @internal
 */
export const selectFilterViewsDialogMode = createSelector(selectSelf, (state) => state.filterViews.mode ?? "list");
/**
 * @internal
 */
export const selectIgnoreExecutionTimestamp = createSelector(selectSelf, (state) => state.ignoreExecutionTimestamp ?? false);
/**
 * @internal
 */
export const selectExecutionTimestamp = createSelector([selectConfig, selectIgnoreExecutionTimestamp], (config, ignoreExecutionTimestamp) => {
    if (ignoreExecutionTimestamp) {
        return undefined;
    }
    return config.executionTimestamp ?? undefined;
});
/**
 * @internal
 */
export const selectFilterValidationIncompatibleDefaultFiltersOverride = createSelector(selectSelf, (state) => state.filterValidationMessages.incompatibleDefaultFiltersOverride);
/**
 * Returns the invalidation ID for automations management.
 * When this value changes (and is not 0 or undefined), the Automations component should reload its data.
 *
 * @alpha
 */
export const selectAutomationsInvalidationId = createSelector(selectSelf, (state) => state.automationsManagement.invalidationId);
