import * as i0 from '@angular/core';
import { inject, ElementRef, Directive, input, booleanAttribute, signal, computed, contentChildren, contentChild, ChangeDetectorRef, INJECTOR, NgModule } from '@angular/core';
import { ResizeObserverService } from '@siemens/element-ng/resize-observer';
import { map, distinctUntilChanged, shareReplay, switchMap, startWith, auditTime } from 'rxjs/operators';
import { toObservable } from '@angular/core/rxjs-interop';
import { BehaviorSubject, of, combineLatest } from 'rxjs';

/**
 * Copyright (c) Siemens 2016 - 2026
 * SPDX-License-Identifier: MIT
 */
class SiAutoCollapsableListMeasurable {
    elementRef = inject((ElementRef));
    resizeObserverService = inject(ResizeObserverService);
    /**
     * Emits on element width changes.
     *
     * @defaultValue
     * ```
     * this.resizeObserverService
     *       .observe(this.elementRef.nativeElement, 0, true, true)
     *       .pipe(
     *         map(size => size.width),
     *         distinctUntilChanged(),
     *         shareReplay(1)
     *       )
     * ```
     */
    size$ = this.resizeObserverService.observe(this.elementRef.nativeElement, 0, true, true).pipe(map(size => size.width), distinctUntilChanged(), shareReplay(1));
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiAutoCollapsableListMeasurable, deps: [], target: i0.ɵɵFactoryTarget.Directive });
    static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.0.8", type: SiAutoCollapsableListMeasurable, isStandalone: true, ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiAutoCollapsableListMeasurable, decorators: [{
            type: Directive
        }] });

/**
 * Copyright (c) Siemens 2016 - 2026
 * SPDX-License-Identifier: MIT
 */
class SiAutoCollapsableListItemDirective extends SiAutoCollapsableListMeasurable {
    /**
     * Hide this item even if enough space is available.
     * When calculating the overall available size, this item is still considered when forceHide=true
     *
     * @defaultValue false
     */
    forceHide = input(false, { ...(ngDevMode ? { debugName: "forceHide" } : {}), transform: booleanAttribute });
    /**
     * True if enough space is available for this item.
     *
     * @defaultValue false
     */
    canBeVisible = signal(false, ...(ngDevMode ? [{ debugName: "canBeVisible" }] : []));
    /**
     * True if this item is actually visible to the user
     */
    isVisible = computed(() => this.canBeVisible() && !this.forceHide(), ...(ngDevMode ? [{ debugName: "isVisible" }] : []));
    ngAfterViewInit() {
        if (getComputedStyle(this.elementRef.nativeElement).display === 'inline') {
            console.error('siAutoCollapsibleListItem does not work on items with display="inline"');
        }
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiAutoCollapsableListItemDirective, deps: null, target: i0.ɵɵFactoryTarget.Directive });
    static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.0.8", type: SiAutoCollapsableListItemDirective, isStandalone: true, selector: "[siAutoCollapsableListItem]", inputs: { forceHide: { classPropertyName: "forceHide", publicName: "forceHide", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "style.visibility": "isVisible() ? \"visible\" : \"hidden\"", "style.position": "isVisible() ? \"\" : \"absolute\"", "style.z-index": "isVisible() ? \"\" : \"-1\"" } }, exportAs: ["siAutoCollapsableListItem"], usesInheritance: true, ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiAutoCollapsableListItemDirective, decorators: [{
            type: Directive,
            args: [{
                    selector: '[siAutoCollapsableListItem]',
                    host: {
                        '[style.visibility]': 'isVisible() ? "visible" : "hidden"',
                        '[style.position]': 'isVisible() ? "" : "absolute"',
                        // Ensure hidden items are behind the visible ones. Otherwise, the visible ones are not clickable
                        '[style.z-index]': 'isVisible() ? "" : "-1"'
                    },
                    exportAs: 'siAutoCollapsableListItem'
                }]
        }], propDecorators: { forceHide: [{ type: i0.Input, args: [{ isSignal: true, alias: "forceHide", required: false }] }] } });

/**
 * Copyright (c) Siemens 2016 - 2026
 * SPDX-License-Identifier: MIT
 */
class SiAutoCollapsableListAdditionalContentDirective extends SiAutoCollapsableListMeasurable {
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiAutoCollapsableListAdditionalContentDirective, deps: null, target: i0.ɵɵFactoryTarget.Directive });
    static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.0.8", type: SiAutoCollapsableListAdditionalContentDirective, isStandalone: true, selector: "[siAutoCollapsableListAdditionalContent]", usesInheritance: true, ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiAutoCollapsableListAdditionalContentDirective, decorators: [{
            type: Directive,
            args: [{
                    selector: '[siAutoCollapsableListAdditionalContent]'
                }]
        }] });

/**
 * Copyright (c) Siemens 2016 - 2026
 * SPDX-License-Identifier: MIT
 */
class SiAutoCollapsableListOverflowItemDirective extends SiAutoCollapsableListItemDirective {
    /**
     * Number of hidden items.
     *
     * @defaultValue 0
     */
    hiddenItemCount = 0;
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiAutoCollapsableListOverflowItemDirective, deps: null, target: i0.ɵɵFactoryTarget.Directive });
    static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.0.8", type: SiAutoCollapsableListOverflowItemDirective, isStandalone: true, selector: "[siAutoCollapsableListOverflowItem]", exportAs: ["siAutoCollapsableListOverflowItem"], usesInheritance: true, ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiAutoCollapsableListOverflowItemDirective, decorators: [{
            type: Directive,
            args: [{
                    selector: '[siAutoCollapsableListOverflowItem]',
                    exportAs: 'siAutoCollapsableListOverflowItem'
                }]
        }] });

/**
 * Copyright (c) Siemens 2016 - 2026
 * SPDX-License-Identifier: MIT
 */
class SiAutoCollapsableListDirective {
    /**
     * The items which are displayed in the siAutoCollapsableList.
     */
    items = contentChildren(SiAutoCollapsableListItemDirective, ...(ngDevMode ? [{ debugName: "items" }] : []));
    overflowItem = contentChild(SiAutoCollapsableListOverflowItemDirective, ...(ngDevMode ? [{ debugName: "overflowItem" }] : []));
    additionalContent = contentChildren(SiAutoCollapsableListAdditionalContentDirective, ...(ngDevMode ? [{ debugName: "additionalContent" }] : []));
    /** @defaultValue true */
    siAutoCollapsableList = input(true, { ...(ngDevMode ? { debugName: "siAutoCollapsableList" } : {}), transform: booleanAttribute });
    /**
     * The (flex) gap in pixels, will automatically be set if a pixel value is used in CSS.
     */
    gap = input(...(ngDevMode ? [undefined, { debugName: "gap" }] : []));
    /**
     * The element which size is available for the content of the siAutoCollapsableList.
     *
     * @defaultValue undefined
     */
    containerElement = input(undefined, { ...(ngDevMode ? { debugName: "containerElement" } : {}), alias: 'siAutoCollapsableListContainerElement' });
    resizeSubscription;
    disableInitSubscription;
    elementRef = inject(ElementRef);
    resizeObserverService = inject(ResizeObserverService);
    changeDetectorRef = inject(ChangeDetectorRef);
    containerElementSubject = new BehaviorSubject(this.elementRef.nativeElement);
    /**
     * The same as {@link gap}, but automatically read from the computed styles.
     * Used if not set by user.
     */
    computedGap = 0;
    injector = inject(INJECTOR);
    ngAfterViewInit() {
        if (this.siAutoCollapsableList()) {
            this.readGapSize();
            this.setupResizeListener();
        }
        else {
            this.reset();
        }
    }
    ngOnChanges(changes) {
        if (changes.siAutoCollapsableList) {
            const siAutoCollapsableList = this.siAutoCollapsableList();
            if (!siAutoCollapsableList && this.resizeSubscription) {
                this.reset();
            }
            else if (siAutoCollapsableList && !this.resizeSubscription && this.items()) {
                this.setupResizeListener();
            }
        }
        if (changes.containerElement) {
            this.containerElementSubject.next(this.containerElement() ?? this.elementRef.nativeElement);
        }
    }
    ngOnDestroy() {
        this.resizeSubscription?.unsubscribe();
        this.disableInitSubscription?.unsubscribe();
        this.containerElementSubject.complete();
    }
    setupResizeListener() {
        this.disableInitSubscription?.unsubscribe();
        const containerSize$ = this.containerElementSubject.pipe(switchMap(element => this.resizeObserverService.observe(element, 0, true, true)), map(size => size.width), distinctUntilChanged(), map(size => {
            const { paddingInlineStart, paddingInlineEnd } = getComputedStyle(this.containerElement() ?? this.elementRef.nativeElement);
            return size - parseFloat(paddingInlineStart) - parseFloat(paddingInlineEnd);
        }));
        const itemSizes$ = toObservable(this.items, { injector: this.injector }).pipe(startWith(this.items()), switchMap(items => !items.length
            ? of([])
            : combineLatest(items.map(item => item.size$.pipe(map(size => ({
                size,
                directive: item
            })))))));
        const additionalContentSizes$ = toObservable(this.additionalContent, {
            injector: this.injector
        }).pipe(startWith(this.additionalContent()), switchMap(additionalContent => combineLatest(additionalContent.map(item => item.size$))), startWith([]));
        this.resizeSubscription = combineLatest([
            containerSize$,
            this.overflowItem()?.size$ ?? of(0),
            itemSizes$,
            additionalContentSizes$
        ])
            .pipe(auditTime(0))
            .subscribe(([containerSize, overflowItemSize, items, additionalContentSizes]) => this.updateItemVisibility(containerSize, overflowItemSize, items, additionalContentSizes));
    }
    updateItemVisibility(containerSize, overflowItemSize, items, additionalContent) {
        let remainingSpace = containerSize - additionalContent.reduce((a, b) => a + b, 0);
        const itemsRemaining = items.slice();
        const gap = this.gap() ?? this.computedGap;
        while (remainingSpace > 0 && itemsRemaining.length) {
            const item = itemsRemaining.shift();
            if (remainingSpace - item.size - gap - overflowItemSize >= 0) {
                // There is space for the item and an overflow item.
                item.directive.canBeVisible.set(true);
                remainingSpace -= item.size + gap;
            }
            else if (!itemsRemaining.length &&
                (remainingSpace - item.size >= 0 || overflowItemSize >= item.size)) {
                // There are no other items remaining and there is enough space or the overflow item is biggger than the current one.
                item.directive.canBeVisible.set(true);
                remainingSpace = 0;
            }
            else {
                // There is no space for the item.
                remainingSpace = 0;
                item.directive.canBeVisible.set(false);
            }
        }
        itemsRemaining.forEach(item => item.directive.canBeVisible.set(false));
        const overflowItem = this.overflowItem();
        if (overflowItem) {
            overflowItem.hiddenItemCount = this.items().filter(item => !item.canBeVisible()).length;
            overflowItem.canBeVisible.set(overflowItem.hiddenItemCount !== 0);
        }
        this.changeDetectorRef.markForCheck();
    }
    reset() {
        this.resizeSubscription?.unsubscribe();
        this.resizeSubscription = undefined;
        this.disableInitSubscription = toObservable(this.items, { injector: this.injector }).subscribe(items => queueMicrotask(() => {
            items.forEach(item => item.canBeVisible.set(true));
        }));
        const overflowItem = this.overflowItem();
        if (overflowItem) {
            queueMicrotask(() => {
                overflowItem.canBeVisible.set(false);
                overflowItem.hiddenItemCount = 0;
            });
        }
    }
    readGapSize() {
        const { gap } = getComputedStyle(this.containerElement() ?? this.elementRef.nativeElement);
        if (gap.endsWith('px') || gap === '0') {
            this.computedGap = parseFloat(gap);
        }
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiAutoCollapsableListDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
    static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.2.0", version: "21.0.8", type: SiAutoCollapsableListDirective, isStandalone: true, selector: "[siAutoCollapsableList]", inputs: { siAutoCollapsableList: { classPropertyName: "siAutoCollapsableList", publicName: "siAutoCollapsableList", isSignal: true, isRequired: false, transformFunction: null }, gap: { classPropertyName: "gap", publicName: "gap", isSignal: true, isRequired: false, transformFunction: null }, containerElement: { classPropertyName: "containerElement", publicName: "siAutoCollapsableListContainerElement", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "style.overflow": "siAutoCollapsableList() ? \"hidden\" : \"\"" }, styleAttribute: "position: relative" }, queries: [{ propertyName: "items", predicate: SiAutoCollapsableListItemDirective, isSignal: true }, { propertyName: "overflowItem", first: true, predicate: SiAutoCollapsableListOverflowItemDirective, descendants: true, isSignal: true }, { propertyName: "additionalContent", predicate: SiAutoCollapsableListAdditionalContentDirective, isSignal: true }], exportAs: ["siAutoCollapsableList"], usesOnChanges: true, ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiAutoCollapsableListDirective, decorators: [{
            type: Directive,
            args: [{
                    selector: '[siAutoCollapsableList]',
                    host: {
                        style: 'position: relative',
                        '[style.overflow]': 'siAutoCollapsableList() ? "hidden" : ""'
                    },
                    exportAs: 'siAutoCollapsableList'
                }]
        }], propDecorators: { items: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => SiAutoCollapsableListItemDirective), { isSignal: true }] }], overflowItem: [{ type: i0.ContentChild, args: [i0.forwardRef(() => SiAutoCollapsableListOverflowItemDirective), { isSignal: true }] }], additionalContent: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => SiAutoCollapsableListAdditionalContentDirective), { isSignal: true }] }], siAutoCollapsableList: [{ type: i0.Input, args: [{ isSignal: true, alias: "siAutoCollapsableList", required: false }] }], gap: [{ type: i0.Input, args: [{ isSignal: true, alias: "gap", required: false }] }], containerElement: [{ type: i0.Input, args: [{ isSignal: true, alias: "siAutoCollapsableListContainerElement", required: false }] }] } });

/**
 * Copyright (c) Siemens 2016 - 2026
 * SPDX-License-Identifier: MIT
 */
class SiAutoCollapsableListModule {
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiAutoCollapsableListModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
    static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.0.8", ngImport: i0, type: SiAutoCollapsableListModule, imports: [SiAutoCollapsableListAdditionalContentDirective,
            SiAutoCollapsableListDirective,
            SiAutoCollapsableListItemDirective,
            SiAutoCollapsableListOverflowItemDirective], exports: [SiAutoCollapsableListAdditionalContentDirective,
            SiAutoCollapsableListDirective,
            SiAutoCollapsableListItemDirective,
            SiAutoCollapsableListOverflowItemDirective] });
    static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiAutoCollapsableListModule });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiAutoCollapsableListModule, decorators: [{
            type: NgModule,
            args: [{
                    imports: [
                        SiAutoCollapsableListAdditionalContentDirective,
                        SiAutoCollapsableListDirective,
                        SiAutoCollapsableListItemDirective,
                        SiAutoCollapsableListOverflowItemDirective
                    ],
                    exports: [
                        SiAutoCollapsableListAdditionalContentDirective,
                        SiAutoCollapsableListDirective,
                        SiAutoCollapsableListItemDirective,
                        SiAutoCollapsableListOverflowItemDirective
                    ]
                }]
        }] });

/**
 * Copyright (c) Siemens 2016 - 2026
 * SPDX-License-Identifier: MIT
 */

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

export { SiAutoCollapsableListAdditionalContentDirective, SiAutoCollapsableListDirective, SiAutoCollapsableListItemDirective, SiAutoCollapsableListMeasurable, SiAutoCollapsableListModule, SiAutoCollapsableListOverflowItemDirective };
//# sourceMappingURL=siemens-element-ng-auto-collapsable-list.mjs.map
