import * as i0 from '@angular/core';
import { InjectionToken, isDevMode, Injectable, Optional, Inject, Pipe } from '@angular/core';
import * as i1$1 from '@rxap/data-source';
import { RXAP_DATA_SOURCE_METADATA, RxapDataSourceError } from '@rxap/data-source';
import { AbstractPaginationDataSource, RxapAbstractPaginationDataSource } from '@rxap/data-source/pagination';
import { ToggleSubject } from '@rxap/rxjs';
import { hasIndexSignature, clone, equals } from '@rxap/utilities';
import * as i1 from 'rxjs';
import { BehaviorSubject, combineLatest, of } from 'rxjs';
import { startWith, tap, debounceTime, map, distinctUntilChanged, switchMap, retry } from 'rxjs/operators';

const RXAP_TABLE_DATA_SOURCE_PAGINATOR = new InjectionToken('rxap/data-source/table/paginator');
const RXAP_TABLE_DATA_SOURCE_SORT = new InjectionToken('rxap/data-source/table/sort');
const RXAP_TABLE_DATA_SOURCE_FILTER = new InjectionToken('rxap/data-source/table/filter');
const RXAP_TABLE_DATA_SOURCE_PARAMETERS = new InjectionToken('rxap/data-source/table/parameters');
const RXAP_TABLE_DATA_SOURCE = new InjectionToken('rxap/data-source/table/source');
const RXAP_TABLE_METHOD = new InjectionToken('rxap/data-source/table/table-method');

class AbstractTableDataSource extends AbstractPaginationDataSource {
    constructor(paginator = null, sort = null, filter = null, parameters = null, metadata = null) {
        super(paginator, metadata);
        this.loading$ = new ToggleSubject(true);
        if (parameters) {
            this.parameters = parameters;
        }
        if (sort) {
            this.sort = sort;
        }
        if (filter) {
            this.filter = filter;
        }
    }
    get sortByColumn() {
        return this.sort?.active;
    }
    get sortDirection() {
        return this.sort?.direction;
    }
    get totalRowCount() {
        return this.paginator.length;
    }
    get filterValue() {
        return this.filter?.current;
    }
    applySortBy(data, column, direction) {
        return column ? data.slice().sort((a, b) => {
            if (!hasIndexSignature(a) || !hasIndexSignature(b)) {
                return 0;
            }
            const aColumn = a[column];
            const bColumn = b[column];
            const type = typeof aColumn;
            let sort = 0;
            switch (type) {
                case 'boolean':
                    sort = aColumn === bColumn ? 0 : aColumn ? 1 : -1;
                    break;
                case 'string':
                    sort = aColumn.localeCompare(bColumn);
                    break;
                case 'number':
                case 'bigint':
                    sort = aColumn - bColumn;
                    break;
            }
            return direction === 'desc' ? sort * -1 : sort;
        }) : data.slice();
    }
    applyFilterBy(data, filter) {
        if (filter) {
            if (typeof filter === 'string') {
                if (isDevMode()) {
                    console.error('The filter is a string. Currently not supported by the AbstractTableDataSource');
                }
                return data.slice();
            }
            else {
                return data.filter(row => {
                    return Object.entries(filter).every(([key, value]) => {
                        const type = typeof value;
                        if (row[key] !== undefined && hasIndexSignature(row)) {
                            switch (type) {
                                case 'undefined':
                                    return true;
                                case 'object':
                                    return value === null || value === undefined || value === row[key];
                                case 'boolean':
                                    return value === row[key];
                                case 'number':
                                    return value === row[key];
                                case 'string':
                                    return (row[key] || '').toString().toLowerCase().includes(value.toLowerCase());
                                case 'function':
                                    return value(row[key]);
                                case 'bigint':
                                    return value === row[key];
                            }
                        }
                        return true;
                    });
                });
            }
        }
        else {
            return data.slice();
        }
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.1", ngImport: i0, type: AbstractTableDataSource, deps: [{ token: RXAP_TABLE_DATA_SOURCE_PAGINATOR, optional: true }, { token: RXAP_TABLE_DATA_SOURCE_SORT, optional: true }, { token: RXAP_TABLE_DATA_SOURCE_FILTER, optional: true }, { token: RXAP_TABLE_DATA_SOURCE_PARAMETERS, optional: true }, { token: RXAP_DATA_SOURCE_METADATA, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.1", ngImport: i0, type: AbstractTableDataSource }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.1", ngImport: i0, type: AbstractTableDataSource, decorators: [{
            type: Injectable
        }], ctorParameters: () => [{ type: undefined, decorators: [{
                    type: Optional
                }, {
                    type: Inject,
                    args: [RXAP_TABLE_DATA_SOURCE_PAGINATOR]
                }] }, { type: undefined, decorators: [{
                    type: Optional
                }, {
                    type: Inject,
                    args: [RXAP_TABLE_DATA_SOURCE_SORT]
                }] }, { type: undefined, decorators: [{
                    type: Optional
                }, {
                    type: Inject,
                    args: [RXAP_TABLE_DATA_SOURCE_FILTER]
                }] }, { type: i1.Observable, decorators: [{
                    type: Optional
                }, {
                    type: Inject,
                    args: [RXAP_TABLE_DATA_SOURCE_PARAMETERS]
                }] }, { type: undefined, decorators: [{
                    type: Optional
                }, {
                    type: Inject,
                    args: [RXAP_DATA_SOURCE_METADATA]
                }] }] });
function RxapAbstractTableDataSource(metadataOrId, className = 'AbstractTableDataSource', packageName = '@rxap/data-source/table') {
    return function (target) {
        RxapAbstractPaginationDataSource(metadataOrId, className, packageName)(target);
    };
}

/**
 * @deprecated removed use RXAP_TABLE_METHOD instead
 */
const RXAP_TABLE_REMOTE_METHOD = new InjectionToken('rxap/data-source/table/remote-method');
class DynamicTableDataSource extends AbstractTableDataSource {
    constructor(method, paginator = null, sort = null, filter = null, parameters = null, metadata = method.metadata) {
        super(paginator, sort, filter, parameters, metadata);
        this.method = method;
        this.paginatorMap = new Map();
        this.sortMap = new Map();
        this.filterMap = new Map();
        this.parametersMap = new Map();
        this._refresh$ = new BehaviorSubject(Date.now());
    }
    /**
     * @deprecated use method instead
     * @private
     */
    get remoteMethod() {
        return this.method;
    }
    // eslint-disable-next-line @angular-eslint/contextual-lifecycle
    ngOnInit() {
        this._data$ = this.createTableDataLoader(this.paginator, this.sort, this.filter, this.parameters);
    }
    setTotalLengthFactory(id) {
        const paginator = id ? this.paginatorMap.get(id) : this.paginator;
        function setTotalLength(length) {
            if (paginator) {
                paginator.length = length;
            }
        }
        return setTotalLength;
    }
    setTotalLength(length, id) {
        if (id) {
            if (this.paginatorMap.has(id)) {
                this.paginatorMap.get(id).length = length;
            }
        }
        else {
            if (this.paginator) {
                this.paginator.length = length;
            }
        }
    }
    refresh() {
        this._refresh$.next(Date.now());
    }
    setPaginator(paginator, id) {
        if (paginator) {
            if (id) {
                this.paginatorMap.set(id, paginator);
            }
            else {
                this.paginator = paginator;
            }
        }
    }
    setSort(sort, id) {
        if (sort) {
            if (id) {
                this.sortMap.set(id, sort);
            }
            else {
                this.sort = sort;
            }
        }
    }
    setFilter(tableFilter, id) {
        if (tableFilter) {
            if (id) {
                this.filterMap.set(id, tableFilter);
            }
            else {
                this.filter = tableFilter;
            }
        }
    }
    setParameters(parameters, id) {
        if (parameters) {
            if (id) {
                this.parametersMap.set(id, parameters);
            }
            else {
                this.parameters = parameters;
            }
        }
    }
    genericRetryFunction(error, retryCount) {
        this.loading$.disable();
        return super.genericRetryFunction(error, retryCount);
    }
    _connect(viewer) {
        // call to ensure all parent logic is executed
        let data = super._connect(viewer);
        if (viewer.id && this.hasDynamicInputs(viewer.id)) {
            data = this.createTableDataLoader(this.paginatorMap.get(viewer.id), this.sortMap.get(viewer.id), this.filterMap.get(viewer.id), this.parametersMap.get(viewer.id), viewer.id);
        }
        return data;
    }
    _disconnect(viewerId) {
        if (this.hasDynamicInputs(viewerId)) {
            this.paginatorMap.delete(viewerId);
            this.sortMap.delete(viewerId);
            this.filterMap.delete(viewerId);
            this.parametersMap.delete(viewerId);
        }
        super._disconnect(viewerId);
    }
    async loadPage(tableEvent) {
        try {
            return await this.method.call(tableEvent);
        }
        catch (e) {
            console.error(`Failed to load page: ${e.message}`);
            this.handelError(e);
            this.hasError$.enable();
            this.error$.next(e);
        }
        return [];
    }
    handelError(error) {
        if (isDevMode()) {
            console.error(`Failed to load page: ${error.message}`, error);
        }
    }
    hasDynamicInputs(id) {
        return this.paginatorMap.has(id) || this.sortMap.has(id) || this.filterMap.has(id) || this.parametersMap.has(id);
    }
    createTableDataLoader(paginatorLike, sortLike, filterLike, parametersLike, id) {
        return combineLatest([
            paginatorLike?.page?.pipe(startWith({
                pageIndex: paginatorLike?.pageIndex ?? 0,
                pageSize: paginatorLike?.pageSize ?? Number.MAX_SAFE_INTEGER,
                length: paginatorLike?.length,
            })) ?? of(undefined),
            sortLike?.sortChange?.pipe(startWith({
                active: sortLike?.active,
                direction: sortLike?.direction,
            })) ?? of(undefined),
            filterLike?.change?.pipe(tap(() => paginatorLike?.firstPage && paginatorLike?.firstPage())) ?? of(undefined),
            parametersLike ?? of(undefined),
            this._refresh$,
            this._retry$.pipe(startWith(null)),
        ]).pipe(debounceTime(100), map(([page, sort, filter, parameters, refresh]) => {
            const tableEvent = {
                page,
                start: page ? page.pageSize * page.pageIndex : 0,
                end: page ? page.pageSize * page.pageIndex + page.pageSize : Number.MAX_SAFE_INTEGER,
                sort,
                filter,
                parameters,
                refresh,
            };
            return {
                ...clone(tableEvent),
                setTotalLength: this.setTotalLengthFactory(id),
            };
        }), distinctUntilChanged((a, b) => equals(a, b)), tap(() => {
            this.loading$.enable();
            if (this.hasError$.value) {
                this.hasError$.disable();
            }
        }), switchMap(tableEvent => this.loadPage(tableEvent)), tap({
            next: () => this.loading$.disable(),
            error: error => {
                this.hasError$.enable();
                this.error$.next(error);
                this.handelError(error);
            },
        }), retry({
            delay: (error, retryCount) => this.genericRetryFunction(error, retryCount),
        }));
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.1", ngImport: i0, type: DynamicTableDataSource, deps: [{ token: RXAP_TABLE_METHOD, optional: true }, { token: RXAP_TABLE_DATA_SOURCE_PAGINATOR, optional: true }, { token: RXAP_TABLE_DATA_SOURCE_SORT, optional: true }, { token: RXAP_TABLE_DATA_SOURCE_FILTER, optional: true }, { token: RXAP_TABLE_DATA_SOURCE_PARAMETERS, optional: true }, { token: RXAP_DATA_SOURCE_METADATA, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.1", ngImport: i0, type: DynamicTableDataSource }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.1", ngImport: i0, type: DynamicTableDataSource, decorators: [{
            type: Injectable
        }], ctorParameters: () => [{ type: undefined, decorators: [{
                    type: Optional
                }, {
                    type: Inject,
                    args: [RXAP_TABLE_METHOD]
                }] }, { type: undefined, decorators: [{
                    type: Optional
                }, {
                    type: Inject,
                    args: [RXAP_TABLE_DATA_SOURCE_PAGINATOR]
                }] }, { type: undefined, decorators: [{
                    type: Optional
                }, {
                    type: Inject,
                    args: [RXAP_TABLE_DATA_SOURCE_SORT]
                }] }, { type: undefined, decorators: [{
                    type: Optional
                }, {
                    type: Inject,
                    args: [RXAP_TABLE_DATA_SOURCE_FILTER]
                }] }, { type: i1.Observable, decorators: [{
                    type: Optional
                }, {
                    type: Inject,
                    args: [RXAP_TABLE_DATA_SOURCE_PARAMETERS]
                }] }, { type: undefined, decorators: [{
                    type: Optional
                }, {
                    type: Inject,
                    args: [RXAP_DATA_SOURCE_METADATA]
                }] }] });

class RxapTableDataSourceError extends RxapDataSourceError {
    constructor(message, code, className) {
        super(message, code, className);
        this.addSubPackageName('table');
    }
}

class TableDataSource extends AbstractTableDataSource {
    constructor(dataSource, paginator = null, sort = null, filter = null, parameters = null, metadata = dataSource.metadata) {
        super(paginator, sort, filter, parameters, metadata);
        this.dataSource = dataSource;
    }
    refresh() {
        this.dataSource.refresh();
    }
    _connect(viewer) {
        return [
            this.dataSource.connect(viewer).pipe(tap((data) => this.updateTotalLength(data.length)), tap(() => this.loading$.disable()), switchMap((data) => {
                this.assertPaginator();
                if (this.paginator && this.paginator.page) {
                    return combineLatest([
                        this.paginator.page.pipe(startWith({
                            pageIndex: this.paginator.pageIndex,
                            pageSize: this.paginator.pageSize,
                            length: this.paginator.length,
                        })),
                        this.sort?.sortChange?.pipe(startWith({
                            active: this.sort?.active,
                            direction: this.sort?.direction,
                        })) ?? of(null),
                        this.filter?.change.pipe(startWith({})) ?? of(null),
                    ]).pipe(map(([page, sort, filter]) => {
                        let filteredData = data;
                        if (filter) {
                            filteredData = this.applyFilterBy(filteredData, filter);
                        }
                        let sortData = filteredData;
                        if (sort) {
                            sortData = this.applySortBy(sortData, sort.active, sort.direction);
                        }
                        return this.applyPagination(sortData, page.pageSize, page.pageIndex);
                    }));
                }
                throw new Error('The paginator have not a defined page property!');
            })),
            () => this.dataSource.disconnect(viewer),
        ];
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.1", ngImport: i0, type: TableDataSource, deps: [{ token: RXAP_TABLE_DATA_SOURCE }, { token: RXAP_TABLE_DATA_SOURCE_PAGINATOR, optional: true }, { token: RXAP_TABLE_DATA_SOURCE_SORT, optional: true }, { token: RXAP_TABLE_DATA_SOURCE_FILTER, optional: true }, { token: RXAP_TABLE_DATA_SOURCE_PARAMETERS, optional: true }, { token: RXAP_DATA_SOURCE_METADATA, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.1", ngImport: i0, type: TableDataSource }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.1", ngImport: i0, type: TableDataSource, decorators: [{
            type: Injectable
        }], ctorParameters: () => [{ type: i1$1.BaseDataSource, decorators: [{
                    type: Inject,
                    args: [RXAP_TABLE_DATA_SOURCE]
                }] }, { type: undefined, decorators: [{
                    type: Optional
                }, {
                    type: Inject,
                    args: [RXAP_TABLE_DATA_SOURCE_PAGINATOR]
                }] }, { type: undefined, decorators: [{
                    type: Optional
                }, {
                    type: Inject,
                    args: [RXAP_TABLE_DATA_SOURCE_SORT]
                }] }, { type: undefined, decorators: [{
                    type: Optional
                }, {
                    type: Inject,
                    args: [RXAP_TABLE_DATA_SOURCE_FILTER]
                }] }, { type: i1.Observable, decorators: [{
                    type: Optional
                }, {
                    type: Inject,
                    args: [RXAP_TABLE_DATA_SOURCE_PARAMETERS]
                }] }, { type: undefined, decorators: [{
                    type: Optional
                }, {
                    type: Inject,
                    args: [RXAP_DATA_SOURCE_METADATA]
                }] }] });
function RxapTableDataSource(metadataOrId, className = 'TableDataSource', packageName = '@rxap/data-source/table') {
    return function (target) {
        RxapAbstractTableDataSource(metadataOrId, className, packageName)(target);
    };
}

class ToTableDataSourcePipe {
    transform(dataSource, paginator, sort, filter) {
        return new TableDataSource(dataSource, paginator, sort, filter);
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.1", ngImport: i0, type: ToTableDataSourcePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
    static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "19.2.1", ngImport: i0, type: ToTableDataSourcePipe, isStandalone: true, name: "toTableDataSource" }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.1", ngImport: i0, type: ToTableDataSourcePipe, decorators: [{
            type: Pipe,
            args: [{
                    name: 'toTableDataSource',
                    standalone: true,
                }]
        }] });

// region 
// endregion

/**
 * Generated bundle index. Do not edit.
 */

export { AbstractTableDataSource, DynamicTableDataSource, RXAP_TABLE_DATA_SOURCE, RXAP_TABLE_DATA_SOURCE_FILTER, RXAP_TABLE_DATA_SOURCE_PAGINATOR, RXAP_TABLE_DATA_SOURCE_PARAMETERS, RXAP_TABLE_DATA_SOURCE_SORT, RXAP_TABLE_METHOD, RXAP_TABLE_REMOTE_METHOD, RxapAbstractTableDataSource, RxapTableDataSource, RxapTableDataSourceError, TableDataSource, ToTableDataSourcePipe };
//# sourceMappingURL=rxap-data-source-table.mjs.map
