import { CommonModule } from '@angular/common';
import {
  Component,
  ElementRef,
  HostListener,
  inject,
  Input,
  input,
  SimpleChanges,
  viewChild,
} from '@angular/core';
import { FormControl, FormsModule, ReactiveFormsModule } from '@angular/forms';
import { ActivatedRoute, Router } from '@angular/router';

import { TranslateModule } from '@ngx-translate/core';
import { Store } from '@ngxs/store';
import { Observable } from 'rxjs';

import { GetSearchByCategoryAction } from '../../../../action/category.action';
import { ClickOutsideDirective } from '../../../../directive/out-side-directive';
import { ICategory, ICategoryModel } from '../../../../interface/category.interface';
import { IProduct } from '../../../../interface/product.interface';
import { CategoryState } from '../../../../state/category.state';
import { ProductState } from '../../../../state/product.state';
import { Button } from '../../../widgets/button/button';
import { GetProductBySearchAction } from './../../../../action/product.action';
import { SearchDropdown } from './search-dropdown/search-dropdown';

@Component({
  selector: 'app-box-search',
  imports: [
    CommonModule,
    TranslateModule,
    FormsModule,
    ReactiveFormsModule,
    SearchDropdown,
    Button,
    ClickOutsideDirective,
  ],
  templateUrl: './search.html',
  styleUrl: './search.scss',
})
export class Search {
  private store = inject(Store);
  private route = inject(ActivatedRoute);
  private router = inject(Router);

  @Input() style: string = 'basic';
  readonly data = input<any>();

  readonly resultsContainer = viewChild<ElementRef>('resultsContainer');

  productBySearch$: Observable<IProduct[]> = inject(Store).select(ProductState.productBySearch);
  category$: Observable<ICategoryModel> = inject(Store).select(CategoryState.category);
  searchCategory$: Observable<ICategory[]> = inject(Store).select(CategoryState.searchByCategory);

  public term = new FormControl();
  public selectedCategory = new FormControl('');
  public show: boolean = false;
  public isOpenResult = false;
  public product: IProduct[];
  public filteredResults: IProduct[] = [];
  public filteredCategory: ICategory[] = [];
  public selectedResultIndex = -1;
  public categories: ICategory[];

  constructor() {
    this.category$.subscribe(
      res => (this.categories = res.data.filter(category => category.type == 'product')),
    );
    this.store.dispatch(new GetSearchByCategoryAction({ status: 1, paginate: 4 }));
    this.searchCategory$.subscribe(categories => {
      this.filteredCategory = categories;
    });

    this.productBySearch$.subscribe(item => (this.product = item));
    this.selectedCategory.valueChanges.subscribe(data => {
      this.isOpenResult = false;
      let category = data ? { status: 1, category_id: data } : { status: 1 };
      this.store.dispatch(new GetProductBySearchAction(category));
      this.store.dispatch(
        new GetSearchByCategoryAction(data ? { status: 1, ids: data } : { status: 1, paginate: 4 }),
      );
    });
  }

  ngOnChanges(changes: SimpleChanges) {
    let data = changes['data']?.currentValue;
    let ids = data?.content?.home_banner?.main_banner?.category_ids;
    if (ids && ids.length) {
      this.category$.subscribe(res => {
        this.categories = res.data.filter(category => ids?.includes(category.id));
      });
    }
  }

  @HostListener('document:keydown', ['$event'])
  handleKeyboardEvent(event: KeyboardEvent) {
    if (event.key === 'ArrowUp') {
      this.navigateResults(-1);
    } else if (event.key === 'ArrowDown') {
      this.navigateResults(1);
    }
  }

  onInputChange() {
    this.filteredResults =
      this.term.value <= 0
        ? this.product.slice(0, 4)
        : this.filterWords(this.term.value).slice(0, 4);
    this.filteredCategory =
      this.term.value <= 0
        ? this.filteredCategory.slice(0, 4)
        : this.searchCategory(this.term.value);
    this.selectedResultIndex = -1;
  }

  focusInput(val: boolean) {
    this.filteredResults = this.product.slice(0, 4);
    this.isOpenResult = val;
  }

  filterWords(input: string): IProduct[] {
    return this.product.filter(product => {
      const productName = product.name.toLowerCase();
      const inputLower = input.toLowerCase();
      const words = productName.split(' ');
      const isMatch = words.some(word => word.startsWith(inputLower));
      return isMatch;
    });
  }

  selectResult(result: string) {
    this.term.patchValue(result);
    this.filteredResults = [];
    this.selectedResultIndex = -1;
  }

  searchCategory(term: string) {
    let params = { status: 1, paginate: 4, search: term };
    this.store.dispatch(new GetSearchByCategoryAction(params));
    this.searchCategory$.subscribe(categories => (this.filteredCategory = categories));
    return [];
  }

  navigateResults(direction: number) {
    const newIndex = this.selectedResultIndex + direction;
    if (newIndex >= 0 && newIndex < this.filteredResults.length) {
      this.selectedResultIndex = newIndex;
      this.scrollResultsContainer();
    }
  }

  private scrollResultsContainer() {
    const resultsContainer = this.resultsContainer();
    if (resultsContainer && resultsContainer.nativeElement) {
      const container = resultsContainer.nativeElement;
      const selectedResultElement =
        resultsContainer.nativeElement.querySelector('.result-item.selected');

      if (selectedResultElement) {
        const containerRect = container.getBoundingClientRect();
        const selectedRect = selectedResultElement.getBoundingClientRect();

        if (selectedRect.bottom > containerRect.bottom) {
          // Scroll down
          container.scrollTop += 150;
        } else if (selectedRect.top < containerRect.top) {
          // Scroll up
          container.scrollTop -= 150;
        }
      }
    }
  }

  onEnterKey() {
    // Perform the action you want when the Enter key is pressed in the input
    if (this.selectedResultIndex !== -1) {
      const selectedItem = this.filteredResults[this.selectedResultIndex];
      void this.router.navigateByUrl(`/product/${selectedItem.slug}`);
      this.isOpenResult = false;
      this.selectedResultIndex = 0;
      this.term.patchValue('');
    }
  }

  redirectToSearch() {
    void this.router.navigate(['/search'], {
      relativeTo: this.route,
      queryParams: {
        category: null,
        search: this.term.value ? this.term.value : null,
      },
      queryParamsHandling: 'merge', // preserve the existing query params in the route
      skipLocationChange: false, // do trigger navigation
    });
  }

  toggleSearchBox() {
    this.show = !this.show;
  }
}
