import { addEventListener, QueryState, syncWithSharedQuery, TaskState, } from '@wix/bex-core';
import { ToolbarCollectionState } from '../ToolbarCollectionState';
import { TableState } from '../TableState';
import { NestedTableNestedModeState } from './NestedTableNestedModeState';
import { NestedTableFlatModeState } from './NestedTableFlatModeState';
import { NestedCollectionFetchAllState } from './NestedCollectionFetchAllState';
import { reaction } from 'mobx';
import { createNestedOptimisticActions } from './createNestedOptimisticActions';
export class NestedTableState {
    constructor(params) {
        this.initTask = new TaskState();
        this.sequences = new Map();
        this.container = params.container;
        this.query = new QueryState({
            filters: params.filters || {},
        });
        this.levels = params.levels.map((level, i) => ({
            ...level,
            depth: i,
        }));
        const fetchAllLimit = params.fetchAllLimit ?? params.fetchAllThreshold;
        this.options = {
            fetchAllThreshold: fetchAllLimit ?? 1000,
            expandAllThreshold: params.expandAllThreshold ?? fetchAllLimit ?? 1000,
        };
        this.mainColumn = params.mainColumn;
        const rootLevelDescriptor = this.levels[0];
        if (rootLevelDescriptor == null) {
            throw new Error('NestedTableState must have at least one level');
        }
        const nestedOptimisticActionsState = {
            parentId: '',
            sequences: this.sequences,
            query: this.query,
            levelDescriptor: rootLevelDescriptor,
        };
        this.rootNodeCollection = rootLevelDescriptor.createCollection(nestedOptimisticActionsState);
        createNestedOptimisticActions(this.container, this.rootNodeCollection.collection, nestedOptimisticActionsState);
        const { collection } = this.rootNodeCollection;
        syncWithSharedQuery(collection.query, this.query);
        this.reportBi = (reportProps) => {
            const { isFetchAllAborted } = this;
            this.container.reportBi({
                ...reportProps,
                params: {
                    ...reportProps.params,
                    ...(isFetchAllAborted != null && {
                        componentStatus: isFetchAllAborted
                            ? 'All items collapsed'
                            : 'All items expanded',
                    }),
                },
            });
        };
        this.toolbar = new ToolbarCollectionState({
            collection: this.rootNodeCollection.collection,
            container: params.container,
            componentType: 'NestedTable',
            reportBi: this.reportBi,
        });
        this.toolbar.setNewColumns(params.columns.map((column) => ({
            ...column,
            render: () => null,
        })));
        this.tableState = new TableState({
            collection: this.rootNodeCollection.collection,
            container: params.container,
            toolbar: this.toolbar,
        });
        this.nested = new NestedTableNestedModeState({
            wrapper: this,
            reportBi: this.reportBi,
        });
        this.flat = new NestedTableFlatModeState({
            wrapper: this,
        });
    }
    get nestedMode() {
        return this.nested;
    }
    get flatMode() {
        return this.flat;
    }
    getNode(key) {
        return this.nested.getNode(key);
    }
    getRootNode() {
        return this.nested.root;
    }
    /**
     * Get all the nodes in the table
     */
    getAllNodes() {
        return this.nested.getAllNodes();
    }
    get isFetchAllAborted() {
        return this.nested.isFetchAllAborted;
    }
    get expandAll() {
        return this.nested.expandAll;
    }
    get nestedCollection() {
        return this.nested.nestedCollection;
    }
    _attemptFetchAllAndPopulateCache() {
        const initTask = new TaskState();
        return {
            initTask,
            init: ({ invalidate } = { invalidate: false }) => {
                initTask.runOnce(async () => {
                    const fetchAllState = new NestedCollectionFetchAllState({
                        options: this.options,
                        query: this.nested.query,
                        nestedCollectionState: this.nested.nestedCollection,
                    });
                    const disposers = [fetchAllState.init({ invalidate })];
                    try {
                        await fetchAllState.initTask.status.promise;
                    }
                    finally {
                        disposers.forEach((d) => d());
                    }
                });
                return () => { };
            },
        };
    }
    refreshAll({ invalidate = true } = {}) {
        const initTask = this.isFlatMode
            ? this.flat.initTask
            : this.nested.initTask;
        initTask.reset();
        initTask.runOnce(async () => {
            const fetchAll = this._attemptFetchAllAndPopulateCache();
            fetchAll.init({ invalidate });
            await fetchAll.initTask.status.promise;
            await (this.isFlatMode
                ? this.flatMode._refreshAll()
                : this.nestedMode.root._refreshAll());
            this.rootNodeCollection.collection.query.events.emit('refresh');
        });
    }
    get isFlatMode() {
        return !!this.query.search.value;
    }
    _addFilterListeners() {
        return Object.values(this.query.filtersEntries).map(([_, filter]) => {
            return addEventListener(filter.events, 'refresh', () => {
                this.refreshAll({
                    invalidate: false,
                });
            });
        });
    }
    init() {
        const { initTask, tableState, query } = this;
        const disposers = [
            query.init({ skipFilterListeners: true }),
            ...this._addFilterListeners(),
            reaction(() => this.isFlatMode, (isFlatMode) => {
                const { query: { _fields }, } = this;
                if (isFlatMode) {
                    _fields.add('breadcrumbs');
                }
                else {
                    _fields.delete('breadcrumbs');
                }
            }, { fireImmediately: true }),
            tableState.init({
                featuresInitializers: [],
                skipFilterListeners: true,
            }),
        ];
        initTask.runOnce(async () => {
            tableState.initTask.runOnce();
            await tableState.initTask.status.promise;
        });
        return () => {
            initTask.reset();
            disposers.forEach((d) => d());
        };
    }
}
//# sourceMappingURL=NestedTableState.js.map