import * as i0 from '@angular/core';
import { input, model, output, viewChild, signal, computed, forwardRef, ChangeDetectionStrategy, Component } from '@angular/core';
import { NG_VALUE_ACCESSOR } from '@angular/forms';
import { listenGlobal, isRTL } from '@siemens/element-ng/common';
import { SiIconComponent } from '@siemens/element-ng/icon';
import { SiTranslatePipe } from '@siemens/element-translate-ng/translate';

/**
 * Copyright (c) Siemens 2016 - 2026
 * SPDX-License-Identifier: MIT
 */
class SiStatusToggleComponent {
    /** List of status items. */
    items = input.required(...(ngDevMode ? [{ debugName: "items" }] : []));
    /**
     * Disabled state for the whole component.
     * @defaultValue false
     **/
    disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
    /** Value of currently selected status item. */
    value = model(...(ngDevMode ? [undefined, { debugName: "value" }] : []));
    /** Emitted when an item is clicked. */
    itemClick = output();
    containerElement = viewChild.required('container');
    draggableElement = viewChild.required('draggable');
    boundingX = 0;
    x0 = 0;
    offset0 = 0;
    onChange;
    onTouched;
    unlistenDragEvents = [];
    internalDisabled = signal(false, ...(ngDevMode ? [{ debugName: "internalDisabled" }] : []));
    selectedIndex = signal(undefined, ...(ngDevMode ? [{ debugName: "selectedIndex" }] : []));
    draggablePosition = signal('', ...(ngDevMode ? [{ debugName: "draggablePosition" }] : []));
    animated = signal(false, ...(ngDevMode ? [{ debugName: "animated" }] : []));
    isDisabled = computed(() => this.disabled() || this.internalDisabled(), ...(ngDevMode ? [{ debugName: "isDisabled" }] : []));
    ngOnChanges(changes) {
        if (changes.value) {
            this.setValue(this.value(), true, false);
        }
    }
    ngOnInit() {
        const selectedIndex = this.items().findIndex(v => v.value === this.value());
        if (selectedIndex >= 0) {
            this.selectItem(selectedIndex, false, false);
        }
    }
    ngOnDestroy() {
        this.handleDragEnd();
    }
    /** @internal */
    writeValue(value) {
        this.setValue(value, true, false);
    }
    /** @internal */
    registerOnChange(fn) {
        this.onChange = fn;
    }
    /** @internal */
    registerOnTouched(fn) {
        this.onTouched = fn;
    }
    /** @internal */
    setDisabledState(isDisabled) {
        this.internalDisabled.set(isDisabled);
    }
    handleMouseDown(event) {
        if (this.isDisabled() || event.buttons !== 1) {
            return;
        }
        if (this.handleDragStart(event)) {
            this.unlistenDragEvents.push(listenGlobal('mousemove', e => this.handleDragMove(e)));
            this.unlistenDragEvents.push(listenGlobal('mouseup', e => this.handleDragEnd(e)));
        }
    }
    handleTouchStart(event) {
        if (event.touches.length !== 1 || this.disabled()) {
            return;
        }
        if (this.handleDragStart(event)) {
            this.unlistenDragEvents.push(listenGlobal('touchmove', e => this.handleDragMove(e), true));
            this.unlistenDragEvents.push(listenGlobal('touchend', e => this.handleDragEnd(e)));
        }
    }
    handleDragStart(event) {
        const rect = this.containerElement().nativeElement.getBoundingClientRect();
        this.boundingX = rect.x;
        const draggable = this.draggableElement().nativeElement;
        this.offset0 = draggable.offsetLeft;
        this.x0 = this.getX(event);
        // adjust for click outside current selection
        const clickIndex = this.getUnderlyingIndex(this.x0, true);
        const currentIndex = this.getUnderlyingIndex(this.offset0);
        const factor = isRTL() ? -1 : 1;
        this.offset0 += (clickIndex - currentIndex) * draggable.offsetWidth * factor;
        this.handleDragMove(event);
        return true;
    }
    handleDragEnd(event) {
        this.arrangeToUnderlyingItem(event);
        this.unlistenDragEvents.forEach(handler => handler());
        this.unlistenDragEvents.length = 0;
    }
    getOffset(event, isStart = false) {
        const containerWidth = this.containerElement().nativeElement.clientWidth;
        const draggableWidth = this.draggableElement().nativeElement.clientWidth;
        const dX = this.getX(event) - this.x0;
        const left = Math.min(Math.max(0, this.offset0 + dX), containerWidth - draggableWidth);
        return isStart && isRTL() ? containerWidth - draggableWidth - left : left;
    }
    getUnderlyingIndex(offsetLeft, floor = false) {
        const pos = offsetLeft / this.draggableElement().nativeElement.clientWidth;
        const element = floor ? Math.floor(pos) : Math.round(pos);
        const len = this.items().length;
        const index = isRTL() ? len - element - 1 : element;
        return Math.max(0, Math.min(len - 1, index));
    }
    arrangeToUnderlyingItem(event) {
        if (event && !this.isDisabled()) {
            const index = this.getUnderlyingIndex(this.getOffset(event));
            this.selectItem(this.items()[index].disabled ? this.selectedIndex() : index);
            this.onTouched?.();
        }
    }
    handleDragMove(event) {
        if (event.cancelable) {
            event.preventDefault();
            event.stopPropagation();
        }
        this.draggablePosition.set(`${this.getOffset(event, true)}px`);
        this.animated.set(false);
    }
    getX(event) {
        const clientX = event.clientX ?? event.changedTouches[0]?.clientX ?? 0;
        return clientX - this.boundingX;
    }
    setValue(val, animated = true, emit = false) {
        this.selectItem(this.items().findIndex(v => v.value === val), animated, emit);
    }
    selectItem(index, animated = true, emit = true) {
        if (index === undefined || index === -1 || this.isDisabled()) {
            return;
        }
        const values = this.items();
        const value = values[index];
        if (!value.disabled) {
            const prevIndex = this.selectedIndex();
            this.value.set(value.value);
            this.animated.set(animated);
            this.selectedIndex.set(index);
            this.draggablePosition.set(`${(100 / values.length) * index}%`);
            if (emit && index !== prevIndex) {
                if (this.onChange) {
                    this.onChange(this.value());
                }
            }
            if (emit) {
                this.itemClick.emit(this.value());
            }
        }
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiStatusToggleComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
    static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.8", type: SiStatusToggleComponent, isStandalone: true, selector: "si-status-toggle", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: true, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", itemClick: "itemClick" }, providers: [
            {
                provide: NG_VALUE_ACCESSOR,
                // eslint-disable-next-line @angular-eslint/no-forward-ref
                useExisting: forwardRef(() => SiStatusToggleComponent),
                multi: true
            }
        ], viewQueries: [{ propertyName: "containerElement", first: true, predicate: ["container"], descendants: true, isSignal: true }, { propertyName: "draggableElement", first: true, predicate: ["draggable"], descendants: true, isSignal: true }], usesOnChanges: true, ngImport: i0, template: "<div\n  #container\n  role=\"radiogroup\"\n  class=\"status-toggle-container\"\n  [class.disabled]=\"isDisabled()\"\n  (mousedown)=\"handleMouseDown($event)\"\n  (touchstart)=\"handleTouchStart($event)\"\n>\n  @let itemsValue = items();\n  <div\n    #draggable\n    class=\"toggle-draggable\"\n    [class.animated]=\"animated()\"\n    [class.disabled]=\"isDisabled()\"\n    [style.inset-inline-start]=\"draggablePosition()\"\n    [style.width.%]=\"100 / itemsValue.length\"\n  >\n    <div class=\"visible-toggle-draggable\"></div>\n  </div>\n\n  @let selIndexValue = selectedIndex();\n  @for (item of itemsValue; track $index) {\n    <div\n      #items\n      class=\"status-toggle-item focus-inside px-4\"\n      role=\"radio\"\n      [attr.aria-checked]=\"$index === selIndexValue\"\n      [attr.tabindex]=\"isDisabled() || item.disabled ? '' : '0'\"\n      [attr.aria-disabled]=\"isDisabled() || item.disabled\"\n      [class.active]=\"$index === selIndexValue\"\n      [class.disabled]=\"item.disabled || isDisabled()\"\n      [style.width.%]=\"100 / $count\"\n      (keydown.enter)=\"selectItem($index)\"\n    >\n      <span class=\"icon icon-stack\">\n        <si-icon\n          [class]=\"$index === selIndexValue ? (item.activeIconClass ?? 'active') : ''\"\n          [icon]=\"$index === selIndexValue ? (item.activeIcon ?? item.icon) : item.icon\"\n        />\n        @if ($index === selIndexValue && item.activeIconStacked) {\n          <si-icon\n            [class]=\"item.activeIconStackedClass ?? `${item.activeIconClass}-contrast`\"\n            [icon]=\"item.activeIconStacked\"\n          />\n        }\n      </span>\n      <span\n        class=\"text-truncate\"\n        [class]=\"$index === selIndexValue ? (item.activeTextClass ?? 'active') : ''\"\n      >\n        {{ item.text | translate }}\n      </span>\n    </div>\n  }\n</div>\n", styles: [":host{display:block;block-size:48px;border:1px solid var(--element-ui-4);border-radius:var(--element-radius-2);background:var(--element-base-2);padding:2px}.status-toggle-container{position:relative;display:flex;gap:2px;inline-size:100%;block-size:100%;border-radius:var(--element-radius-1);justify-content:space-around;z-index:0;-webkit-user-select:none;user-select:none}.status-toggle-container.disabled .toggle-draggable{display:none}.status-toggle-container.disabled .status-toggle-item{color:var(--element-text-disabled)}.status-toggle-item{display:flex;align-items:center;justify-content:center;flex-direction:column;z-index:10;color:var(--element-text-secondary);border-radius:1px;cursor:pointer}.status-toggle-item.active{color:var(--element-text-primary)!important}.status-toggle-item.disabled{cursor:default;color:var(--element-text-disabled)!important}.status-toggle-item span{max-inline-size:100%;-webkit-user-select:none;user-select:none}.toggle-draggable{position:absolute;inset-block:0;z-index:1;cursor:pointer}.toggle-draggable.animated{transition:all .4s ease}.visible-toggle-draggable{inline-size:100%;block-size:100%;border-radius:1px;background:var(--element-base-1-selected)}\n"], dependencies: [{ kind: "component", type: SiIconComponent, selector: "si-icon", inputs: ["icon"] }, { kind: "pipe", type: SiTranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiStatusToggleComponent, decorators: [{
            type: Component,
            args: [{ selector: 'si-status-toggle', imports: [SiIconComponent, SiTranslatePipe], providers: [
                        {
                            provide: NG_VALUE_ACCESSOR,
                            // eslint-disable-next-line @angular-eslint/no-forward-ref
                            useExisting: forwardRef(() => SiStatusToggleComponent),
                            multi: true
                        }
                    ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div\n  #container\n  role=\"radiogroup\"\n  class=\"status-toggle-container\"\n  [class.disabled]=\"isDisabled()\"\n  (mousedown)=\"handleMouseDown($event)\"\n  (touchstart)=\"handleTouchStart($event)\"\n>\n  @let itemsValue = items();\n  <div\n    #draggable\n    class=\"toggle-draggable\"\n    [class.animated]=\"animated()\"\n    [class.disabled]=\"isDisabled()\"\n    [style.inset-inline-start]=\"draggablePosition()\"\n    [style.width.%]=\"100 / itemsValue.length\"\n  >\n    <div class=\"visible-toggle-draggable\"></div>\n  </div>\n\n  @let selIndexValue = selectedIndex();\n  @for (item of itemsValue; track $index) {\n    <div\n      #items\n      class=\"status-toggle-item focus-inside px-4\"\n      role=\"radio\"\n      [attr.aria-checked]=\"$index === selIndexValue\"\n      [attr.tabindex]=\"isDisabled() || item.disabled ? '' : '0'\"\n      [attr.aria-disabled]=\"isDisabled() || item.disabled\"\n      [class.active]=\"$index === selIndexValue\"\n      [class.disabled]=\"item.disabled || isDisabled()\"\n      [style.width.%]=\"100 / $count\"\n      (keydown.enter)=\"selectItem($index)\"\n    >\n      <span class=\"icon icon-stack\">\n        <si-icon\n          [class]=\"$index === selIndexValue ? (item.activeIconClass ?? 'active') : ''\"\n          [icon]=\"$index === selIndexValue ? (item.activeIcon ?? item.icon) : item.icon\"\n        />\n        @if ($index === selIndexValue && item.activeIconStacked) {\n          <si-icon\n            [class]=\"item.activeIconStackedClass ?? `${item.activeIconClass}-contrast`\"\n            [icon]=\"item.activeIconStacked\"\n          />\n        }\n      </span>\n      <span\n        class=\"text-truncate\"\n        [class]=\"$index === selIndexValue ? (item.activeTextClass ?? 'active') : ''\"\n      >\n        {{ item.text | translate }}\n      </span>\n    </div>\n  }\n</div>\n", styles: [":host{display:block;block-size:48px;border:1px solid var(--element-ui-4);border-radius:var(--element-radius-2);background:var(--element-base-2);padding:2px}.status-toggle-container{position:relative;display:flex;gap:2px;inline-size:100%;block-size:100%;border-radius:var(--element-radius-1);justify-content:space-around;z-index:0;-webkit-user-select:none;user-select:none}.status-toggle-container.disabled .toggle-draggable{display:none}.status-toggle-container.disabled .status-toggle-item{color:var(--element-text-disabled)}.status-toggle-item{display:flex;align-items:center;justify-content:center;flex-direction:column;z-index:10;color:var(--element-text-secondary);border-radius:1px;cursor:pointer}.status-toggle-item.active{color:var(--element-text-primary)!important}.status-toggle-item.disabled{cursor:default;color:var(--element-text-disabled)!important}.status-toggle-item span{max-inline-size:100%;-webkit-user-select:none;user-select:none}.toggle-draggable{position:absolute;inset-block:0;z-index:1;cursor:pointer}.toggle-draggable.animated{transition:all .4s ease}.visible-toggle-draggable{inline-size:100%;block-size:100%;border-radius:1px;background:var(--element-base-1-selected)}\n"] }]
        }], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: true }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], itemClick: [{ type: i0.Output, args: ["itemClick"] }], containerElement: [{ type: i0.ViewChild, args: ['container', { isSignal: true }] }], draggableElement: [{ type: i0.ViewChild, args: ['draggable', { isSignal: true }] }] } });

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

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

export { SiStatusToggleComponent };
//# sourceMappingURL=siemens-element-ng-status-toggle.mjs.map
