// (C) 2021-2026 GoodData Corporation
import { createSelector } from "@reduxjs/toolkit";
import { invariant } from "ts-invariant";
import { convertDateFilterConfigToDateFilterOptions } from "../../../../_staging/dateFilterConfig/dateFilterConfigConverters.js";
import { createMemoizedSelector } from "../../_infra/selectors.js";
import { selectIsInEditMode } from "../../renderMode/renderModeSelectors.js";
import { selectActiveTabLocalIdentifier, selectTabs } from "../tabsSelectors.js";
import { DEFAULT_TAB_ID } from "../tabsState.js";
const selectTabsArray = createSelector(selectTabs, (tabs) => [...(tabs ?? [])]);
/**
 * Returns date filter config overrides keyed by tab identifier.
 *
 * @internal
 */
export const selectDateFilterConfigOverridesByTab = createSelector(selectTabsArray, (tabs) => {
    if (!tabs.length) {
        return {};
    }
    return tabs.reduce((acc, tab) => {
        const identifier = tab.localIdentifier ?? DEFAULT_TAB_ID;
        acc[identifier] = tab.dateFilterConfig?.dateFilterConfig ?? undefined;
        return acc;
    }, {});
});
/**
 * Returns date filter config that is specified on the loaded dashboard.
 *
 * The dashboard-level date filter configuration MAY contain overrides and additional configuration to apply
 * on top of the workspace-level date filter config. If the dashboard-level overrides are not specified, then
 * the workspace-level config should be taken as-is.
 *
 * @remarks See {@link selectEffectiveDateFilterConfig} - you can use this selector to obtain the effective
 *  date filter config that contains the final config obtained by merging the workspace-level config and the
 *  dashboard-level overrides.
 *
 * @alpha
 */
export const selectDateFilterConfigOverrides = createSelector(selectDateFilterConfigOverridesByTab, selectActiveTabLocalIdentifier, (overridesByTab, activeTabId) => {
    if (!overridesByTab || Object.keys(overridesByTab).length === 0) {
        return undefined;
    }
    const resolvedActiveTabId = activeTabId ?? Object.keys(overridesByTab)[0];
    return overridesByTab[resolvedActiveTabId] ?? undefined;
});
/**
 * Returns effective date filter config. The effective date filter config is created by merging the workspace-level
 * date filter config and the dashboard-level date filter config.
 *
 * This is the configuration that the DateFilter SHOULD use when rendering filtering presets.
 *
 * @alpha
 */
export const selectEffectiveDateFilterConfig = createSelector(selectTabs, selectActiveTabLocalIdentifier, (tabs, activeTabId) => {
    const activeTab = tabs?.find((tab) => tab.localIdentifier === activeTabId);
    invariant(activeTab?.dateFilterConfig?.effectiveDateFilterConfig, "attempting to access uninitialized date filter config state");
    return activeTab.dateFilterConfig.effectiveDateFilterConfig;
});
/**
 * Returns effective date filter options. This is created by merging the workspace-level
 * date filter config and the dashboard-level date filter config.
 *
 * These are the date filter options that the DateFilter SHOULD use when rendering filtering presets.
 *
 * @alpha
 */
export const selectEffectiveDateFilterOptions = createSelector(selectEffectiveDateFilterConfig, (effectiveDateFilterConfig) => convertDateFilterConfigToDateFilterOptions(effectiveDateFilterConfig));
/**
 * Returns effective date filter options from. This is created by merging the workspace-level
 * date filter config and the dashboard-level date filter config.
 *
 * These are the date filter options that the DateFilter SHOULD use when rendering filtering presets.
 *
 * @alpha
 */
export const selectEffectiveDateFilterAvailableGranularities = createSelector(selectEffectiveDateFilterConfig, (effectiveDateFilterConfig) => effectiveDateFilterConfig.relativeForm?.availableGranularities ?? []);
/**
 * Indicates whether the effective date filter is using dashboard-level overrides.
 */
const effectiveDateFilterConfigIsUsingOverrides = createSelector(selectTabs, selectActiveTabLocalIdentifier, (tabs, activeTabId) => {
    const activeTab = tabs?.find((tab) => tab.localIdentifier === activeTabId);
    invariant(activeTab?.dateFilterConfig?.isUsingDashboardOverrides !== undefined, "attempting to access uninitialized date filter config state");
    return activeTab.dateFilterConfig.isUsingDashboardOverrides;
});
/**
 * Returns custom title to use for the date filter. Custom title comes from the dashboard-level date filter config overrides. If no overrides
 * were defined OR the effective date filter config is not using them (because applying them means the final date filter config is invalid),
 * then no custom filter should be used.
 *
 * @alpha
 */
export const selectEffectiveDateFilterTitle = createSelector(effectiveDateFilterConfigIsUsingOverrides, selectDateFilterConfigOverrides, (isUsingOverrides, dashboardOverrides) => {
    if (!isUsingOverrides) {
        return undefined;
    }
    // If this happens then the load command handler does not work correctly - it sets that the overrides are used
    // while there are none.
    invariant(dashboardOverrides !== undefined);
    return dashboardOverrides.filterName;
});
/**
 * Returns display mode for the effective date filter. This always comes from the dashboard-level date filter config overrides - regardless whether
 * the rest of the overrides are actually used.
 *
 * @alpha
 */
export const selectEffectiveDateFilterMode = createSelector(selectIsInEditMode, selectDateFilterConfigOverrides, (isInEditMode, dashboardOverrides) => {
    if (isInEditMode) {
        return "active";
    }
    return dashboardOverrides?.mode ?? "active";
});
/**
 * Returns the date filter config validation result warnings indicating any problems encountered during the date filter config resolution.
 *
 * @alpha
 */
export const selectDateFilterConfigValidationWarnings = createSelector(selectTabs, selectActiveTabLocalIdentifier, (tabs, activeTabId) => {
    const activeTab = tabs?.find((tab) => tab.localIdentifier === activeTabId);
    return activeTab?.dateFilterConfig?.dateFilterConfigValidationWarnings ?? [];
});
/**
 * Returns effective date filter config for a specific tab.
 *
 * @param tabLocalIdentifier - Tab local identifier
 * @returns Effective date filter config for the specified tab
 *
 * @internal
 */
export const selectEffectiveDateFilterConfigForTab = createMemoizedSelector((tabLocalIdentifier) => createSelector(selectTabs, (tabs) => {
    const tab = tabs?.find((t) => t.localIdentifier === tabLocalIdentifier);
    return tab?.dateFilterConfig?.effectiveDateFilterConfig;
}));
/**
 * Returns effective date filter options for a specific tab.
 *
 * @param tabLocalIdentifier - Tab local identifier
 * @returns Date filter options for the specified tab
 *
 * @internal
 */
export const selectEffectiveDateFilterOptionsForTab = createMemoizedSelector((tabLocalIdentifier) => createSelector(selectEffectiveDateFilterConfigForTab(tabLocalIdentifier), (effectiveDateFilterConfig) => effectiveDateFilterConfig
    ? convertDateFilterConfigToDateFilterOptions(effectiveDateFilterConfig)
    : undefined));
/**
 * Returns effective date filter available granularities for a specific tab.
 *
 * @param tabLocalIdentifier - Tab local identifier
 * @returns Available granularities for the specified tab
 *
 * @internal
 */
export const selectEffectiveDateFilterAvailableGranularitiesForTab = createMemoizedSelector((tabLocalIdentifier) => createSelector(selectEffectiveDateFilterConfigForTab(tabLocalIdentifier), (effectiveDateFilterConfig) => effectiveDateFilterConfig?.relativeForm?.availableGranularities ?? []));
/**
 * Returns effective date filter available granularities for all tabs as a map.
 * Key is the tab local identifier; value is the array of available granularities.
 *
 * @internal
 */
export const selectEffectiveDateFilterGranularitiesPerTab = createSelector(selectTabs, (tabs) => {
    if (!tabs?.length) {
        return {};
    }
    return tabs.reduce((acc, tab) => {
        const identifier = tab.localIdentifier ?? DEFAULT_TAB_ID;
        acc[identifier] =
            tab.dateFilterConfig?.effectiveDateFilterConfig?.relativeForm?.availableGranularities ?? [];
        return acc;
    }, {});
});
/**
 * Returns effective date filter options for all tabs as a map.
 * Key is the tab local identifier; value is the date filter options (undefined when no config exists for that tab).
 *
 * @internal
 */
export const selectEffectiveDateFilterOptionsPerTab = createSelector(selectTabs, (tabs) => {
    if (!tabs?.length) {
        return {};
    }
    return tabs.reduce((acc, tab) => {
        const identifier = tab.localIdentifier ?? DEFAULT_TAB_ID;
        acc[identifier] = tab.dateFilterConfig?.effectiveDateFilterConfig
            ? convertDateFilterConfigToDateFilterOptions(tab.dateFilterConfig.effectiveDateFilterConfig)
            : undefined;
        return acc;
    }, {});
});
