import {
  ChangeDetectionStrategy,
  Component,
  DestroyRef,
  effect,
  inject,
  input,
  OnInit,
  output,
} from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { FormControl, ReactiveFormsModule } from '@angular/forms';
import { NgIcon, provideIcons } from '@ng-icons/core';
import { lucideSearch } from '@ng-icons/lucide';
import { HlmInputImports } from '@spartan-ng/helm/input';
import { debounceTime, distinctUntilChanged } from 'rxjs';

@Component({
  selector: 'au-table-search',
  changeDetection: ChangeDetectionStrategy.OnPush,
  imports: [ReactiveFormsModule, NgIcon, HlmInputImports],
  providers: [provideIcons({ lucideSearch })],
  host: { class: 'block' },
  template: `
    <div class="relative w-full md:w-80">
      <ng-icon
        name="lucideSearch"
        class="text-muted-foreground absolute top-1/2 left-3 -translate-y-1/2 text-sm"
      />
      <input
        class="w-full pl-9"
        [placeholder]="placeholder()"
        [formControl]="searchControl"
        hlmInput
      />
    </div>
  `,
})
export class TableSearch implements OnInit {
  private readonly destroyRef = inject(DestroyRef);

  readonly placeholder = input('Filter...');
  readonly debounce = input(300);
  /**
   * Optional controlled value. When provided, the internal `FormControl`
   * mirrors it (with `emitEvent: false` to avoid feedback loops). Useful when
   * the host owns the search state via a `useTableSearch` atom and needs to
   * reset/preset the input programmatically.
   */
  readonly value = input<string | null | undefined>(undefined);
  readonly search = output<string>();

  protected readonly searchControl = new FormControl('', { nonNullable: true });

  constructor() {
    // Sync external value → internal FormControl without re-emitting.
    effect(() => {
      const next = this.value();
      if (next === undefined || next === null) return;
      if (this.searchControl.value === next) return;
      this.searchControl.setValue(next, { emitEvent: false });
    });
  }

  ngOnInit() {
    this.searchControl.valueChanges
      .pipe(
        debounceTime(this.debounce()),
        distinctUntilChanged(),
        takeUntilDestroyed(this.destroyRef),
      )
      .subscribe((value) => this.search.emit(value));
  }
}
