import { MXInputBaseValueComponent, MXLookComponent, AXAutocompleteParentComponent, AXComponent, AXValuableComponent, AXFocusableComponent, AXClearableComponent } from '@acorex/cdk/common';
import { AXAutocompleteComponent } from '@acorex/components/autocomplete';
import { AXDecoratorGenericComponent, AXDecoratorIconComponent } from '@acorex/components/decorators';
import { AXTagComponent } from '@acorex/components/tag';
import { AXUnsubscriber } from '@acorex/core/utils';
import { NgTemplateOutlet } from '@angular/common';
import * as i0 from '@angular/core';
import { inject, signal, input, output, contentChild, forwardRef, HostBinding, ChangeDetectionStrategy, ViewEncapsulation, Component, NgModule } from '@angular/core';
import * as i1 from '@angular/forms';
import { FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms';
import { get, isNil, cloneDeep, castArray, set, isNull } from 'lodash-es';
import { classes } from 'polytype';

class AXTagBoxComponent extends classes((MXInputBaseValueComponent), MXLookComponent, (AXAutocompleteParentComponent)) {
    constructor() {
        super(...arguments);
        this.unsubscriber = inject(AXUnsubscriber);
        this.updateOn = signal('change', ...(ngDevMode ? [{ debugName: "updateOn" }] : []));
        this.addOnComma = input(true, ...(ngDevMode ? [{ debugName: "addOnComma" }] : []));
        this.addOnEnter = input(true, ...(ngDevMode ? [{ debugName: "addOnEnter" }] : []));
        this.valueField = input('id', ...(ngDevMode ? [{ debugName: "valueField" }] : []));
        this.textField = input('text', ...(ngDevMode ? [{ debugName: "textField" }] : []));
        this.readonlyField = input('readonly', ...(ngDevMode ? [{ debugName: "readonlyField" }] : []));
        this.allowDuplicateValues = input(false, ...(ngDevMode ? [{ debugName: "allowDuplicateValues" }] : []));
        this.tagTemplate = input(...(ngDevMode ? [undefined, { debugName: "tagTemplate" }] : []));
        this.onTagClick = output();
        this.onTagDblClick = output();
        this.onTagContextMenu = output();
        this.inputValue = signal('', ...(ngDevMode ? [{ debugName: "inputValue" }] : []));
        this.autocompleteComponent = contentChild(AXAutocompleteComponent, ...(ngDevMode ? [{ debugName: "autocompleteComponent" }] : []));
    }
    ngOnInit() {
        super.ngOnInit();
        this.onKeyDown.pipe(this.unsubscriber.takeUntilDestroy).subscribe((e) => {
            const input = this.inputValue().trim();
            if (e.nativeEvent.key === 'Enter' && this.addOnEnter()) {
                if (!input.length)
                    return;
                this.addItems(this.convertString(input));
            }
            if (e.nativeEvent.key === ',' && this.addOnComma()) {
                if (!input.length)
                    return;
                e.nativeEvent.preventDefault();
                if (!input || input === ',') {
                    this.inputValue.set('');
                    this.emitOnTextChanged('', true);
                    return;
                }
                this.addItems(this.convertString(input));
            }
            if (e.nativeEvent.key === 'Backspace') {
                if (this.inputValue().length)
                    return;
                this.removeItem(this.value?.length - 1);
            }
        });
        this.onItemSelected.pipe(this.unsubscriber.takeUntilDestroy).subscribe((e) => {
            const incomingItems = this.convertString(e.value);
            const currentValue = this.value ?? [];
            const vf = this.valueField();
            const filtered = incomingItems.filter((item) => !currentValue.some((prev) => get(prev, vf) === get(item, vf)));
            this.addItems(filtered);
        });
    }
    /**
     * Adds items to the tag box.
     *
     * @param items - Array of objects to add as tags
     */
    addItems(items) {
        if (this.disabled || this.readonly) {
            return;
        }
        //
        if (isNil(items) || items.length === 0) {
            return;
        }
        //
        const value = cloneDeep(this.value ?? []);
        // filter out duplicates instead of early return
        let itemsToAdd = items;
        if (!this.allowDuplicateValues()) {
            const vf = this.valueField();
            itemsToAdd = items.filter((item) => !value.some((prev) => get(prev, vf) === get(item, vf)));
            if (itemsToAdd.length === 0) {
                this.inputValue.set('');
                this.emitOnTextChanged('', true);
                return;
            }
        }
        this.inputValue.set('');
        this.emitOnTextChanged('', true);
        this.commitValue(value.concat(itemsToAdd), true);
        // sync autocomplete selection to avoid re-adding removed items
        this.syncAutocompleteSelection();
    }
    /**
     * Removes a tag at the specified index.
     *
     * @param index - Index of the tag to remove
     */
    removeItem(index) {
        if (this.disabled || this.readonly) {
            return;
        }
        const value = cloneDeep(this.value ?? []);
        value.splice(index, 1);
        this.commitValue(value, true);
        // sync autocomplete selection to avoid re-adding removed items
        this.syncAutocompleteSelection();
    }
    /**
     * Converts input values to tag objects.
     *
     * @param v - Value to convert (string, object, or array)
     * @returns Array of tag objects
     */
    convertString(v) {
        const array = castArray(v);
        return array
            .map((c) => {
            if (!c)
                return null;
            if (typeof c === 'object') {
                return c;
            }
            const obj = {};
            set(obj, this.valueField(), c);
            set(obj, this.textField(), c);
            return obj;
        })
            .filter((c) => !isNull(c));
    }
    getFieldValue(item, path) {
        return get(item, path);
    }
    /**
     * Keep autocomplete selected values in sync with current tags
     */
    syncAutocompleteSelection() {
        const ac = this.autocompleteComponent();
        if (!ac)
            return;
        const vf = ac.valueField || this.valueField();
        const values = (this.value ?? []).map((t) => get(t, vf)).filter((v) => v != null);
        ac.value = ac.multiple ? values : (values[0] ?? null);
    }
    internalSetValue(value) {
        const result = this.convertString(value);
        return result;
    }
    get __hostName() {
        return this.name;
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: AXTagBoxComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: AXTagBoxComponent, isStandalone: true, selector: "ax-tag-box", inputs: { disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: false, isRequired: false, transformFunction: null }, tabIndex: { classPropertyName: "tabIndex", publicName: "tabIndex", isSignal: false, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: false, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: false, isRequired: false, transformFunction: null }, state: { classPropertyName: "state", publicName: "state", isSignal: false, isRequired: false, transformFunction: null }, name: { classPropertyName: "name", publicName: "name", isSignal: false, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: false, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: false, isRequired: false, transformFunction: null }, allowNull: { classPropertyName: "allowNull", publicName: "allowNull", isSignal: false, isRequired: false, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", isSignal: false, isRequired: false, transformFunction: null }, look: { classPropertyName: "look", publicName: "look", isSignal: false, isRequired: false, transformFunction: null }, addOnComma: { classPropertyName: "addOnComma", publicName: "addOnComma", isSignal: true, isRequired: false, transformFunction: null }, addOnEnter: { classPropertyName: "addOnEnter", publicName: "addOnEnter", isSignal: true, isRequired: false, transformFunction: null }, valueField: { classPropertyName: "valueField", publicName: "valueField", isSignal: true, isRequired: false, transformFunction: null }, textField: { classPropertyName: "textField", publicName: "textField", isSignal: true, isRequired: false, transformFunction: null }, readonlyField: { classPropertyName: "readonlyField", publicName: "readonlyField", isSignal: true, isRequired: false, transformFunction: null }, allowDuplicateValues: { classPropertyName: "allowDuplicateValues", publicName: "allowDuplicateValues", isSignal: true, isRequired: false, transformFunction: null }, tagTemplate: { classPropertyName: "tagTemplate", publicName: "tagTemplate", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onBlur: "onBlur", onFocus: "onFocus", valueChange: "valueChange", stateChange: "stateChange", onValueChanged: "onValueChanged", readonlyChange: "readonlyChange", disabledChange: "disabledChange", onKeyDown: "onKeyDown", onKeyUp: "onKeyUp", onKeyPress: "onKeyPress", onTagClick: "onTagClick", onTagDblClick: "onTagDblClick", onTagContextMenu: "onTagContextMenu" }, host: { properties: { "attr.name": "this.__hostName" } }, providers: [
            { provide: AXComponent, useExisting: AXTagBoxComponent },
            { provide: AXValuableComponent, useExisting: AXTagBoxComponent },
            { provide: AXFocusableComponent, useExisting: AXTagBoxComponent },
            { provide: AXClearableComponent, useExisting: AXTagBoxComponent },
            { provide: MXInputBaseValueComponent, useExisting: AXTagBoxComponent },
            { provide: AXAutocompleteParentComponent, useExisting: AXTagBoxComponent },
            {
                provide: NG_VALUE_ACCESSOR,
                useExisting: forwardRef(() => AXTagBoxComponent),
                multi: true,
            },
            AXUnsubscriber,
        ], queries: [{ propertyName: "autocompleteComponent", first: true, predicate: AXAutocompleteComponent, descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<div\n  (click)=\"input.focus()\"\n  [class.ax-state-disabled]=\"disabled\"\n  [class.ax-state-readonly]=\"readonly\"\n  class=\"ax-editor-container ax-{{ look }}\"\n>\n  <ng-content select=\"ax-prefix\"> </ng-content>\n  <div class=\"ax-tags-container\">\n    @for (tag of value; track $index; let i = $index) {\n      @if (tagTemplate()) {\n        <ng-container\n          [ngTemplateOutlet]=\"tagTemplate()\"\n          [ngTemplateOutletContext]=\"{ $implicit: tag, index: i }\"\n        ></ng-container>\n      } @else {\n        <ax-tag\n          [text]=\"(getFieldValue(tag, textField()) ?? '') + ''\"\n          look=\"twotone\"\n          (onClick)=\"onTagClick.emit($event)\"\n          (onDblClick)=\"onTagDblClick.emit($event)\"\n          (onContextMenu)=\"onTagContextMenu.emit($event)\"\n        >\n          @if (!getFieldValue(tag, readonlyField()) && !disabled && !readonly) {\n            <ax-suffix>\n              <button (click)=\"removeItem(i)\"><ax-icon class=\"ax-icon ax-icon-close\"></ax-icon></button>\n            </ax-suffix>\n          }\n        </ax-tag>\n      }\n    }\n    <input\n      #input\n      [id]=\"id\"\n      class=\"ax-input\"\n      [disabled]=\"disabled\"\n      [readonly]=\"readonly\"\n      [tabindex]=\"tabIndex\"\n      [(ngModel)]=\"inputValue\"\n      (blur)=\"emitOnBlurEvent($event)\"\n      [attr.placeholder]=\"placeholder\"\n      (keyup)=\"emitOnKeyupEvent($event)\"\n      (focus)=\"emitOnFocusEvent($event)\"\n      [class.ax-state-disabled]=\"disabled\"\n      [class.ax-state-readonly]=\"readonly\"\n      (keydown)=\"emitOnKeydownEvent($event)\"\n      (keypress)=\"emitOnKeypressEvent($event)\"\n      [ngModelOptions]=\"{ updateOn: updateOn() }\"\n      (ngModelChange)=\"emitOnTextChanged($event, true)\"\n    />\n  </div>\n  @if (!disabled && !readonly && value?.length) {\n    <ng-content select=\"ax-clear-button\"></ng-content>\n  }\n  <ng-content select=\"ax-suffix\"> </ng-content>\n</div>\n<ng-content select=\"ax-autocomplete\"> </ng-content>\n<ng-content select=\"ax-validation-rule\"> </ng-content>\n<div class=\"ax-error-container\"></div>\n", styles: ["ax-tag-box{width:100%}ax-tag-box .ax-editor-container{height:auto;padding:.25rem;min-height:var(--ax-sys-size-base)}ax-tag-box .ax-editor-container .ax-tags-container{width:100%;gap:.25rem;display:flex;flex-wrap:wrap}ax-tag-box .ax-editor-container .ax-tags-container ax-tag{--ax-comp-tag-border-radius: .375rem}ax-tag-box .ax-editor-container .ax-tags-container input{min-width:var(--ax-comp-tag-item-input-min-width, 7.5rem);height:calc(var(--ax-sys-size-base) * var(--ax-comp-tag-size-ratio, .75));padding-inline-start:var(--ax-comp-tag-item-input-padding-inline-start, .5rem)}ax-tag-box .ax-editor-container ax-clear-button{height:1rem}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "component", type: AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: AXTagComponent, selector: "ax-tag", inputs: ["color", "look", "text"], outputs: ["onClick", "onDblClick", "onContextMenu"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: AXTagBoxComponent, decorators: [{
            type: Component,
            args: [{ selector: 'ax-tag-box', inputs: [
                        'disabled',
                        'tabIndex',
                        'readonly',
                        'value',
                        'state',
                        'name',
                        'id',
                        'placeholder',
                        'allowNull',
                        'type',
                        'look',
                    ], outputs: [
                        'onBlur',
                        'onFocus',
                        'valueChange',
                        'stateChange',
                        'onValueChanged',
                        'readonlyChange',
                        'disabledChange',
                        'onKeyDown',
                        'onKeyUp',
                        'onKeyPress',
                    ], encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, providers: [
                        { provide: AXComponent, useExisting: AXTagBoxComponent },
                        { provide: AXValuableComponent, useExisting: AXTagBoxComponent },
                        { provide: AXFocusableComponent, useExisting: AXTagBoxComponent },
                        { provide: AXClearableComponent, useExisting: AXTagBoxComponent },
                        { provide: MXInputBaseValueComponent, useExisting: AXTagBoxComponent },
                        { provide: AXAutocompleteParentComponent, useExisting: AXTagBoxComponent },
                        {
                            provide: NG_VALUE_ACCESSOR,
                            useExisting: forwardRef(() => AXTagBoxComponent),
                            multi: true,
                        },
                        AXUnsubscriber,
                    ], imports: [FormsModule, AXDecoratorGenericComponent, AXDecoratorIconComponent, AXTagComponent, NgTemplateOutlet], template: "<div\n  (click)=\"input.focus()\"\n  [class.ax-state-disabled]=\"disabled\"\n  [class.ax-state-readonly]=\"readonly\"\n  class=\"ax-editor-container ax-{{ look }}\"\n>\n  <ng-content select=\"ax-prefix\"> </ng-content>\n  <div class=\"ax-tags-container\">\n    @for (tag of value; track $index; let i = $index) {\n      @if (tagTemplate()) {\n        <ng-container\n          [ngTemplateOutlet]=\"tagTemplate()\"\n          [ngTemplateOutletContext]=\"{ $implicit: tag, index: i }\"\n        ></ng-container>\n      } @else {\n        <ax-tag\n          [text]=\"(getFieldValue(tag, textField()) ?? '') + ''\"\n          look=\"twotone\"\n          (onClick)=\"onTagClick.emit($event)\"\n          (onDblClick)=\"onTagDblClick.emit($event)\"\n          (onContextMenu)=\"onTagContextMenu.emit($event)\"\n        >\n          @if (!getFieldValue(tag, readonlyField()) && !disabled && !readonly) {\n            <ax-suffix>\n              <button (click)=\"removeItem(i)\"><ax-icon class=\"ax-icon ax-icon-close\"></ax-icon></button>\n            </ax-suffix>\n          }\n        </ax-tag>\n      }\n    }\n    <input\n      #input\n      [id]=\"id\"\n      class=\"ax-input\"\n      [disabled]=\"disabled\"\n      [readonly]=\"readonly\"\n      [tabindex]=\"tabIndex\"\n      [(ngModel)]=\"inputValue\"\n      (blur)=\"emitOnBlurEvent($event)\"\n      [attr.placeholder]=\"placeholder\"\n      (keyup)=\"emitOnKeyupEvent($event)\"\n      (focus)=\"emitOnFocusEvent($event)\"\n      [class.ax-state-disabled]=\"disabled\"\n      [class.ax-state-readonly]=\"readonly\"\n      (keydown)=\"emitOnKeydownEvent($event)\"\n      (keypress)=\"emitOnKeypressEvent($event)\"\n      [ngModelOptions]=\"{ updateOn: updateOn() }\"\n      (ngModelChange)=\"emitOnTextChanged($event, true)\"\n    />\n  </div>\n  @if (!disabled && !readonly && value?.length) {\n    <ng-content select=\"ax-clear-button\"></ng-content>\n  }\n  <ng-content select=\"ax-suffix\"> </ng-content>\n</div>\n<ng-content select=\"ax-autocomplete\"> </ng-content>\n<ng-content select=\"ax-validation-rule\"> </ng-content>\n<div class=\"ax-error-container\"></div>\n", styles: ["ax-tag-box{width:100%}ax-tag-box .ax-editor-container{height:auto;padding:.25rem;min-height:var(--ax-sys-size-base)}ax-tag-box .ax-editor-container .ax-tags-container{width:100%;gap:.25rem;display:flex;flex-wrap:wrap}ax-tag-box .ax-editor-container .ax-tags-container ax-tag{--ax-comp-tag-border-radius: .375rem}ax-tag-box .ax-editor-container .ax-tags-container input{min-width:var(--ax-comp-tag-item-input-min-width, 7.5rem);height:calc(var(--ax-sys-size-base) * var(--ax-comp-tag-size-ratio, .75));padding-inline-start:var(--ax-comp-tag-item-input-padding-inline-start, .5rem)}ax-tag-box .ax-editor-container ax-clear-button{height:1rem}\n"] }]
        }], propDecorators: { addOnComma: [{ type: i0.Input, args: [{ isSignal: true, alias: "addOnComma", required: false }] }], addOnEnter: [{ type: i0.Input, args: [{ isSignal: true, alias: "addOnEnter", required: false }] }], valueField: [{ type: i0.Input, args: [{ isSignal: true, alias: "valueField", required: false }] }], textField: [{ type: i0.Input, args: [{ isSignal: true, alias: "textField", required: false }] }], readonlyField: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonlyField", required: false }] }], allowDuplicateValues: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowDuplicateValues", required: false }] }], tagTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "tagTemplate", required: false }] }], onTagClick: [{ type: i0.Output, args: ["onTagClick"] }], onTagDblClick: [{ type: i0.Output, args: ["onTagDblClick"] }], onTagContextMenu: [{ type: i0.Output, args: ["onTagContextMenu"] }], autocompleteComponent: [{ type: i0.ContentChild, args: [i0.forwardRef(() => AXAutocompleteComponent), { isSignal: true }] }], __hostName: [{
                type: HostBinding,
                args: ['attr.name']
            }] } });

class AXTagBoxModule {
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: AXTagBoxModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
    static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.15", ngImport: i0, type: AXTagBoxModule, imports: [AXTagBoxComponent], exports: [AXTagBoxComponent] }); }
    static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: AXTagBoxModule, imports: [AXTagBoxComponent] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: AXTagBoxModule, decorators: [{
            type: NgModule,
            args: [{
                    imports: [AXTagBoxComponent],
                    exports: [AXTagBoxComponent],
                    providers: [],
                }]
        }] });

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

export { AXTagBoxComponent, AXTagBoxModule };
//# sourceMappingURL=acorex-components-tag-box.mjs.map
