// (C) 2021-2026 GoodData Corporation
import { isEmpty } from "lodash-es";
import { batchActions } from "redux-batched-actions";
import { all, call, put, select } from "redux-saga/effects";
import { invariant } from "ts-invariant";
import { DashboardAttributeFilterSelectionTypeValues, areObjRefsEqual, isInsightWidget, objRefToString, } from "@gooddata/sdk-model";
import { attributeFilterAdded } from "../../../events/filters.js";
import { invalidArgumentsProvided } from "../../../events/general.js";
import { dispatchDashboardEvent } from "../../../store/_infra/eventDispatcher.js";
import { selectBackendCapabilities } from "../../../store/backendCapabilities/backendCapabilitiesSelectors.js";
import { selectCrossFilteringFiltersLocalIdentifiers } from "../../../store/drill/drillSelectors.js";
import { selectAttributeFilterDisplayFormsMap, selectCanAddMoreFilters, selectFilterContextAttributeFilterByDisplayForm, selectFilterContextAttributeFilterByLocalId, selectFilterContextAttributeFilterItems, } from "../../../store/tabs/filterContext/filterContextSelectors.js";
import { tabsActions } from "../../../store/tabs/index.js";
import { selectAllAnalyticalWidgets } from "../../../store/tabs/layout/layoutSelectors.js";
import { resolveDisplayFormMetadata } from "../../../utils/displayFormResolver.js";
import { validateDrillToCustomUrlParams } from "../../common/validateDrillToCustomUrlParams.js";
import { dispatchFilterContextChanged } from "../common.js";
import { canFilterBeAdded } from "./validation/uniqueFiltersValidation.js";
export function* addAttributeFilterHandler(ctx, cmd, type = "normal") {
    const { displayForm, index, initialIsNegativeSelection, initialSelection, parentFilters, selectionMode, mode, localIdentifier, primaryDisplayForm, title, } = cmd.payload;
    const isUnderFilterCountLimit = yield select(selectCanAddMoreFilters);
    const usedDisplayForm = primaryDisplayForm || displayForm;
    const displayAsLabel = primaryDisplayForm && !areObjRefsEqual(primaryDisplayForm, displayForm) ? displayForm : undefined;
    if (!isUnderFilterCountLimit && type !== "crossfilter") {
        throw invalidArgumentsProvided(ctx, cmd, `Attempting to add filter, even though the limit on the count of filters has been reached.`);
    }
    const allFilters = yield select(selectFilterContextAttributeFilterItems);
    const resolvedDisplayForm = yield call(resolveDisplayFormMetadata, ctx, [usedDisplayForm]);
    if (!isEmpty(resolvedDisplayForm.missing)) {
        throw invalidArgumentsProvided(ctx, cmd, `Attempting to add filter for a non-existing display form ${objRefToString(usedDisplayForm)}.`);
    }
    const displayFormMetadata = resolvedDisplayForm.resolved.get(usedDisplayForm);
    invariant(displayFormMetadata);
    const attributeRef = displayFormMetadata.attribute;
    const canBeAdded = yield call(canFilterBeAdded, ctx, usedDisplayForm, allFilters);
    const crossFilteringFiltersLocalIdentifiers = yield select(selectCrossFilteringFiltersLocalIdentifiers);
    const isVirtualFilter = crossFilteringFiltersLocalIdentifiers.includes(localIdentifier);
    if (!isVirtualFilter && !canBeAdded) {
        throw invalidArgumentsProvided(ctx, cmd, `Filter for attribute ${objRefToString(attributeRef)} represented by the displayForm ${objRefToString(usedDisplayForm)} already exists in the filter context.`);
    }
    yield put(batchActions([
        tabsActions.addAttributeFilter({
            displayForm: displayFormMetadata.ref,
            index,
            initialIsNegativeSelection,
            initialSelection,
            parentFilters,
            selectionMode,
            localIdentifier,
            title,
        }),
        tabsActions.addAttributeFilterDisplayForm(displayFormMetadata),
    ]));
    const addedFilterByLocalId = yield select(selectFilterContextAttributeFilterByLocalId(localIdentifier));
    const addedFilterByDisplayForm = yield select(selectFilterContextAttributeFilterByDisplayForm(displayFormMetadata.ref));
    const addedFilter = addedFilterByLocalId ?? addedFilterByDisplayForm;
    invariant(addedFilter, "Inconsistent state in attributeFilterAddCommandHandler");
    const capabilities = yield select(selectBackendCapabilities);
    const attributeFilterConfigActions = [];
    if (capabilities.supportsHiddenAndLockedFiltersOnUI && mode) {
        attributeFilterConfigActions.push(tabsActions.changeAttributeFilterConfigMode({
            localIdentifier: addedFilter.attributeFilter.localIdentifier,
            mode,
        }));
    }
    // New filters default to listOrText available mode
    attributeFilterConfigActions.push(tabsActions.changeAttributeFilterSelectionType({
        localIdentifier: addedFilter.attributeFilter.localIdentifier,
        selectionType: DashboardAttributeFilterSelectionTypeValues.LIST_OR_TEXT,
    }));
    if (displayAsLabel) {
        attributeFilterConfigActions.push(tabsActions.changeDisplayAsLabel({
            localIdentifier: addedFilter.attributeFilter.localIdentifier,
            displayAsLabel,
        }));
    }
    if (attributeFilterConfigActions.length > 0) {
        yield put(batchActions(attributeFilterConfigActions));
    }
    yield dispatchDashboardEvent(attributeFilterAdded(ctx, addedFilter, cmd.payload.index, cmd.correlationId));
    yield call(dispatchFilterContextChanged, ctx, cmd);
    const widgets = yield select(selectAllAnalyticalWidgets);
    yield call(validateDrillToCustomUrlParams, widgets.filter(isInsightWidget));
}
export function* getConnectingAttributes(ctx, addedFilterAttribute, neighborFilter) {
    const { backend, workspace } = ctx;
    const displayFormsMap = yield select(selectAttributeFilterDisplayFormsMap);
    const neighborFilterAttribute = displayFormsMap.get(neighborFilter.attributeFilter.displayForm)?.attribute;
    invariant(neighborFilterAttribute, "Inconsistent state in attributeFilterAddCommandHandler");
    const connectingAttributeRefs = yield call(getCommonAttributesRefs, ctx.backend, ctx.workspace, addedFilterAttribute, neighborFilterAttribute);
    const connectingAttributesMeta = yield all(connectingAttributeRefs.map((ref) => call(getConnectingAttributeByRef, backend, workspace, ref)));
    const connectingAttributes = connectingAttributesMeta.map((meta) => {
        return {
            title: meta.title,
            ref: meta.ref,
        };
    });
    return {
        filterLocalId: neighborFilter.attributeFilter.localIdentifier,
        connectingAttributes: connectingAttributes,
    };
}
function getCommonAttributesRefs(backend, workspace, addedFilterAttribute, neighborFilterAttribute) {
    return backend
        .workspace(workspace)
        .attributes()
        .getCommonAttributes([addedFilterAttribute, neighborFilterAttribute]);
}
function getConnectingAttributeByRef(backend, workspace, ref) {
    return backend.workspace(workspace).attributes().getAttribute(ref);
}
//# sourceMappingURL=addAttributeFilterHandler.js.map