/*!
 * Built by Revolist OU ❤️
 */
import reduce from "lodash/reduce";
import { isRowType, rowTypes, DataStore, getSourceItem, getVisibleSourceItem, } from "../store/index";
/**
 * Data source provider
 *
 * @dependsOn DimensionProvider
 */
export class DataProvider {
    constructor(dimensionProvider) {
        this.dimensionProvider = dimensionProvider;
        this.stores = reduce(rowTypes, (sources, k) => {
            sources[k] = new DataStore(k);
            return sources;
        }, {});
    }
    /**
     * Replaces the data source for a row type and synchronizes the related dimension metadata.
     *
     * `rgRow` updates also refresh the virtual row model unless `disableVirtualRows` is set.
     * Pinned row types skip virtual row recalculation because they are rendered directly.
     *
     * @param data Full source data assigned to the target row store.
     * @param type Row collection to update. Defaults to the main body rows.
     * @param disableVirtualRows Prevents recalculating virtual rows for the main row store.
     * @param grouping Optional grouping metadata applied together with the new data set.
     * @param silent Preserves the current trimmed state instead of resetting it during the update.
     * @param preserveTrimmed Re-applies current trimmed indexes after a silent update.
     * @returns The same `data` array that was provided to the method.
     */
    setData(data, type = 'rgRow', disableVirtualRows = false, grouping, 
    // if true, store will be updated without resetting trimmed state
    silent = false, preserveTrimmed = false) {
        // set rgRow data
        this.stores[type].updateData([...data], grouping, silent, preserveTrimmed);
        // for pinned row no need virtual data
        const noVirtual = type !== 'rgRow' || disableVirtualRows;
        this.dimensionProvider.setData(data.length, type, noVirtual);
        return data;
    }
    getModel(virtualIndex, type = 'rgRow') {
        const store = this.stores[type].store;
        return getSourceItem(store, virtualIndex);
    }
    changeOrder({ rowType = 'rgRow', from, to }) {
        const storeService = this.stores[rowType];
        // take currently visible row indexes
        const newItemsOrder = [...storeService.store.get('proxyItems')];
        const prevItems = storeService.store.get('items');
        // take out
        const toMove = newItemsOrder.splice(newItemsOrder.indexOf(prevItems[from]), // get index in proxy
        1);
        // insert before
        newItemsOrder.splice(newItemsOrder.indexOf(prevItems[to]), // get index in proxy
        0, ...toMove);
        storeService.setData({
            proxyItems: newItemsOrder,
        });
        // take currently visible row indexes
        const newItems = storeService.store.get('items');
        this.dimensionProvider.updateSizesPositionByNewDataIndexes(rowType, newItems, prevItems);
    }
    setCellData({ type, rowIndex, prop, val }, mutate = true) {
        const model = this.getModel(rowIndex, type);
        model[prop] = val;
        this.stores[type].setSourceData({ [rowIndex]: model }, mutate);
    }
    setRangeData(data, type) {
        const items = {};
        for (let rowIndex in data) {
            const oldModel = (items[rowIndex] = getSourceItem(this.stores[type].store, parseInt(rowIndex, 10)));
            if (!oldModel) {
                continue;
            }
            for (let prop in data[rowIndex]) {
                oldModel[prop] = data[rowIndex][prop];
            }
        }
        this.stores[type].setSourceData(items);
    }
    refresh(type = 'all') {
        if (isRowType(type)) {
            this.refreshItems(type);
        }
        rowTypes.forEach((t) => this.refreshItems(t));
    }
    refreshItems(type = 'rgRow') {
        const items = this.stores[type].store.get('items');
        this.stores[type].setData({ items: [...items] });
    }
    setGrouping({ depth }, type = 'rgRow') {
        this.stores[type].setData({ groupingDepth: depth });
    }
    setTrimmed(trimmed, type = 'rgRow') {
        const store = this.stores[type];
        store.addTrimmed(trimmed);
        this.dimensionProvider.setTrimmed(trimmed, type);
        if (type === 'rgRow') {
            this.dimensionProvider.setData(getVisibleSourceItem(store.store).length, type);
        }
    }
}
