import { Component, booleanAttribute, forwardRef, input } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';

/** Atom: text input. Utrecht textbox wired up as a form control (ngModel/reactive). */
@Component({
  selector: 'app-text-input',
  styles: [
    `
      :host {
        display: block;
      }
      input {
        inline-size: 100%;
        box-sizing: border-box;
      }
    `,
  ],
  template: `
    <input
      class="form-control"
      [class.is-invalid]="invalid()"
      [type]="type()"
      [id]="inputId()"
      [attr.aria-invalid]="invalid() ? 'true' : null"
      [attr.aria-describedby]="describedBy()"
      [placeholder]="placeholder()"
      [disabled]="disabled"
      [value]="value"
      (input)="onInput($event)"
      (blur)="onTouched()"
    />
  `,
  providers: [
    { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => TextInputComponent), multi: true },
  ],
})
export class TextInputComponent implements ControlValueAccessor {
  type = input<'text' | 'password' | 'email'>('text');
  placeholder = input('');
  invalid = input(false);
  inputId = input<string>();
  /** Set when the paired form-field renders a `-desc` hint, so it gets announced. */
  hasDescription = input(false, { transform: booleanAttribute });

  value = '';
  disabled = false;
  onChange: (v: string) => void = () => {};
  onTouched: () => void = () => {};

  describedBy(): string | null {
    const id = this.inputId();
    if (!id) return null;
    const ids = [
      ...(this.hasDescription() ? [`${id}-desc`] : []),
      ...(this.invalid() ? [`${id}-error`] : []),
    ];
    return ids.length ? ids.join(' ') : null;
  }

  onInput(e: Event) {
    this.value = (e.target as HTMLInputElement).value;
    this.onChange(this.value);
  }
  writeValue(v: string) {
    this.value = v ?? '';
  }
  registerOnChange(fn: (v: string) => void) {
    this.onChange = fn;
  }
  registerOnTouched(fn: () => void) {
    this.onTouched = fn;
  }
  setDisabledState(d: boolean) {
    this.disabled = d;
  }
}
