import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
// (C) 2020-2026 GoodData Corporation
import { useCallback, useMemo, useState } from "react";
import { HighlightStyle, StreamLanguage, syntaxHighlighting } from "@codemirror/language";
import { Tag } from "@lezer/highlight";
import { compact, uniqBy } from "lodash-es";
import { FormattedMessage, useIntl } from "react-intl";
import { filterObjRef, idRef, insightFilters as insightDefinitionFilters, isArbitraryAttributeFilter, isAttributeFilter, isMatchAttributeFilter, isMeasureValueFilter, isNegativeAttributeFilter, isPositiveAttributeFilter, isUriRef, objRefToString, serializeObjRef, } from "@gooddata/sdk-model";
import { ConfirmDialogBase, FullScreenOverlay, Overlay, OverlayController, OverlayControllerProvider, SyntaxHighlightingInput, useMediaQuery, } from "@gooddata/sdk-ui-kit";
import { dashboardAttributeFilterItemToAttributeFilter } from "../../../../converters/filterConverters.js";
import { useDashboardSelector } from "../../../../model/react/DashboardStoreProvider.js";
import { selectAllCatalogDisplayFormsMap, selectAllCatalogMeasuresMap, } from "../../../../model/store/catalog/catalogSelectors.js";
import { selectEnableMeasureValueFilterKD, selectIsWhiteLabeled, } from "../../../../model/store/config/configSelectors.js";
import { selectInsightByWidgetRef } from "../../../../model/store/insights/insightsSelectors.js";
import { selectAttributeFilterConfigsOverrides } from "../../../../model/store/tabs/attributeFilterConfigs/attributeFilterConfigsSelectors.js";
import { selectFilterContextAttributeFilterItems, selectFilterContextMeasureValueFilters, } from "../../../../model/store/tabs/filterContext/filterContextSelectors.js";
import { DASHBOARD_HEADER_OVERLAYS_Z_INDEX } from "../../../constants/zIndex.js";
import { useInvalidFilteringParametersIdentifiers } from "../../../widget/insight/configuration/DrillTargets/useInvalidFilteringParametersIdentifiers.js";
import { isDrillToCustomUrlConfig } from "../../types.js";
import { ParametersPanel } from "./CustomUrlEditorParameters.js";
// Define custom tags for tokenization
const customTags = {
    attribute: Tag.define("attribute"),
    invalidAttribute: Tag.define("invalidAttribute"),
    identifier: Tag.define("identifier"),
    invalidIdentifier: Tag.define("invalidIdentifier"),
    filter: Tag.define("filter"),
    invalidFilter: Tag.define("invalidFilter"),
};
// Map tags to class names for styling
const customHighlightStyle = HighlightStyle.define([
    { tag: customTags.identifier, class: "cm-identifier" },
    { tag: [customTags.attribute, customTags.filter], class: "cm-attribute" },
    {
        tag: [customTags.invalidAttribute, customTags.invalidFilter, customTags.invalidIdentifier],
        class: "cm-invalid",
    },
]);
const createUrlLanguage = (rules) => {
    return StreamLanguage.define({
        name: "customUrl",
        token: (stream) => {
            for (const rule of rules) {
                if (stream.match(rule.regex)) {
                    return rule.token;
                }
            }
            stream.next();
            return null;
        },
        tokenTable: customTags,
    });
};
export function UrlInput({ onChange, onCursor, currentUrlValue, intl, syntaxHighlightingRules, }) {
    const placeholder = intl.formatMessage({
        id: "configurationPanel.drillIntoUrl.editor.textAreaPlaceholder",
    });
    const extensions = useMemo(() => {
        if (!syntaxHighlightingRules)
            return [];
        return [createUrlLanguage(syntaxHighlightingRules), syntaxHighlighting(customHighlightStyle)];
    }, [syntaxHighlightingRules]);
    return syntaxHighlightingRules ? (_jsx(SyntaxHighlightingInput, { onChange: onChange, onCursor: onCursor, value: currentUrlValue, placeholder: placeholder, className: "gd-input-syntax-highlighting-input", extensions: extensions })) : null;
}
function HelpLink({ link }) {
    return (_jsxs("a", { className: "gd-button-link gd-drill-to-custom-url-help", target: "_blank", href: link, rel: "noopener noreferrer", children: [
            _jsx("span", { className: "gd-icon-circle-question" }), _jsx("span", { className: "gd-button-link-text", children: _jsx(FormattedMessage, { id: "configurationPanel.drillIntoUrl.editor.helpButtonLabel" }) })
        ] }));
}
const buildValidDisplayFormsFormattingRule = (attributeDisplayForms) => {
    if (attributeDisplayForms.length === 0) {
        return undefined;
    }
    const validAttributePlaceholders = attributeDisplayForms
        .map(({ displayForm }) => `{attribute_title\\(${displayForm.id}\\)}`)
        .join("|");
    return { regex: new RegExp(`^${validAttributePlaceholders}`), token: customTags.attribute.toString() };
};
const buildValidInsightFiltersFormattingRule = (attributeFilters) => {
    if (attributeFilters.length === 0) {
        return undefined;
    }
    const validInsightAttributeFilterPlaceholders = attributeFilters
        .map((filter) => {
        const ref = filterObjRef(filter);
        const id = isUriRef(ref) ? ref.uri : ref.identifier;
        return `{attribute_filter_selection\\(${id}\\)}`;
    })
        .join("|");
    return {
        regex: new RegExp(`^${validInsightAttributeFilterPlaceholders}`),
        token: customTags.filter.toString(),
    };
};
const buildValidDashboardFiltersFormattingRule = (attributeFilters, attributeFilterConfigs = []) => {
    if (attributeFilters.length === 0) {
        return undefined;
    }
    const filterPlaceholders = attributeFilters.map((filter) => {
        const ref = filterObjRef(filter);
        const id = objRefToString(ref);
        return `{dash_attribute_filter_selection\\(${id}\\)}`;
    });
    const configPlaceholders = attributeFilterConfigs
        .filter((config) => !!config.displayAsLabel)
        .map((config) => {
        const id = !!config.displayAsLabel && objRefToString(config.displayAsLabel);
        return `{dash_attribute_filter_selection\\(${id}\\)}`;
    });
    const validDashboardAttributeFilterPlaceholders = [...filterPlaceholders, ...configPlaceholders].join("|");
    return {
        regex: new RegExp(`^${validDashboardAttributeFilterPlaceholders}`),
        token: customTags.filter.toString(),
    };
};
const buildValidDashboardMvfFormattingRule = (measureIdentifiers) => {
    if (measureIdentifiers.length === 0) {
        return undefined;
    }
    const validDashboardMvfPlaceholders = measureIdentifiers
        .map((id) => `{dash_mvf_condition\\(${id}\\)}`)
        .join("|");
    return {
        regex: new RegExp(`^${validDashboardMvfPlaceholders}`),
        token: customTags.filter.toString(),
    };
};
const buildValidInsightMvfFormattingRule = (measureIdentifiers) => {
    if (measureIdentifiers.length === 0) {
        return undefined;
    }
    const validInsightMvfPlaceholders = measureIdentifiers
        .map((id) => `{mvf_condition\\(${id}\\)}`)
        .join("|");
    return {
        regex: new RegExp(`^${validInsightMvfPlaceholders}`),
        token: customTags.filter.toString(),
    };
};
const IDENTIFIER_RULE = {
    regex: /^\{workspace_id\}|\{project_id\}|\{visualization_id\}|\{widget_id\}|\{dashboard_id\}|\{client_id\}|\{data_product_id\}/,
    token: customTags.identifier.toString(),
};
const INVALID_IDENTIFIER_RULE = { regex: /^\{[^}{]*\}/, token: "invalid" };
const INVALID_DISPLAY_FORMS_RULE = {
    regex: /^\{attribute_title\(.*?\)\}/,
    token: customTags.invalidAttribute.toString(),
};
const INVALID_DASHBOARD_ATTRIBUTE_FILTER_RULE = {
    regex: /^\{dash_attribute_filter_selection\(.*?\)\}/,
    token: customTags.invalidFilter.toString(),
};
const INVALID_DASHBOARD_MVF_RULE = {
    regex: /^\{dash_mvf_condition\(.*?\)\}/,
    token: customTags.invalidFilter.toString(),
};
const INVALID_INSIGHT_MVF_RULE = {
    regex: /^\{mvf_condition\(.*?\)\}/,
    token: customTags.invalidFilter.toString(),
};
const INVALID_INSIGHT_ATTRIBUTE_FILTER_RULE = {
    regex: /^\{attribute_filter_selection\(.*?\)\}/,
    token: customTags.invalidFilter.toString(),
};
const DEFAULT_RULES = [
    INVALID_DISPLAY_FORMS_RULE,
    INVALID_DASHBOARD_ATTRIBUTE_FILTER_RULE,
    INVALID_DASHBOARD_MVF_RULE,
    INVALID_INSIGHT_MVF_RULE,
    INVALID_INSIGHT_ATTRIBUTE_FILTER_RULE,
    IDENTIFIER_RULE,
    INVALID_IDENTIFIER_RULE,
];
const buildFormattingRules = (attributeDisplayForms, dashboardFilters, insightFilters, dashboardMeasureIdentifiers, insightMeasureIdentifiers, attributeFilterConfigs) => {
    const validDisplayFormsRule = buildValidDisplayFormsFormattingRule(attributeDisplayForms);
    const validInsightFiltersRule = buildValidInsightFiltersFormattingRule(insightFilters);
    const validDashboardFiltersRule = buildValidDashboardFiltersFormattingRule(dashboardFilters, attributeFilterConfigs);
    const validDashboardMvfRule = buildValidDashboardMvfFormattingRule(dashboardMeasureIdentifiers);
    const validInsightMvfRule = buildValidInsightMvfFormattingRule(insightMeasureIdentifiers);
    return compact([
        validDisplayFormsRule,
        validDashboardFiltersRule,
        validDashboardMvfRule,
        validInsightFiltersRule,
        validInsightMvfRule,
        ...DEFAULT_RULES,
    ]);
};
function UrlInputPanel({ currentUrlValue, onChange, onCursor, documentationLink, attributeDisplayForms, intl, insightFilters, dashboardFilters, dashboardMeasureValueFilters, insightMeasureValueFilters, enableInsightMeasureValueFilters, attributeFilterConfigs, }) {
    const isWhiteLabeled = useDashboardSelector(selectIsWhiteLabeled);
    const catalogMeasuresMap = useDashboardSelector(selectAllCatalogMeasuresMap);
    const dashboardMeasureIdentifiers = useMemo(() => {
        return (dashboardMeasureValueFilters ?? []).map((filter) => {
            const measureRef = filter.dashboardMeasureValueFilter.measure;
            return catalogMeasuresMap.get(measureRef)?.measure.id ?? objRefToString(measureRef);
        });
    }, [catalogMeasuresMap, dashboardMeasureValueFilters]);
    const insightMeasureIdentifiers = useMemo(() => enableInsightMeasureValueFilters
        ? (insightMeasureValueFilters ?? []).map((filter) => {
            const measureRef = filter.measureValueFilter.measure;
            return objRefToString(measureRef);
        })
        : [], [enableInsightMeasureValueFilters, insightMeasureValueFilters]);
    const syntaxHighlightingRules = useMemo(() => attributeDisplayForms &&
        insightFilters &&
        dashboardFilters &&
        dashboardMeasureValueFilters &&
        buildFormattingRules(attributeDisplayForms, dashboardFilters, insightFilters, dashboardMeasureIdentifiers, insightMeasureIdentifiers, attributeFilterConfigs), [
        attributeDisplayForms,
        insightFilters,
        dashboardFilters,
        dashboardMeasureValueFilters,
        dashboardMeasureIdentifiers,
        insightMeasureIdentifiers,
        attributeFilterConfigs,
    ]);
    return (_jsxs("div", { children: [
            _jsx("label", { className: "gd-label", children: _jsx(FormattedMessage, { id: "configurationPanel.drillIntoUrl.editor.textAreaLabel" }) }), _jsx(UrlInput, { onChange: onChange, onCursor: onCursor, currentUrlValue: currentUrlValue, syntaxHighlightingRules: syntaxHighlightingRules, intl: intl }), !isWhiteLabeled && documentationLink ? _jsx(HelpLink, { link: documentationLink }) : null] }));
}
const initialCursorPosition = {
    from: 0,
    to: 0,
};
const insertPlaceholderAtCursor = (text, placeholder, cursor) => `${text.substring(0, cursor.from)}${placeholder}${text.substring(cursor.to)}`;
const URL_START_RULES = [
    /^[A-Za-z0-9.\-+]+:/,
    /^\{attribute_title\(/,
    /^\{attribute_filter_selection\(/,
    /^\{dash_attribute_filter_selection\(/,
    /^\{dash_mvf_condition\(/,
];
const INSIGHT_MVF_URL_START_RULE = /^\{mvf_condition\(/;
const assertValidUrl = (url, enableInsightMeasureValueFilters) => {
    const rules = enableInsightMeasureValueFilters
        ? [...URL_START_RULES, INSIGHT_MVF_URL_START_RULE]
        : URL_START_RULES;
    return rules.some((rule) => rule.test(url)) ? url : `https://${url}`;
};
const getWarningTextForInvalidParameters = (parameters) => {
    const invalidParameters = parameters.map((parameter) => `"${parameter}"`).join(", ");
    return (_jsx(FormattedMessage, { id: "configurationPanel.drillIntoUrl.editor.invalidAttributeDisplayForms", values: { invalidParameters } }));
};
function CustomUrlEditorDialog({ urlDrillTarget, documentationLink, onSelect, onClose, attributeDisplayForms, loadingAttributeDisplayForms = false, invalidAttributeDisplayFormIdentifiers, enableClientIdParameter, enableDataProductIdParameter, enableWidgetIdParameter, widgetRef, }) {
    const intl = useIntl();
    const enableInsightMeasureValueFilters = useDashboardSelector(selectEnableMeasureValueFilterKD);
    const insightFilters = useSanitizedInsightFilters(widgetRef);
    const insightMeasureValueFilters = useInsightMeasureValueFilters(widgetRef, enableInsightMeasureValueFilters);
    const dashboardFilters = useSanitizedDashboardFilters();
    const dashboardMeasureValueFilters = useDashboardSelector(selectFilterContextMeasureValueFilters);
    const attributeFilterConfigs = useDashboardSelector(selectAttributeFilterConfigsOverrides);
    const invalidFilteringParametersIdentifiers = useInvalidFilteringParametersIdentifiers(urlDrillTarget, insightFilters, dashboardFilters, dashboardMeasureValueFilters, enableInsightMeasureValueFilters ? insightMeasureValueFilters : undefined, enableInsightMeasureValueFilters, attributeFilterConfigs);
    const invalidParameters = useMemo(() => {
        return [...invalidAttributeDisplayFormIdentifiers, ...invalidFilteringParametersIdentifiers];
    }, [invalidAttributeDisplayFormIdentifiers, invalidFilteringParametersIdentifiers]);
    const previousValue = urlDrillTarget
        ? (isDrillToCustomUrlConfig(urlDrillTarget) && urlDrillTarget.customUrl) || ""
        : "";
    const [currentValue, setCurrentValue] = useState(previousValue);
    const apply = () => onSelect(assertValidUrl(currentValue, enableInsightMeasureValueFilters));
    const handleOnChange = (value) => setCurrentValue(value);
    const isApplyEnabled = currentValue && currentValue.localeCompare(previousValue) !== 0;
    const [cursorPosition, setCursorPosition] = useState(initialCursorPosition);
    const handleCursorPosition = (from, to) => setCursorPosition({ from, to });
    const handleOnAdd = (parameterPlaceholder) => setCurrentValue(insertPlaceholderAtCursor(currentValue, parameterPlaceholder, cursorPosition));
    const editorWarningText = invalidParameters.length > 0 ? getWarningTextForInvalidParameters(invalidParameters) : undefined;
    return (_jsxs(ConfirmDialogBase, { className: "gd-drill-custom-url-editor s-gd-drill-custom-url-editor", isPositive: true, headline: previousValue
            ? intl.formatMessage({ id: "configurationPanel.drillIntoUrl.editor.editUrlTitle" })
            : intl.formatMessage({ id: "configurationPanel.drillIntoUrl.editor.addUrlTitle" }), cancelButtonText: intl.formatMessage({
            id: "configurationPanel.drillIntoUrl.editor.cancelButtonLabel",
        }), submitButtonText: intl.formatMessage({
            id: "configurationPanel.drillIntoUrl.editor.applyButtonLabel",
        }), isSubmitDisabled: !isApplyEnabled, submitOnEnterKey: false, onCancel: onClose, onSubmit: apply, warning: editorWarningText, children: [
            _jsx(UrlInputPanel, { onChange: handleOnChange, onCursor: handleCursorPosition, documentationLink: documentationLink, currentUrlValue: currentValue, attributeDisplayForms: attributeDisplayForms, insightFilters: insightFilters, dashboardFilters: dashboardFilters, dashboardMeasureValueFilters: dashboardMeasureValueFilters, insightMeasureValueFilters: insightMeasureValueFilters, enableInsightMeasureValueFilters: enableInsightMeasureValueFilters, attributeFilterConfigs: attributeFilterConfigs, intl: intl }), _jsx(ParametersPanel, { insightFilters: insightFilters, dashboardFilters: dashboardFilters, dashboardMeasureValueFilters: dashboardMeasureValueFilters, insightMeasureValueFilters: insightMeasureValueFilters, attributeFilterConfigs: attributeFilterConfigs, attributeDisplayForms: attributeDisplayForms, loadingAttributeDisplayForms: loadingAttributeDisplayForms, enableClientIdParameter: enableClientIdParameter, enableDataProductIdParameter: enableDataProductIdParameter, enableWidgetIdParameter: enableWidgetIdParameter, onAdd: handleOnAdd, intl: intl, widgetRef: widgetRef })
        ] }));
}
const overlayController = OverlayController.getInstance(DASHBOARD_HEADER_OVERLAYS_Z_INDEX);
export function CustomUrlEditor(props) {
    const isMobileDevice = useMediaQuery("mobileDevice");
    const SelectedOverlay = isMobileDevice ? FullScreenOverlay : Overlay;
    return (_jsx(OverlayControllerProvider, { overlayController: overlayController, children: _jsx(SelectedOverlay, { onClose: props.onClose, isModal: true, closeOnOutsideClick: false, closeOnEscape: true, positionType: "fixed", className: "gd-modal-overlay", children: _jsx(CustomUrlEditorDialog, { ...props }) }) }));
}
function useInsightMeasureValueFilters(widgetRef, enabled) {
    const insight = useDashboardSelector(selectInsightByWidgetRef(widgetRef));
    return useMemo(() => {
        if (!enabled || !insight) {
            return [];
        }
        return insightDefinitionFilters(insight).filter(isMeasureValueFilter);
    }, [enabled, insight]);
}
function useSanitizedInsightFilters(widgetRef) {
    const insight = useDashboardSelector(selectInsightByWidgetRef(widgetRef));
    const sanitizeAttributeFilter = useSanitizeAttributeFilter();
    return useMemo(() => {
        if (!insight) {
            return undefined;
        }
        // Date filters are currently not supported, so filter them out
        return uniqBy(insightDefinitionFilters(insight)
            .filter(isAttributeFilter)
            .map(sanitizeAttributeFilter)
            .filter(isAttributeFilter), // filter out undefined values (eg. filters with removed display forms)
        (f) => serializeObjRef(filterObjRef(f)));
    }, [insight, sanitizeAttributeFilter]);
}
function useSanitizedDashboardFilters() {
    // Date filters are currently not supported, so select only attribute filters
    const dashboardFilters = useDashboardSelector(selectFilterContextAttributeFilterItems);
    const sanitizeAttributeFilter = useSanitizeAttributeFilter();
    return useMemo(() => {
        return dashboardFilters
            ?.map(dashboardAttributeFilterItemToAttributeFilter)
            .map(sanitizeAttributeFilter)
            .filter(isAttributeFilter); // filter out undefined values (eg. filters with removed display forms)
    }, [dashboardFilters, sanitizeAttributeFilter]);
}
function useSanitizeAttributeFilter() {
    const catalogDisplayFormsMap = useDashboardSelector(selectAllCatalogDisplayFormsMap);
    return useCallback((filter) => {
        const displayForm = catalogDisplayFormsMap.get(filterObjRef(filter));
        if (displayForm) {
            if (isNegativeAttributeFilter(filter)) {
                return {
                    ...filter,
                    negativeAttributeFilter: {
                        ...filter.negativeAttributeFilter,
                        displayForm: idRef(displayForm.id, "displayForm"),
                    },
                };
            }
            else if (isPositiveAttributeFilter(filter)) {
                return {
                    ...filter,
                    positiveAttributeFilter: {
                        ...filter.positiveAttributeFilter,
                        displayForm: idRef(displayForm.id, "displayForm"),
                    },
                };
            }
            else if (isArbitraryAttributeFilter(filter)) {
                return {
                    ...filter,
                    arbitraryAttributeFilter: {
                        ...filter.arbitraryAttributeFilter,
                        label: idRef(displayForm.id, "displayForm"),
                    },
                };
            }
            else if (isMatchAttributeFilter(filter)) {
                return {
                    ...filter,
                    matchAttributeFilter: {
                        ...filter.matchAttributeFilter,
                        label: idRef(displayForm.id, "displayForm"),
                    },
                };
            }
        }
        // display form no longer exists -> filter is invalid
        return undefined;
    }, [catalogDisplayFormsMap]);
}
