import { _IdGenerator } from '@angular/cdk/a11y';
import { ChangeDetectionStrategy, Component, computed, effect, inject, input, model, signal } from '@angular/core';
import { AbstractControl, ControlValueAccessor, NG_VALIDATORS, NG_VALUE_ACCESSOR, ValidationErrors, Validator } from '@angular/forms';
import { FAST_KENDO_COMMON, FAST_PAGE_COMMON } from '../../app.config';

@Component({
  selector: 'fast-checkbox',
  imports: [FAST_KENDO_COMMON, FAST_PAGE_COMMON],
  template: `
    <div class="fast-box flex items-center justify-center size-4 border-2 rounded text-white"
         [class.opacity-50]="isDisabled()"
         [class.bg-blue-400]="value()"
         [class.border-blue-400]="value()"
         [class.border-slate-500]="!value()">
      <fast-svg [class.opacity-0]="!value()" size="14" icon="check"/>
    </div>
    <fast-label [id]="labelId" class="select-none">
      {{ labelText() }}
      <ng-content></ng-content>
    </fast-label>
  `,
  providers: [
    { provide: NG_VALUE_ACCESSOR, multi: true, useExisting: FastCheckboxComponent },
    { provide: NG_VALIDATORS, multi: true, useExisting: FastCheckboxComponent },
  ],
  changeDetection: ChangeDetectionStrategy.OnPush,
  host: {
    'class': `
      inline-flex
      items-center
      gap-1
      outline-none
      rounded
      hover:[&>.fast-box]:ring-2
      focus-visible:[&>.fast-box]:ring-2
      hover:[&>.fast-box]:ring-blue-800
      focus-visible:[&>.fast-box]:ring-blue-800
      dark:hover:[&>.fast-box]:ring-blue-200
      dark:focus-visible:[&>.fast-box]:ring-blue-200`,
    '[class.cursor-pointer]': '!isDisabled()',
    '[class.**:cursor-pointer]': '!isDisabled()',
    '[class.cursor-not-allowed]': 'isDisabled()',
    '[class.**:cursor-not-allowed]': 'isDisabled()',
    '[class.flex-row-reverse]': 'labelAlign() === "start"',
    '[attr.tabindex]': 'isDisabled() ? -1 : 0',
    '[attr.role]': '"checkbox"',
    '[attr.aria-checked]': 'value() ?? false',
    '[attr.aria-disabled]': 'isDisabled()',
    '[attr.aria-labelledby]': 'labelId',
    '(click)': 'toggle()',
    '(keydown.space)': 'toggle($event)',
    '(keydown.enter)': 'toggle($event)'
  }
})
export class FastCheckboxComponent implements ControlValueAccessor, Validator {
  labelText = input('');
  labelAlign = input<'start' | 'end'>('end');
  required = input(false);
  disabled = input(false);
  checked = model(false);

  value = signal<boolean | null>(null);
  private formControlDisabled = signal(false);
  private usingReactiveForms = false;

  labelId = inject(_IdGenerator).getId('checkbox-label-');
  isDisabled = computed(() => this.disabled() || this.formControlDisabled());

  private onChange?: (v: boolean) => void;
  private onTouched?: () => void;
  private onValidatorChange?: () => void;

  constructor() {
    effect(() => {
      if (!this.usingReactiveForms) this.value.set(this.checked());
    });

    effect(() => {
      this.required();
      this.onValidatorChange?.();
    });
  }

  toggle(event?: Event): void {
    if (this.isDisabled()) return;

    if (event && event instanceof KeyboardEvent)
      event.preventDefault()

    this.onTouched?.();
    const newValue = !this.value();
    this.value.set(newValue);
    this.checked.set(newValue);
    this.onChange?.(newValue);
  }

  writeValue(obj: unknown): void {
    const v = !!obj;
    this.value.set(v);
    this.checked.set(v);
  }

  registerOnChange(fn: (v: boolean) => void): void {
    this.usingReactiveForms = true;
    this.onChange = fn;
  }

  registerOnTouched(fn: () => void): void { this.onTouched = fn; }
  setDisabledState(isDisabled: boolean): void { this.formControlDisabled.set(isDisabled); }
  registerOnValidatorChange(fn: () => void): void { this.onValidatorChange = fn; }

  validate(control: AbstractControl<boolean>): ValidationErrors | null {
    return this.required() && control.value !== true ? { required: true } : null;
  }
}
