import * as i0 from '@angular/core';
import { EventEmitter, inject, ChangeDetectorRef, ElementRef, forwardRef, numberAttribute, booleanAttribute, HostBinding, Input, ViewChildren, Output, ChangeDetectionStrategy, Component } from '@angular/core';
import { ReactiveFormsModule, NG_VALUE_ACCESSOR } from '@angular/forms';
import * as i1 from '@eui/components/shared';
import { BaseStatesDirective } from '@eui/components/shared';
import * as i2 from '@eui/components/eui-icon';
import { EUI_ICON } from '@eui/components/eui-icon';
import * as i3 from '@eui/components/eui-button';
import { EUI_BUTTON } from '@eui/components/eui-button';
import { Subject, fromEvent, takeUntil } from 'rxjs';

/**
 * @description
 * Interactive star rating component for collecting user feedback and displaying rating values.
 * Implements ControlValueAccessor for seamless integration with Angular reactive and template-driven forms.
 * Supports keyboard navigation with arrow keys, Home, and End for accessibility.
 * Provides customizable number of stars and visual feedback for current rating state.
 * Commonly used for product reviews, feedback forms, and quality assessments.
 *
 * @usageNotes
 * ### Basic usage
 * ```html
 * <eui-rating [(rating)]="userRating"></eui-rating>
 * ```
 *
 * ### With reactive forms
 * ```typescript
 * ratingControl = new FormControl(3);
 * ```
 * ```html
 * <eui-rating [formControl]="ratingControl" [numberOfStars]="5"></eui-rating>
 * ```
 *
 * ### Disabled state
 * ```html
 * <eui-rating [rating]="4" [euiDisabled]="true"></eui-rating>
 * ```
 *
 * ### Accessibility
 * - Full keyboard navigation: Arrow keys to change rating, Home/End for first/last
 * - ARIA radiogroup role with proper labeling
 * - Each star is focusable and announces its value to screen readers
 * - Visual focus indicators for keyboard users
 *
 * ### Notes
 * - Click same star again to clear rating (set to 0)
 * - Only one star is focusable at a time (roving tabindex pattern)
 * - Emits `ratingChange` event on user interaction
 */
class EuiRatingComponent {
    constructor() {
        /**
         * Unique identifier for the toggle
         * @default Generated unique ID with 'eui-rating-' prefix
         */
        // @Input() id = `eui-rating-${uniqueId()}`;
        /**
         * Whether the toggle is disabled
         * @default false
         */
        this.euiDisabled = false;
        /**
         * Current numbers of stars rating to display
         * @default 5
         */
        this.numberOfStars = 5;
        /**
         * Current rating number
         * @default 0
         */
        this.rating = 0;
        /**
         * Event emitted when toggle state changes
         * @emits boolean - The new toggle state
         */
        this.ratingChange = new EventEmitter();
        /**
         * Binds the aria-label attribute to the component.
         * @default 'eUI Rating'
         */
        this.ariaLabel = 'eUI Rating';
        /**
         * Binds the role attribute to the component.
         * @default 'radiogroup'
         */
        this.role = 'radiogroup';
        // eslint-disable-next-line
        this.numbers = [];
        this.baseStatesDirective = inject(BaseStatesDirective);
        this.cd = inject(ChangeDetectorRef);
        this.destroy$ = new Subject();
        // TODO: find the correct type or turn into a generic, https://www.typescriptlang.org/docs/handbook/2/generics.html
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        this.onChange = () => {
            /* empty */
        };
        // TODO: find the correct type or turn into a generic, https://www.typescriptlang.org/docs/handbook/2/generics.html
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        this.onTouch = () => {
            /* empty */
        };
    }
    /** CSS classes applied to the host element */
    get cssClasses() {
        return [this.baseStatesDirective.getCssClasses('eui-rating')].join(' ').trim();
    }
    ngOnInit() {
        this.initState();
    }
    ngAfterViewInit() {
        this.ratingButtons.toArray().forEach((buttonRef) => {
            fromEvent(buttonRef.nativeElement, 'blur').pipe(takeUntil(this.destroy$)).subscribe(() => {
                this.onTouch();
            });
        });
    }
    ngOnDestroy() {
        this.destroy$.next(true);
        this.destroy$.unsubscribe();
    }
    /**
     * Implements ControlValueAccessor
     * Updates the toggle's checked state
     */
    writeValue(value) {
        this.rating = value;
        this.updateState();
        this.cd.detectChanges();
    }
    /**
     * Implements ControlValueAccessor
     * Updates the rating's disabled state
     */
    setDisabledState(isDisabled) {
        this.euiDisabled = isDisabled;
        this.cd.detectChanges();
    }
    /**
     * Handles focus out event
     * Notifies form control of touch event
     */
    onFocusOut() {
        this.onTouch();
    }
    /**
     * Implements ControlValueAccessor
     * Registers change handler
     * @todo Improve type definition or make generic
     */
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    registerOnChange(fn) {
        this.onChange = fn;
    }
    /**
     * Implements ControlValueAccessor
     * Registers touch handler
     * @todo Improve type definition or make generic
     */
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    registerOnTouched(fn) {
        this.onTouch = fn;
    }
    /**
     * Actions applied upon a keydown event
     *
     * @param event The keyboard event
     * @param index The index of the current star button
     */
    onKeydown(event, index) {
        switch (event.key) {
            case 'Home': {
                // Focus the first star
                this.ratingButtons.toArray()[0].nativeElement.focus();
                event.preventDefault();
                this.updateRating(0, false);
                break;
            }
            case 'End': {
                // Focus the last star
                this.ratingButtons.toArray()[this.numberOfStars - 1].nativeElement.focus();
                event.preventDefault();
                this.updateRating(this.numberOfStars, false);
                break;
            }
            case 'ArrowRight': {
                // Focus the next star button
                if (this.rating < this.numberOfStars) {
                    this.ratingButtons.toArray()[index].nativeElement.focus();
                    // Update the rating
                    if (this.rating === 0) {
                        this.updateRating(2, false);
                    }
                    else {
                        this.updateRating(this.rating + 1, false);
                    }
                }
                break;
            }
            case 'ArrowLeft': {
                // Focus the previous star
                if (this.rating === 1) {
                    this.ratingButtons.toArray()[0].nativeElement.focus();
                }
                else if (this.rating > 1) {
                    this.ratingButtons.toArray()[index - 2].nativeElement.focus();
                    this.updateRating(this.rating - 1, false);
                }
                break;
            }
        }
    }
    /**
     * Toggles the current state if not disabled
     * Emits the new state and notifies form control
     */
    onUpdate(rating) {
        this.updateRating(rating, true);
    }
    /**
     * Updates the checked state of the star button based on the index
     * @param index The index of the star button
     * @returns boolean - true if the index matches the rating, false otherwise
     */
    updateCheckedState(index) {
        return index === this.rating;
    }
    /**
     * Returns the tab index value based on the current rating and index
     * @param index The index of the star button
     * @returns number - 0 if the star is focusable, -1 otherwise
     */
    getTabIndexValue(index) {
        if (this.rating === 0) {
            return index === 1 ? 0 : -1; // Only the first star is focusable when no rating is set
        }
        else {
            return index === this.rating ? 0 : -1; // Only the current star is focusable
        }
    }
    initState() {
        for (let i = 1; i < this.numberOfStars + 1; i++) {
            this.numbers.push({
                index: i,
                value: i <= this.rating,
            });
        }
    }
    updateState() {
        for (let i = 1; i < this.numberOfStars + 1; i++) {
            this.numbers[i - 1].value = i <= this.rating;
        }
    }
    updateRating(rating, clearifSame = false) {
        if (!this.euiDisabled) {
            if (this.rating === rating && clearifSame) {
                this.rating = 0;
            }
            else {
                this.rating = rating;
            }
            this.updateState();
            this.onChange(this.rating);
            this.ratingChange.next(this.rating);
        }
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: EuiRatingComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: EuiRatingComponent, isStandalone: true, selector: "eui-rating", inputs: { euiDisabled: ["euiDisabled", "euiDisabled", booleanAttribute], numberOfStars: ["numberOfStars", "numberOfStars", numberAttribute], rating: ["rating", "rating", numberAttribute], ariaLabel: "ariaLabel" }, outputs: { ratingChange: "ratingChange" }, host: { properties: { "class": "this.cssClasses", "attr.aria-label": "this.ariaLabel", "attr.role": "this.role" } }, providers: [
            {
                provide: NG_VALUE_ACCESSOR,
                useExisting: forwardRef(() => EuiRatingComponent),
                multi: true,
            },
        ], viewQueries: [{ propertyName: "ratingButtons", predicate: ["euiRatingButtonRef"], descendants: true, read: ElementRef }], hostDirectives: [{ directive: i1.BaseStatesDirective }], ngImport: i0, template: "@for (n of numbers; track n.index) {\n<button\n    #euiRatingButtonRef\n    euiButton\n    euiPrimary\n    euiRounded\n    euiBasicButton\n    euiIconButton\n    euiSizeS\n    hasNoFocusRing\n    isCompact\n    [euiDisabled]=\"euiDisabled\"\n    (click)=\"onUpdate(n.index)\"\n    (keydown)=\"onKeydown($event, n.index)\"\n    [attr.tabindex]=\"getTabIndexValue(n.index)\"\n    [attr.aria-label]=\"'Rating star ' + n.index + ' - ' + (n.value ? 'Selected' : 'Not selected')\"\n    role=\"radio\"\n    [attr.aria-checked]=\"updateCheckedState(n.index)\">\n    @if (n.value) {\n        <eui-icon-svg icon=\"eui-star-fill\" fillColor=\"primary\" />\n    } @else {\n        <eui-icon-svg icon=\"eui-star\" fillColor=\"primary\" />\n    }\n</button>\n}\n", styles: [".eui-21 :host.eui-rating{display:inline-flex}.eui-21 :host.eui-rating:focus-visible:not([readonly]){outline:2px solid var(--eui-c-focus-visible)!important;outline-offset:-2px!important;transition:none}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "component", type: i2.EuiIconSvgComponent, selector: "eui-icon-svg, span[euiIconSvg], i[euiIconSvg]", inputs: ["icon", "fillColor", "set", "size", "style", "iconUrl", "transform", "ariaLabel", "ariaHidden", "focusable", "isLoading", "isInputIcon", "euiStart", "euiEnd"] }, { kind: "component", type: i3.EuiButtonComponent, selector: "button[euiButton], a[euiButton]", inputs: ["e2eAttr", "id", "euiBasicButton", "euiCTAButton", "euiBlockButton", "euiIconButton", "euiAvatarButton", "euiLineWrap", "isCompact", "hasNoFocusRing", "isChecked", "euiDisabled"], outputs: ["buttonClick"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: EuiRatingComponent, decorators: [{
            type: Component,
            args: [{ selector: 'eui-rating', changeDetection: ChangeDetectionStrategy.OnPush, hostDirectives: [
                        {
                            directive: BaseStatesDirective,
                        },
                    ], imports: [ReactiveFormsModule, ...EUI_ICON, ...EUI_BUTTON], providers: [
                        {
                            provide: NG_VALUE_ACCESSOR,
                            useExisting: forwardRef(() => EuiRatingComponent),
                            multi: true,
                        },
                    ], template: "@for (n of numbers; track n.index) {\n<button\n    #euiRatingButtonRef\n    euiButton\n    euiPrimary\n    euiRounded\n    euiBasicButton\n    euiIconButton\n    euiSizeS\n    hasNoFocusRing\n    isCompact\n    [euiDisabled]=\"euiDisabled\"\n    (click)=\"onUpdate(n.index)\"\n    (keydown)=\"onKeydown($event, n.index)\"\n    [attr.tabindex]=\"getTabIndexValue(n.index)\"\n    [attr.aria-label]=\"'Rating star ' + n.index + ' - ' + (n.value ? 'Selected' : 'Not selected')\"\n    role=\"radio\"\n    [attr.aria-checked]=\"updateCheckedState(n.index)\">\n    @if (n.value) {\n        <eui-icon-svg icon=\"eui-star-fill\" fillColor=\"primary\" />\n    } @else {\n        <eui-icon-svg icon=\"eui-star\" fillColor=\"primary\" />\n    }\n</button>\n}\n", styles: [".eui-21 :host.eui-rating{display:inline-flex}.eui-21 :host.eui-rating:focus-visible:not([readonly]){outline:2px solid var(--eui-c-focus-visible)!important;outline-offset:-2px!important;transition:none}\n"] }]
        }], propDecorators: { cssClasses: [{
                type: HostBinding,
                args: ['class']
            }], euiDisabled: [{
                type: Input,
                args: [{ transform: booleanAttribute }]
            }], numberOfStars: [{
                type: Input,
                args: [{ transform: numberAttribute }]
            }], rating: [{
                type: Input,
                args: [{ transform: numberAttribute }]
            }], ratingChange: [{
                type: Output
            }], ratingButtons: [{
                type: ViewChildren,
                args: ['euiRatingButtonRef', { read: ElementRef }]
            }], ariaLabel: [{
                type: HostBinding,
                args: ['attr.aria-label']
            }, {
                type: Input
            }], role: [{
                type: HostBinding,
                args: ['attr.role']
            }] } });

const EUI_RATING = [
    EuiRatingComponent,
];
// export { EuiRatingComponent as EuiRating } from './eui-rating.component';

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

export { EUI_RATING, EuiRatingComponent };
//# sourceMappingURL=eui-components-eui-rating.mjs.map
