import { ChangeDetectionStrategy, Component, computed, input, output } from '@angular/core';
import { IconComponent } from '../icon/icon.component';

let nextFormFieldId = 0;

/**
 * Injected by form controls (e.g. app-input) nested inside app-form-field so they can
 * self-apply `id` and `aria-describedby` without the parent template wiring them manually.
 */
export abstract class FormFieldContext {
  abstract readonly fieldId: string;
  abstract readonly describedBy: () => string | null;
}

@Component({
  selector: 'app-form-field',
  standalone: true,
  imports: [IconComponent],
  templateUrl: './form-field.component.html',
  styleUrl: './form-field.component.scss',
  changeDetection: ChangeDetectionStrategy.OnPush,
  providers: [{ provide: FormFieldContext, useExisting: FormFieldComponent }]
})
export class FormFieldComponent implements FormFieldContext {
  readonly label = input<string | null>(null);
  readonly hint = input<string | null>(null);
  readonly error = input<string | null>(null);
  readonly required = input(false);
  /** Optional "Where is this used?" list, e.g. ['Buttons', 'Links', 'Badges']. Already-translated strings. */
  readonly usedBy = input<readonly string[] | null>(null);
  readonly usedByLabel = input<string | null>(null);
  /** Shows a small "reset to original" button next to the label when the field has been changed. */
  readonly showReset = input(false);
  readonly resetLabel = input<string | null>(null);
  readonly resetClicked = output<void>();

  readonly fieldId = `app-form-field-${++nextFormFieldId}`;
  protected readonly hintId = `${this.fieldId}-hint`;
  protected readonly errorId = `${this.fieldId}-error`;
  protected readonly usedById = `${this.fieldId}-used-by`;

  readonly describedBy = computed(() => {
    const ids = [
      this.error() ? this.errorId : (this.hint() ? this.hintId : null),
      this.usedBy()?.length ? this.usedById : null,
    ].filter((id): id is string => !!id);
    return ids.length ? ids.join(' ') : null;
  });
}
