import {
  Component, Input, forwardRef, OnInit,
  Optional,
  Self
} from '@angular/core';
import {
  ControlValueAccessor, NG_VALUE_ACCESSOR, NG_VALIDATORS, Validator, AbstractControl, ValidationErrors,
  FormControl,
  ReactiveFormsModule,
  NgControl
} from '@angular/forms';
import { Observable, of, map, startWith, debounceTime, distinctUntilChanged, filter, switchMap, tap, catchError } from 'rxjs';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input';
import { MatAutocompleteModule, MatAutocompleteSelectedEvent } from '@angular/material/autocomplete';
import { MatOptionModule } from '@angular/material/core';

@Component({
  selector: 'app-custom-autocomplete-api',
  standalone: true,
  templateUrl: './custom-autocomplete-api.component.html',
  styleUrls: ['./custom-autocomplete-api.component.scss'],
  imports: [
    CommonModule,
    FormsModule,
    MatFormFieldModule,
    MatInputModule,
    ReactiveFormsModule,
    MatAutocompleteModule,
    MatOptionModule
  ],
  providers: [
  ]
})
export class CustomAutocompleteComponentApi implements ControlValueAccessor, Validator, OnInit {
  @Input() label!: string;
  @Input() fetchOptions!: (search: string) => Observable<{ value: any; label: string }[]>;

  filteredOptions$!: Observable<{ value: any; label: string }[]>;
  control!: FormControl;

  onChange = (_: any) => {};
  onTouched = () => {};

  constructor(@Optional() @Self() public ngControl: NgControl) {
    if (this.ngControl != null) {
      this.ngControl.valueAccessor = this;
    }
  }

  ngOnInit(): void {
    const rawControl = this.ngControl?.control;

    if (!rawControl || !(rawControl instanceof FormControl)) {
      throw new Error(
        'O componente CustomAutocompleteComponentApi requer [formControl] e ele deve ser uma instância de FormControl.'
      );
    }
  
    this.control = rawControl;
  
    this.filteredOptions$ = this.control.valueChanges.pipe(
      debounceTime(300),
      distinctUntilChanged(),
      filter((val: any) => typeof val === 'string' && val.length >= 3),
      switchMap(val => this.fetchOptions(val).pipe(
        catchError(err => {
          return of([])
        })
      ))
    );
  }

  writeValue(value: any): void {
    this.control?.setValue(value);
  }

  registerOnChange(fn: any): void {
    this.onChange = fn;
  }

  registerOnTouched(fn: any): void {
    this.onTouched = fn;
  }

  setDisabledState?(isDisabled: boolean): void {
    if (!this.control) return;
  
    if (isDisabled) {
      this.control.disable();
    } else {
      this.control.enable();
    }
  }

  onOptionSelected(event: MatAutocompleteSelectedEvent) {
    const selected = event.option.value;
    this.control.setValue(selected);
    this.onChange(selected);
  }

  displayFn(option: any): string {
    return option?.label ?? '';
  }

  validate(control: AbstractControl): ValidationErrors | null {
    return null;
  }
}
