import { createDomElement, extend } from '@slickgrid-universal/utils';
import { SlickEventHandler, SlickGroup } from '../core/index.js';
/**
 * Provides item metadata for group (SlickGroup) and totals (SlickTotals) rows produced by the DataView.
 * This metadata overrides the default behavior and formatting of those rows so that they appear and function
 * correctly when processed by the grid.
 *
 * This class also acts as a grid plugin providing event handlers to expand & collapse groups.
 * If "grid.registerPlugin(...)" is not called, expand & collapse will not work.
 */
export class SlickGroupItemMetadataProvider {
    constructor(inputOptions) {
        this.pluginName = 'GroupItemMetadataProvider';
        this._defaults = {
            groupCssClass: 'slick-group',
            groupTitleCssClass: 'slick-group-title',
            totalsCssClass: 'slick-group-totals',
            groupFocusable: true,
            indentation: 15,
            totalsFocusable: false,
            toggleCssClass: 'slick-group-toggle',
            toggleExpandedCssClass: 'expanded',
            toggleCollapsedCssClass: 'collapsed',
            enableExpandCollapse: true,
            groupFormatter: this.defaultGroupCellFormatter.bind(this),
            totalsFormatter: this.defaultTotalsCellFormatter.bind(this),
            includeHeaderTotals: false,
        };
        this._eventHandler = new SlickEventHandler();
        this._options = extend(true, {}, this._defaults, inputOptions);
    }
    /** Getter of the SlickGrid Event Handler */
    get eventHandler() {
        return this._eventHandler;
    }
    /** Getter of SlickGrid DataView object */
    get dataView() {
        return this._grid?.getData() ?? {};
    }
    get gridOptions() {
        return this._grid?.getOptions() || {};
    }
    init(grid, inputOptions) {
        this._grid = grid;
        this._options = { ...this._defaults, ...inputOptions };
        this._eventHandler.subscribe(grid.onClick, this.handleGridClick.bind(this));
        this._eventHandler.subscribe(grid.onKeyDown, this.handleGridKeyDown.bind(this));
    }
    destroy() {
        this.dispose();
    }
    dispose() {
        // unsubscribe all SlickGrid events
        this._eventHandler?.unsubscribeAll();
    }
    getOptions() {
        return this._options;
    }
    setOptions(inputOptions) {
        this._options = { ...this._options, ...inputOptions };
    }
    getGroupRowMetadata(item, _row) {
        return {
            selectable: false,
            focusable: this._options.groupFocusable,
            cssClasses: `${this._options.groupCssClass} slick-group-level-${item?.level || 0}`,
            formatter: (this._options.includeHeaderTotals && this._options.totalsFormatter) || undefined,
            columns: {
                0: {
                    colspan: this._options.includeHeaderTotals ? '1' : '*',
                    formatter: this._options.groupFormatter,
                    editorClass: null,
                },
            },
        };
    }
    // prettier-ignore
    getTotalsRowMetadata(item, _row) {
        return {
            selectable: false,
            focusable: this._options.totalsFocusable,
            cssClasses: `${this._options.totalsCssClass} slick-group-level-${item?.group?.level || 0}`,
            formatter: this._options.totalsFormatter,
            editorClass: null,
        };
    }
    //
    // protected functions
    // -------------------
    defaultGroupCellFormatter(_row, _cell, _value, _columnDef, item) {
        if (!this._options.enableExpandCollapse) {
            return item.title;
        }
        const groupLevel = item.level || 0;
        const indentation = this._options?.indentation ?? 15;
        const marginLeft = `${groupLevel * indentation}px`;
        const toggleClass = item.collapsed ? this._options.toggleCollapsedCssClass : this._options.toggleExpandedCssClass;
        // use a DocumentFragment to avoid creating an extra div container
        const containerElm = this.gridOptions?.preventDocumentFragmentUsage ? document.createElement('span') : new DocumentFragment();
        // 1. group toggle span
        containerElm.appendChild(createDomElement('span', {
            className: `${this._options.toggleCssClass} ${toggleClass}`,
            ariaExpanded: String(!item.collapsed),
            style: { marginLeft },
        }));
        // 2. group title span
        const groupTitleElm = createDomElement('span', { className: this._options.groupTitleCssClass || '' });
        groupTitleElm.setAttribute('level', groupLevel);
        item.title instanceof HTMLElement || item.title instanceof DocumentFragment
            ? groupTitleElm.appendChild(item.title)
            : this._grid.applyHtmlCode(groupTitleElm, item.title ?? '');
        containerElm.appendChild(groupTitleElm);
        return containerElm;
    }
    defaultTotalsCellFormatter(_row, _cell, _value, columnDef, item, grid) {
        return columnDef?.groupTotalsFormatter?.(item, columnDef, grid) ?? '';
    }
    /** Handle a grid cell clicked, it could be a Group that is being collapsed/expanded or do nothing when it's not */
    handleGridClick(e, args) {
        const target = e.target;
        const item = this._grid?.getDataItem(args.row);
        if (item instanceof SlickGroup && target.classList.contains(this._options.toggleCssClass || '')) {
            this.handleDataViewExpandOrCollapse(item);
            e.stopImmediatePropagation();
            e.preventDefault();
        }
    }
    /**
     * Handle a keyboard down event on a grouping cell.
     * TODO:  add -/+ handling
     */
    handleGridKeyDown(e) {
        if (this._options.enableExpandCollapse && e.key === ' ') {
            const activeCell = this._grid?.getActiveCell();
            if (activeCell) {
                const item = this._grid.getDataItem(activeCell.row);
                if (item instanceof SlickGroup) {
                    this.handleDataViewExpandOrCollapse(item);
                    e.stopImmediatePropagation();
                    e.preventDefault();
                }
            }
        }
    }
    handleDataViewExpandOrCollapse(item) {
        const range = this._grid?.getRenderedRange();
        this.dataView.setRefreshHints({
            ignoreDiffsBefore: range.top,
            ignoreDiffsAfter: range.bottom + 1,
        });
        if (item.collapsed) {
            this.dataView.expandGroup(item.groupingKey);
        }
        else {
            this.dataView.collapseGroup(item.groupingKey);
        }
    }
}
//# sourceMappingURL=slickGroupItemMetadataProvider.js.map