import {
  ChangeDetectionStrategy,
  Component,
  EventEmitter,
  Input,
  OnInit,
  Output,
  ViewChild,
  inject,
} from '@angular/core'
import {
  AutocompleteComponent,
  AutocompleteItem,
} from '../../../../../../libs/ui/inputs/src'
import { firstValueFrom, Observable } from 'rxjs'
import { map } from 'rxjs/operators'
import { SearchFacade } from '../state/search.facade'
import { SearchService } from '../utils/service/search.service'
import { CatalogRecord } from '../../../../../../libs/common/domain/src/lib/model/record'
import { RecordsRepositoryInterface } from '../../../../../../libs/common/domain/src/lib/repository/records-repository.interface'
import { SearchFilters } from '../../../../../../libs/api/metadata-converter/src'
import { TranslatePipe } from '@ngx-translate/core'
import { CommonModule } from '@angular/common'

@Component({
  selector: 'gn-ui-fuzzy-search',
  templateUrl: './fuzzy-search.component.html',
  styleUrls: ['./fuzzy-search.component.css'],
  changeDetection: ChangeDetectionStrategy.OnPush,
  standalone: true,
  imports: [CommonModule, AutocompleteComponent, TranslatePipe],
})
export class FuzzySearchComponent implements OnInit {
  private searchFacade = inject(SearchFacade)
  private searchService = inject(SearchService)
  private recordsRepository = inject(RecordsRepositoryInterface)

  @ViewChild(AutocompleteComponent) autocomplete: AutocompleteComponent
  @Input() autoFocus = false
  @Input() forceTrackPosition = false
  @Input() enterButton = false
  @Input() placeholder?: string
  @Output() itemSelected = new EventEmitter<CatalogRecord>()
  @Output() inputSubmitted = new EventEmitter<string>()
  @Output() isSearchActive = new EventEmitter<boolean>()
  searchInputValue$: Observable<{ title: string }>

  displayWithFn: (record: CatalogRecord) => string = (record) => record.title

  autoCompleteAction = (query: string) =>
    this.recordsRepository
      .fuzzySearch(query)
      .pipe(map((result) => result.records))

  ngOnInit(): void {
    this.searchInputValue$ = this.searchFacade.searchFilters$.pipe(
      map((searchFilter) => ({
        title: searchFilter.any as string,
      }))
    )
  }

  /**
   * Emit the event if the parent component has subscribed to it, so it
   * can define the correct behavior. If no component is listening to that
   * event, then apply the default behavior
   * @param item
   */
  handleItemSelection(item: AutocompleteItem) {
    const record = item as CatalogRecord
    if (this.itemSelected.observers.length > 0) {
      this.itemSelected.emit(record)
    } else {
      this.searchFacade.setFilters({ any: record.title })
    }
  }

  handleInputSubmission(any: string) {
    if (this.inputSubmitted.observers.length > 0) {
      this.inputSubmitted.emit(any)
    } else {
      this.searchService.updateFilters({ any })
    }
  }

  async handleInputCleared() {
    const currentSearchFilters: SearchFilters = await firstValueFrom(
      this.searchFacade.searchFilters$
    )
    if (currentSearchFilters.any) {
      this.searchService.updateFilters({ any: '' })
    }
  }

  handleSearchActive(event: boolean) {
    this.isSearchActive.emit(event)
  }
}
