import { TABLE_EVENT_TYPE, TYPES } from "@visactor/vtable";

import { FilterEngine } from "./filter-engine";

import { FilterStateManager } from "./filter-state-manager";

import { FilterToolbar } from "./filter-toolbar";

import { FilterActionType } from "./types";

import { cloneDeep, merge } from "lodash";

import { filterStyles } from "./styles";

import { categories } from "./constant";

export class FilterPlugin {
    constructor(pluginOptions) {
        var _a, _b, _c, _d, _e;
        this.id = "filter", this.name = "Filter", this.runTime = [ TABLE_EVENT_TYPE.BEFORE_INIT, TABLE_EVENT_TYPE.BEFORE_UPDATE_OPTION, TABLE_EVENT_TYPE.ICON_CLICK, TABLE_EVENT_TYPE.SCROLL, TABLE_EVENT_TYPE.CHANGE_CELL_VALUE, TABLE_EVENT_TYPE.UPDATE_RECORD, TABLE_EVENT_TYPE.ADD_RECORD, TABLE_EVENT_TYPE.DELETE_RECORD, TABLE_EVENT_TYPE.ADD_COLUMN, TABLE_EVENT_TYPE.DELETE_COLUMN ], 
        this.id = null !== (_a = null == pluginOptions ? void 0 : pluginOptions.id) && void 0 !== _a ? _a : this.id, 
        this.pluginOptions = cloneDeep(pluginOptions), this.pluginOptions.filterIcon = null !== (_b = pluginOptions.filterIcon) && void 0 !== _b ? _b : {
            name: "filter-icon",
            type: "svg",
            width: 12,
            height: 12,
            positionType: TYPES.IconPosition.right,
            cursor: "pointer",
            svg: '<svg t="1752821809070" class="icon" viewBox="0 0 1664 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="12092" width="200" height="200"><path d="M89.6 179.2A89.6 89.6 0 0 1 89.6 0h1408a89.6 89.6 0 0 1 0 179.2H89.6z m256 384a89.6 89.6 0 0 1 0-179.2h896a89.6 89.6 0 0 1 0 179.2h-896z m256 384a89.6 89.6 0 0 1 0-179.2h384a89.6 89.6 0 0 1 0 179.2h-384z" fill="#93a2b9" p-id="12093"></path></svg>'
        }, this.pluginOptions.filteringIcon = null !== (_c = pluginOptions.filteringIcon) && void 0 !== _c ? _c : {
            name: "filtering-icon",
            type: "svg",
            width: 12,
            height: 12,
            positionType: TYPES.IconPosition.right,
            cursor: "pointer",
            svg: '<svg t="1752821771292" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="11926" width="200" height="200"><path d="M971.614323 53.05548L655.77935 412.054233C635.196622 435.434613 623.906096 465.509377 623.906096 496.583302v495.384307c0 28.975686-35.570152 43.063864-55.353551 21.781723l-159.865852-171.256294c-5.495389-5.895053-8.59279-13.688514-8.592789-21.781722V496.583302c0-31.073925-11.290526-61.148688-31.873254-84.429153L52.385677 53.05548C34.200936 32.472751 48.888611 0 76.365554 0h871.268892c27.476943 0 42.164618 32.472751 23.979877 53.05548z" fill="#416eff" p-id="11927"></path></svg>'
        }, this.pluginOptions.filterModes && this.pluginOptions.filterModes.length || (this.pluginOptions.filterModes = [ "byValue", "byCondition" ]), 
        this.pluginOptions.styles = merge(filterStyles, null !== (_d = this.pluginOptions.styles) && void 0 !== _d ? _d : {}), 
        this.pluginOptions.conditionCategories = null !== (_e = pluginOptions.conditionCategories) && void 0 !== _e ? _e : categories;
    }
    initFilterPlugin(eventArgs) {
        this.filterEngine = new FilterEngine(this.pluginOptions), this.filterStateManager = new FilterStateManager(this.table, this.filterEngine), 
        this.filterToolbar = new FilterToolbar(this.table, this.filterStateManager, this.pluginOptions), 
        this.columns = eventArgs.options.columns, this.filterToolbar.render(document.body), 
        this.updateFilterIcons(this.columns), this.filterStateManager.subscribe(((_, action) => {
            (null == action ? void 0 : action.type) !== FilterActionType.ADD_FILTER && (this.updateFilterIcons(this.columns), 
            this.table.updateColumns(this.columns, {
                clearRowHeightCache: !1
            }));
        }));
    }
    run(...args) {
        var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
        const eventArgs = args[0], runtime = args[1], table = args[2];
        if (this.table = table, runtime === TABLE_EVENT_TYPE.BEFORE_INIT) this.initFilterPlugin(eventArgs); else if (runtime === TABLE_EVENT_TYPE.BEFORE_UPDATE_OPTION) this.filterEngine && this.filterStateManager && this.filterToolbar || this.initFilterPlugin(eventArgs), 
        this.pluginOptions = Object.assign(Object.assign({}, this.pluginOptions), null === (_b = null === (_a = eventArgs.options.plugins) || void 0 === _a ? void 0 : _a.find((plugin => plugin.id === this.id))) || void 0 === _b ? void 0 : _b.pluginOptions), 
        this.columns = eventArgs.options.columns, this.handleOptionUpdate(eventArgs.options); else if (runtime === TABLE_EVENT_TYPE.ICON_CLICK && "filter-icon" === eventArgs.name || "filtering-icon" === eventArgs.name) {
            if (3 === (null === (_c = eventArgs.event) || void 0 === _c ? void 0 : _c.which) || 2 === (null === (_d = eventArgs.event) || void 0 === _d ? void 0 : _d.button) || 2 == (2 & (null === (_e = eventArgs.event) || void 0 === _e ? void 0 : _e.buttons))) return;
            const col = eventArgs.col, row = eventArgs.row;
            this.filterToolbar.isVisible ? this.filterToolbar.hide(eventArgs.col, eventArgs.row) : this.filterToolbar.show(col, row, this.pluginOptions.filterModes);
        } else if (runtime === TABLE_EVENT_TYPE.SCROLL) "horizontal" === eventArgs.scrollDirection && this.filterToolbar.adjustMenuPosition(); else if (runtime === TABLE_EVENT_TYPE.CHANGE_CELL_VALUE) {
            const changedField = this.table.getHeaderField(eventArgs.col, eventArgs.row);
            this.syncFilterWithTableData(changedField);
        } else if (runtime === TABLE_EVENT_TYPE.UPDATE_RECORD) this.syncFilterWithTableData(); else if (runtime === TABLE_EVENT_TYPE.ADD_RECORD) {
            if ((null === (_g = null === (_f = this.filterStateManager) || void 0 === _f ? void 0 : _f.getActiveFilterFields) || void 0 === _g ? void 0 : _g.call(_f).length) > 0 && Array.isArray(null == eventArgs ? void 0 : eventArgs.records)) {
                const ds = this.table.dataSource;
                eventArgs.records.forEach((r => {
                    var _a;
                    return null === (_a = null == ds ? void 0 : ds.markForceVisibleRecord) || void 0 === _a ? void 0 : _a.call(ds, r);
                }));
            }
            this.syncFilterWithTableData();
        } else if (runtime === TABLE_EVENT_TYPE.DELETE_RECORD) this.syncFilterWithTableData(); else if (runtime === TABLE_EVENT_TYPE.ADD_COLUMN) {
            const columnIndex = null == eventArgs ? void 0 : eventArgs.columnIndex, columnCount = null == eventArgs ? void 0 : eventArgs.columnCount;
            "number" == typeof columnIndex && "number" == typeof columnCount && columnCount > 0 && (null === (_j = null === (_h = this.filterStateManager) || void 0 === _h ? void 0 : _h.shiftFieldsOnAddColumns) || void 0 === _j || _j.call(_h, columnIndex, columnCount)), 
            this.reapplyActiveFilters();
        } else if (runtime === TABLE_EVENT_TYPE.DELETE_COLUMN) {
            const deleteColIndexs = null == eventArgs ? void 0 : eventArgs.deleteColIndexs;
            Array.isArray(deleteColIndexs) && deleteColIndexs.length > 0 && (null === (_l = null === (_k = this.filterStateManager) || void 0 === _k ? void 0 : _k.shiftFieldsOnDeleteColumns) || void 0 === _l || _l.call(_k, deleteColIndexs)), 
            this.reapplyActiveFilters();
        }
    }
    updatePluginOptions(pluginOptions) {
        this.pluginOptions = merge(this.pluginOptions, pluginOptions), this.filterToolbar.updateStyles(this.pluginOptions.styles), 
        this.table.updateColumns(this.columns, {
            clearRowHeightCache: !1
        });
    }
    getFilterSnapshot() {
        var _a, _b, _c;
        return null !== (_c = null === (_b = null === (_a = this.filterStateManager) || void 0 === _a ? void 0 : _a.getSnapshot) || void 0 === _b ? void 0 : _b.call(_a)) && void 0 !== _c ? _c : {
            filters: []
        };
    }
    applyFilterSnapshot(snapshot) {
        var _a, _b;
        null === (_b = null === (_a = this.filterStateManager) || void 0 === _a ? void 0 : _a.applySnapshot) || void 0 === _b || _b.call(_a, snapshot, FilterActionType.APPLY_FILTERS);
    }
    update() {
        this.filterStateManager && this.reapplyActiveFilters();
    }
    syncFilterWithTableData(field) {
        var _a;
        if ("byValue" === (null === (_a = this.filterStateManager.getFilterState(field)) || void 0 === _a ? void 0 : _a.type)) {
            if (null != field) return void this.filterToolbar.valueFilter.syncSingleStateFromTableData(field);
            this.table.dataSource.columns.forEach((({field: field}) => {
                this.filterToolbar.valueFilter.syncSingleStateFromTableData(field);
            }));
        }
    }
    handleOptionUpdate(options) {
        const currentActiveFields = this.filterStateManager ? this.filterStateManager.getActiveFilterFields() : [];
        this.filterStateManager && currentActiveFields.length > 0 && this.validateFilterStatesAfterUpdate(options, currentActiveFields), 
        this.updateFilterIcons(options.columns);
    }
    reapplyActiveFilters() {
        this.filterStateManager.reapplyCurrentFilters();
    }
    validateFilterStatesAfterUpdate(options, activeFields) {
        const columns = options.columns, fieldsToRemove = [];
        activeFields.forEach((field => {
            const column = columns.find((col => col.field === field));
            column && this.shouldEnableFilterForColumn(field, column) || fieldsToRemove.push(field);
        })), fieldsToRemove.forEach((field => {
            this.filterStateManager.dispatch({
                type: FilterActionType.REMOVE_FILTER,
                payload: {
                    field: field
                }
            });
        }));
    }
    updateFilterIcons(columns = []) {
        const filterIcon = this.pluginOptions.filterIcon, filteringIcon = this.pluginOptions.filteringIcon, isIconEqual = (a, b) => a === b || a && b && "object" == typeof a && "object" == typeof b && a.name === b.name, stack = [ ...columns ], subColumns = [];
        for (;stack.length > 0; ) {
            const currentCol = stack.pop();
            currentCol.columns ? currentCol.columns.forEach((col => stack.push(col))) : subColumns.push(currentCol);
        }
        subColumns.forEach((column => {
            var _a;
            const shouldShow = this.shouldEnableFilterForColumn(column.field, column), isFiltering = !!(null === (_a = this.filterStateManager.getFilterState(column.field)) || void 0 === _a ? void 0 : _a.enable);
            let icons = (icons => icons ? Array.isArray(icons) ? icons : [ icons ] : [])(column.headerIcon);
            var list;
            shouldShow ? isFiltering ? icons.some((icon => isIconEqual(icon, filteringIcon))) || (icons = icons.filter((icon => !isIconEqual(icon, filterIcon))), 
            icons.push(filteringIcon)) : icons.some((icon => isIconEqual(icon, filterIcon))) || (icons = icons.filter((icon => !isIconEqual(icon, filteringIcon))), 
            icons.push(filterIcon)) : icons = icons.filter((icon => !isIconEqual(icon, filterIcon))), 
            column.headerIcon = 0 === (list = icons).length ? void 0 : 1 === list.length ? list[0] : list;
        }));
    }
    shouldEnableFilterForColumn(field, column) {
        if (!column.title) return !1;
        const columnWithFilter = column;
        return void 0 !== columnWithFilter.filter ? !!columnWithFilter.filter : this.pluginOptions.enableFilter ? this.pluginOptions.enableFilter(field, column) : void 0 === this.pluginOptions.defaultEnabled || this.pluginOptions.defaultEnabled;
    }
    getFilterState() {
        if (!this.filterStateManager) return null;
        const state = this.filterStateManager.getAllFilterStates(), serializedState = {};
        return state.filters.forEach(((config, field) => {
            serializedState[field] = {
                enable: config.enable,
                field: config.field,
                type: config.type,
                values: config.values,
                operator: config.operator,
                condition: config.condition
            };
        })), {
            filters: serializedState
        };
    }
    setFilterState(filterState) {
        this.filterStateManager && (this.filterStateManager.dispatch({
            type: FilterActionType.CLEAR_ALL_FILTERS,
            payload: {}
        }), filterState && filterState.filters && Object.entries(filterState.filters).forEach((([, config]) => {
            config.enable && this.filterStateManager.dispatch({
                type: FilterActionType.ADD_FILTER,
                payload: {
                    field: config.field,
                    type: config.type,
                    values: config.values,
                    operator: config.operator,
                    condition: config.condition,
                    enable: !0
                }
            });
        })));
    }
    release() {
        this.columns.forEach((column => {
            column.headerIcon = void 0;
        })), this.table = null, this.filterEngine = null, this.filterStateManager = null, 
        this.filterToolbar.destroy(), this.filterToolbar = null;
    }
}