import { Component, ElementRef, booleanAttribute, computed, input, output, signal, viewChildren } from '@angular/core';

let nextId = 0;

@Component({
  selector: '<%= selector %>',
  imports: [],
  templateUrl: './<%= dasherize(name) %>.html',
  styleUrl: './<%= dasherize(name) %>.css',
})
export class <%= classify(name) %> {
  private readonly ratingOptions = viewChildren<ElementRef<HTMLElement>>('ratingOption');

  protected readonly instanceId = `<%= dasherize(name) %>-${nextId++}`;

  readonly label = input('Rating');
  readonly max = input(5);
  readonly value = input<number | null>(null);
  readonly readonly = input(true, { transform: booleanAttribute });
  readonly valueChange = output<number>();

  protected readonly selectedValue = signal(4);
  protected readonly activeValue = computed(() => this.value() ?? this.selectedValue());
  protected readonly values = computed(() => Array.from({ length: Math.max(1, this.max()) }, (_, index) => index + 1));
  protected readonly accessibleLabel = computed(() => `${this.activeValue()} out of ${this.max()} ${this.label()}`);

  protected isSelected(value: number): boolean {
    return this.activeValue() === value;
  }

  protected isFilled(value: number): boolean {
    return value <= this.activeValue();
  }

  protected select(value: number): void {
    if (this.readonly()) {
      return;
    }

    this.selectedValue.set(value);
    this.valueChange.emit(value);
  }

  protected navigate(event: KeyboardEvent, index: number): void {
    if (this.readonly()) {
      return;
    }

    const values = this.values();
    let nextIndex: number;

    switch (event.key) {
      case 'ArrowDown':
      case 'ArrowLeft':
        nextIndex = (index - 1 + values.length) % values.length;
        break;
      case 'ArrowUp':
      case 'ArrowRight':
        nextIndex = (index + 1) % values.length;
        break;
      case 'Home':
        nextIndex = 0;
        break;
      case 'End':
        nextIndex = values.length - 1;
        break;
      default:
        return;
    }

    event.preventDefault();
    this.select(values[nextIndex]);
    this.ratingOptions()[nextIndex]?.nativeElement.focus();
  }
}
