import { action, computed, makeObservable, observable, reaction, runInAction, } from 'mobx';
import { CollectionBIReporter, FedopsReporter, idArrayFilter, MultiCollectionSupport, TaskState, ValueBox, } from '@wix/bex-core';
import { simplifyColumn, simplifyColumns } from './simplifyColumns';
import { ToolbarBIReporter } from './ToolbarBIReporter';
import { SidePanelsState } from './SidePanelsState';
import { RectState } from './RectState';
import { BulkActionToolbarState } from './BulkActionToolbarState';
import { addEventListener } from '@wix/bex-core/util';
import { simplifyExtendedColumns } from './simplifyExtendedColumns';
import { ToolbarState } from '../components/CollectionToolbars/ToolbarState';
import { ColumnSizesState } from './ColumnSizesState';
export class ToolbarCollectionState {
    constructor(params) {
        this.selectedColumns = idArrayFilter();
        this.initTask = new TaskState();
        this.featuredComponents = {
            moreFiltersButton: new ValueBox(null),
            appliedFiltersTagList: new ValueBox(null),
            exportButton: new ValueBox(null),
            exportModal: new ValueBox(null),
        };
        this._userColumns = []; // columns propagated from user
        this._featureColumns = observable.array(); // columns propagated from installed features
        this._extendedColumns = []; // columns propagated from data-extension (can be merged with above?)
        this.internalScroll = undefined;
        this.customColumnsState = null;
        this.customColumnsStateInitialized = false;
        this.columnSizesState = null;
        this.multiLevelSorting = null;
        this.liveRegionRef = {
            current: null,
        };
        this.collectionDataExtension = null;
        this.menuItemExtensions = new Map();
        this.tagsCollectionState = null;
        this.toolbarFiltersState = null;
        this.toolbarFiltersStateInitialized = false;
        this._dnd = null;
        this.filtersProps = null;
        this.viewsProps = null;
        this.dragAndDropCategories = null;
        this.customColumnsProps = null;
        this.selectionProps = new ValueBox({});
        this.featuresAvailability = {};
        this.additionalFeaturesAvailability = {};
        this.actionCell = new ValueBox(undefined);
        this.contentPadding = 24;
        this.contentPaddingPx = `${this.contentPadding}px`;
        this.scrollElementRect = observable({
            height: null,
            top: null,
        });
        this.scrollTopBeforeUnmount = null;
        this.minimizedHeaderHeight = 0;
        this.tabsFilterProps = undefined;
        this._searchExpanded = false;
        this.forceRenderIndexes = undefined;
        this.getCollectionSnapshot = () => {
            const { collection: { result: { originQuery }, }, } = this;
            return {
                viewShown: this.viewsState?.views.currentView?.id,
                tabShown: this.getCurrentTabName(),
                sortOrderApplied: originQuery.sort?.length
                    ? JSON.stringify(originQuery.sort)
                    : undefined,
                filtersApplied: JSON.stringify(originQuery.filtersKey),
                filteredListSizeShown: this.collection.result.total,
            };
        };
        this._toStoredColumn = (column) => {
            const { id, defaultHidden, hideable, hiddenFromCustomColumnsSelection } = column;
            return {
                id,
                isSelected: !hideable || hiddenFromCustomColumnsSelection || !defaultHidden,
            };
        };
        this._adjustSelectedColumns = () => {
            const { selectedColumns, customColumnsState, customColumnsProps, customColumnsStateInitialized, } = this;
            // as long as consumer rendered `<CustomColumns/>` at least once, use `mergeNewColumns` strategy when re-rendering new columns prop
            if (customColumnsProps != null || customColumnsStateInitialized) {
                // if `customColumns` is not set yet - do nothing
                if (customColumnsState) {
                    const { initTask } = customColumnsState;
                    const mergedColumns = customColumnsState.mergeNewColumns();
                    runInAction(() => {
                        selectedColumns.defaultValue = this.columns.map((col) => {
                            const { id, isSelected } = this._toStoredColumn(col);
                            return { id, isSelected };
                        });
                    });
                    if (initTask.status.isSuccess && customColumnsState._touched) {
                        selectedColumns.refresh(mergedColumns);
                    }
                    else {
                        selectedColumns.setValue(mergedColumns);
                    }
                }
            }
            else {
                const allColumns = this.columns.map(({ id }) => ({
                    id,
                    isSelected: true,
                }));
                selectedColumns.defaultValue = allColumns;
                selectedColumns.setValue(allColumns);
            }
        };
        this.closeSidePanel = () => {
            this.sidePanel.close();
        };
        this.retryErrorState = action(() => {
            const { initTask, multi } = this;
            if (initTask.status.isError) {
                initTask.runOnce();
            }
            else {
                multi.retryErrorState();
            }
        });
        this.onSelectionStarted = () => {
            this.bulk._selectionStartTime = performance.now();
        };
        this.onSelectionChanged = action((_selectedIds, change) => {
            if (change == null) {
                return;
            }
            const { panels, bulk } = this;
            panels.closeSidePanel();
            switch (change.type) {
                case 'ALL':
                    bulk.toggleSelectAll({ location: 'Checkbox' });
                    break;
                case 'NONE':
                    bulk.deselectAll({ location: 'Checkbox' });
                    break;
                case 'SINGLE_TOGGLE':
                    if (change.value) {
                        bulk.selectOne(change.id);
                    }
                    else {
                        bulk.deselectOne(change.id);
                    }
                    break;
            }
        });
        this.openCustomFieldModal = ({ customOrigin } = {}) => {
            return this.collectionDataExtension?.customFieldsPanel.openCustomFieldModal({
                origin: 'external',
                customOrigin,
            });
        };
        this.openManageTagsModal = () => {
            return this.tagsCollectionState?.openManageTagsModal();
        };
        this.onAddItemActionComplete = async (items) => {
            await this._resetQueryAndAddItems(items);
            this.toolbarBIReporter.newItemCreationEnd(items);
        };
        this._resetQueryAndAddItems = async (items) => {
            const { collection } = this;
            const { query } = collection;
            query.resetFilters();
            query.resetSorting();
            await collection.clearResultAndMoveToStart({ force: true });
            collection._optimisticActions?.createMany(items, {
                submit: async () => items,
            });
            collection.scrollableContent?.scrollTo?.({
                top: 0,
                behavior: 'smooth',
            });
        };
        this.collection = params.collection;
        this.container = params.container;
        this.componentType = params.componentType;
        this.toolbar = new ToolbarState(this);
        this.fedopsReporter = new FedopsReporter({
            componentName: this.componentType,
            collection: this.collection,
            internalMonitor: this.container.internalMonitor,
        });
        this.multi = new MultiCollectionSupport({
            collections: [this.collection],
        });
        this.itemsContentRect = new RectState(params);
        this.toolbarRect = new RectState(params);
        this.panels = new SidePanelsState({
            container: this.container,
            panelGroupName: this.collection.queryName,
        });
        this.toolbarBIReporter = new ToolbarBIReporter({
            toolbar: this,
            collection: this.collection,
            reportBi: (ev) => {
                this.reportBi({
                    ...ev,
                    params: {
                        ...this._commonDynamicBiParams(),
                        ...ev.params,
                    },
                });
            },
        });
        this.bulk = new BulkActionToolbarState({
            toolbarBIReporter: this.toolbarBIReporter,
            panels: this.panels,
            multi: this.multi,
            translate: this.container.translate,
            scrollToTop: () => {
                this.collection.scrollableContent?.scrollTo({
                    top: 0,
                    left: 0,
                });
            },
        });
        this.namespace = [
            this.container.environment.componentId,
            this.collection.queryName,
        ].join('.');
        const { dataCapsule } = this.container.createEssentials({
            dataCapsule: {
                namespace: this.namespace,
            },
        });
        this.dataCapsule = dataCapsule;
        const reportBiBase = params.reportBi ?? this.container.reportBi;
        this.reportBi = (ev) => {
            reportBiBase({
                ...ev,
                params: {
                    ...this._commonDynamicBiParams(),
                    ...ev.params,
                },
            });
        };
        this.columnSizesState = new ColumnSizesState({
            container: this.container,
            dataCapsule: this.dataCapsule,
            fqdn: this.namespace,
        });
        makeObservable(this, {
            forceRenderIndexes: observable.ref,
            _userColumns: observable.ref,
            _extendedColumns: observable.ref,
            columns: computed,
            customColumnsStateInitialized: observable.ref,
            viewsProps: observable.ref,
            dragAndDropCategories: observable.ref,
            customColumnsProps: observable.ref,
            filtersProps: observable.ref,
            shouldDisplayFiltersTags: computed,
            totalStickyContentHeight: computed,
            showInitialLoader: computed,
            showEmptyState: computed,
            showErrorState: computed,
            hasSubToolbarComponents: computed,
            containerRect: computed,
            setFilterTagsPropsIfChanged: action,
            _initDefaultSortableColumn: action,
            minimizedHeaderHeight: observable.ref,
            tabsFilterProps: observable.ref,
            toolbarFiltersStateInitialized: observable.ref,
            hasToolbarTabs: computed,
            itemsContentHeight: computed,
            setNewColumns: action,
            addFeatureColumn: action,
            setNewExtendedColumns: action,
            _commonDynamicBiParams: action,
            _adjustSortWithNewColumns: action,
            setToolbarFiltersStateInitialized: action,
            activeFiltersEntries: computed,
            _searchExpanded: observable.ref,
        });
    }
    get containerRect() {
        const { itemsContentRect, toolbarRect, internalScroll } = this;
        if (internalScroll && itemsContentRect.rect.height) {
            return {
                ...itemsContentRect.rect,
            };
        }
        if (itemsContentRect.rect.left && toolbarRect.rect.left) {
            const top = toolbarRect.rect.bottom;
            const bottom = top + itemsContentRect.rect.height;
            const left = toolbarRect.rect.left;
            const right = left + toolbarRect.rect.width;
            return {
                left,
                right,
                top,
                bottom,
                height: bottom - top,
                width: right - left,
            };
        }
        return undefined;
    }
    get containerTop() {
        return this.containerRect?.top;
    }
    /**
     * How much height left for the content inside the viewport
     */
    get itemsContentHeight() {
        const { toolbarRect, scrollElementRect, contentPadding, internalScroll, itemsContentRect, } = this;
        if (internalScroll && itemsContentRect.rect.height) {
            return itemsContentRect.rect.height;
        }
        if (toolbarRect.rect.height == null ||
            toolbarRect.rect.top == null ||
            scrollElementRect.height == null ||
            scrollElementRect.top == null) {
            return 0;
        }
        if (process.env.NODE_ENV === 'test') {
            return 796;
        }
        const toolbarOffsetTop = toolbarRect.rect.top - scrollElementRect.top;
        return (scrollElementRect.height -
            toolbarOffsetTop -
            toolbarRect.rect.height -
            contentPadding);
    }
    get totalStickyContentHeight() {
        const { toolbarRect, minimizedHeaderHeight } = this;
        if (toolbarRect.rect.height == null) {
            return null;
        }
        return toolbarRect.rect.height + minimizedHeaderHeight;
    }
    get sidePanel() {
        return this.panels.sidePanel;
    }
    get sidePanelComponents() {
        return this.panels.sidePanelComponents;
    }
    get showInitialLoader() {
        const { multi, initTask } = this;
        return (multi.showInitialLoader ||
            initTask.status.isLoading ||
            initTask.status.isIdle);
    }
    get showEmptyState() {
        const { showInitialLoader, multi: { showRefreshLoader, showEmptyState }, } = this;
        return showEmptyState && !showInitialLoader && !showRefreshLoader;
    }
    get errorStatus() {
        const { initTask, multi } = this;
        return initTask.errorStatus ?? multi.errorStatus;
    }
    get showErrorState() {
        const { showInitialLoader, multi: { showRefreshLoader, showErrorState }, initTask, } = this;
        return ((showErrorState || initTask.status.isError) &&
            !showInitialLoader &&
            !showRefreshLoader);
    }
    get hasSubToolbarComponents() {
        const { appliedFiltersTagList } = this.featuredComponents;
        return appliedFiltersTagList.value != null;
    }
    get reorderModeState() {
        return this._dnd?.reorderModeState;
    }
    get shouldDisplayFiltersTags() {
        return !!this.featuredComponents.appliedFiltersTagList.value?.state.tags
            .length;
    }
    get hasToolbarTabs() {
        return this.tabsFilterProps != null;
    }
    get isReorderModeToolbarVisible() {
        return this.reorderModeState?.isReorderModeToolbarVisible;
    }
    get isReorderModePending() {
        return this.reorderModeState?.isReorderModePending;
    }
    get columns() {
        const { _userColumns, _featureColumns, _extendedColumns } = this;
        return [..._userColumns, ..._featureColumns, ..._extendedColumns];
    }
    get selectedOrderedColumnsOrAll() {
        const { columns, customColumnsState, columnSizesState } = this;
        const baseColumns = customColumnsState
            ? customColumnsState.selectedOrderedColumns
            : columns;
        return columnSizesState?.mergeSizes(baseColumns) ?? baseColumns;
    }
    _commonDynamicBiParams(query = this.collection.result.originQuery) {
        const { collection, viewsState } = this;
        return {
            componentType: this.componentType,
            ...collection._commonDynamicBiParams(query),
            currentTab: this.getCurrentTabName(),
            ...(viewsState && { currentView: viewsState.views.currentView?.id }),
            ...(viewsState?.views?.currentView && {
                isPredefined: viewsState.views.currentView.isPreset,
            }),
            ...(viewsState?.views?.currentView?.filters && {
                numFiltersInView: this._numberFiltersInView(viewsState.views.currentView),
            }),
            visibleColumnsOrder: this.selectedOrderedColumnsOrAll
                .map((col) => col.id ?? col.title ?? col.name)
                .join(','),
            numColumns: this.selectedOrderedColumnsOrAll.length,
            numFiltersActive: collection.query.activeFiltersCount,
        };
    }
    _numberFiltersInView(view) {
        let numFiltersInView = 0;
        if (view.filters) {
            for (const filterName of Object.keys(view.filters)) {
                const filter = view.filters[filterName];
                if (filter && filter.value) {
                    if (Array.isArray(filter.value)) {
                        numFiltersInView += filter.value.length;
                    }
                    else if (filter.value) {
                        numFiltersInView += 1;
                    }
                }
            }
        }
        return numFiltersInView;
    }
    getCurrentTabName() {
        const { tabsFilterProps, collection: { result: { originQuery: query }, }, } = this;
        const tabs = tabsFilterProps &&
            Object.entries(query.rawFilters)
                .filter(([key]) => key === tabsFilterProps.filter.name)
                .flatMap(([, value]) => Array.isArray(value)
                ? value.map(tabsFilterProps.filter.itemKey)
                : value);
        return tabs?.[0];
    }
    getPendingFilter(filter) {
        return this.pendingQuery?.getApplicableFilter(filter) ?? filter;
    }
    init({ featuresInitializers, hasMultiLevelSorting, skipFilterListeners, }) {
        const { collection, multi, initTask, panels, sidePanel, collectionDataExtension, tagsCollectionState, bulk, customColumnsState, viewsState, columnSizesState, } = this;
        const biReporters = multi.collections.map((collection) => new CollectionBIReporter({
            collection,
            reportBi: (ev) => {
                this.reportBi({
                    ...ev,
                    params: {
                        ...collection._commonDynamicBiParams(),
                        ...ev.params,
                    },
                });
            },
        }));
        // must call `initOptionalFeatures` before collection init because we want to allow features to customize the collection before collection.init
        const tableFeatures = featuresInitializers
            .filter((t) => t != null)
            .map((tableFeatInit) => tableFeatInit(this));
        // should be initialized before collection.init() so the sort query will be updated before the time of the first request.
        this._initDefaultSortableColumn(hasMultiLevelSorting);
        const disposers = [
            collectionDataExtension?.init(),
            customColumnsState?._tableInit(),
            viewsState?.init(),
            columnSizesState?.init(),
            // register table feature first as they might register to the collection `beforeInitialFetch`
            ...tableFeatures.map((t) => t.init()),
            reaction(() => this.selectedOrderedColumnsOrAll, (columns) => {
                collection.query._columns.replace(columns.map((c) => c.id));
            }, {
                fireImmediately: true,
            }),
            reaction(() => collectionDataExtension?.dataExtension.availableCustomFields, (customFields) => {
                this.setNewExtendedColumns(customFields ?? []);
            }),
            multi.init({ skipFilterListeners }),
            ...biReporters.map((b) => b.init()),
            panels.init(),
            sidePanel.init(),
            bulk.init(),
            tagsCollectionState?.init(),
            addEventListener(collection.bulkSelect.events, 'openModal', this.bulk.modals.actionModal.modal.open),
            addEventListener(collection.bulkSelect.events, 'closeModal', this.bulk.modals.actionModal.modal.close),
            addEventListener(this.collection.emitter, 'resultUpdated', () => {
                this.broadcast({
                    message: this.container.translate('cairo.a11y.liveRegion.resultsFound', { num: this.collection.result.total }),
                });
            }),
        ];
        const startTime = performance.now();
        initTask.runOnce(async () => {
            this.toolbarBIReporter.loadStart();
            multi.initTask.runOnce();
            customColumnsState?.initTask.runOnce();
            tableFeatures.forEach(({ initTask }) => {
                if (initTask) {
                    initTask.runOnce();
                }
            });
            try {
                await Promise.all([
                    multi.initTask.status.promise,
                    tagsCollectionState?.initTask.status.promise?.catch(() => null),
                    collectionDataExtension?.initTask.status.promise?.catch(() => null),
                    customColumnsState?.initTask.status.promise,
                    columnSizesState?.initTask.status.promise,
                    ...tableFeatures.map((t) => t.initTask?.status.promise),
                ]);
                this.toolbarBIReporter.loadEnd(startTime);
            }
            catch (e) {
                throw e;
            }
        });
        return () => {
            disposers.forEach((d) => d?.());
        };
    }
    setFilterTagsPropsIfChanged(filtersProps) {
        if (this.filtersProps !== filtersProps) {
            this.filtersProps = filtersProps;
        }
    }
    setNewColumns(tableColumns) {
        this._userColumns = simplifyColumns(tableColumns);
    }
    addFeatureColumn(featureColumn) {
        this._featureColumns.push(simplifyColumn(featureColumn));
        this._adjustSelectedColumns();
    }
    setNewExtendedColumns(fields = [], { defaultHidden = false } = {}) {
        if (!this.collectionDataExtension?.dataExtension.initTask.status.isSuccess) {
            return;
        }
        this._extendedColumns = simplifyExtendedColumns({
            fields,
            toExtendedFields: this.collection.toExtendedFields,
            defaultHidden,
        });
        this._adjustSelectedColumns();
    }
    broadcast(params) {
        this.liveRegionRef.current?.broadcast(params);
    }
    setToolbarFiltersStateInitialized(value) {
        this.toolbarFiltersStateInitialized = value;
    }
    updateColumnWidth(columnId, width) {
        this.columnSizesState?.updateColumnWidth(columnId, width);
    }
    _initDefaultSortableColumn(hasMultiLevelSorting = false) {
        const { columns, collection: { query }, } = this;
        const defaultSortableColumns = columns.filter((col) => col.sortable === true && col.id != null && col.defaultSortOrder != null);
        if (defaultSortableColumns.length && !query.sort.value.length) {
            const sortQuery = defaultSortableColumns.map((column) => ({
                field: column.id,
                direction: column.defaultSortOrder,
            }));
            query.sort.setSortQuery(hasMultiLevelSorting ? sortQuery : sortQuery.slice(0, 1));
        }
    }
    _adjustSortWithNewColumns(tableColumns) {
        const { collection: { query }, } = this;
        const tableColumnsIds = new Set(tableColumns.map((column) => column.id));
        query.sort.value
            .filter(({ field }) => !tableColumnsIds.has(field))
            .forEach((s) => {
            query.sort.value.remove(s);
        });
        query.sort.events.emit('change');
        this.collection.scheduleSort({ clearResult: true });
    }
    openFiltersPanel() {
        this.panels.openSidePanel('filters');
    }
    _onSelectAllCheckboxClick() { }
    get activeFiltersEntries() {
        return Array.from(this.multi.collections
            .flatMap(({ query }) => query.activeFiltersEntries.filter(([_, filter]) => filter !== query.search))
            .reduce((map, entry) => map.set(entry[0], entry), new Map())
            .values());
    }
    getPageFeaturedActions() {
        const { collectionDataExtension, tagsCollectionState } = this;
        return [collectionDataExtension, tagsCollectionState]
            .filter((e) => e != null)
            .filter((e) => !e.props?.disableDefaultPageAction)
            .flatMap((e) => e.featuredPageActions);
    }
}
//# sourceMappingURL=ToolbarCollectionState.js.map