import { SearchInputComponent } from '@libs/ui';
import { Observable, Subject, combineLatest } from 'rxjs';
import { Breadcrumb } from '../../../../../../core/models/breadcrumb.model';
import { Process } from '../../../../../../core/models/process.model';
import { Product } from '../../../../../../core/models/product.model';
import { RecentArticleSearch } from '../../../../../../core/models/recent-article-search.model';
import { Search } from '../../../../../../core/models/search.model';
import {
  AddProcess,
  AddSearch,
  AllowProductLoad,
  ChangeCurrentRoute,
  SetArticleSearchErrorStatus,
} from '../../../../../../core/store/actions/process.actions';
import { LoadRecentProducts, SetProductCachedResults } from '../../../../../../core/store/actions/product.actions';
import { AfterViewInit, Component, Input, OnInit, ViewChild, OnDestroy } from '@angular/core';
import { Router } from '@angular/router';
import { Select, Store } from '@ngxs/store';
import { AutocompleteState } from '../../../../../../core/store/state/autocomplete.state';
import { LoadAutocomplete, CancelPendingAutocomplete } from '../../../../../../core/store/actions/autocomplete.actions';
import { ProductService } from '../../../../../../core/services/product.service';
import { debounceTime, distinctUntilChanged, takeUntil, filter, takeLast, take, last } from 'rxjs/operators';
import { fadeInAnimation } from './fadeIn.animation';
import { AddBreadcrumb } from '../../../../../../core/store/actions/breadcrumb.actions';
import { ProcessSelectors } from '../../../../../../core/store/selectors/process.selectors';
import { RadioButtonGroup } from '@libs/ui/lib/radio-button-group';
import { AutocompleteResults } from '../../../../../../core/models/autocomplete-results.model';
import { PRODUCT_SCROLL_INDEX } from '../../../../../../core/utils/app.constants';
import { AppState } from '../../../../../../core/store/state/app.state';
import { isNullOrUndefined } from 'util';
import { ProductSerachFilters } from '../../../../../../core/models/product-search-filters.model';
import { Filter } from '../../../../../../core/models/filter.model';
import { FilterItem } from '../../../../../../core/models/filter-item.model';
import { SharedSelectors } from 'apps/sales/src/app/core/store/selectors/shared.selectors';
import { AppService } from 'apps/sales/src/app/core/services/app.service';
import { ListResponseArgsOfItemDTO } from '@swagger/cat';
import { FilterType } from 'apps/sales/src/app/core/models/filter-type.enum';
import { SetFilterType } from 'apps/sales/src/app/core/store/actions/filter.actions';

@Component({
  selector: 'app-text-search',
  templateUrl: './text-search.component.html',
  styleUrls: ['./text-search.component.scss'],
  animations: [fadeInAnimation],
})
export class TextSearchComponent implements OnInit, AfterViewInit, OnDestroy {
  @Select(ProcessSelectors.getRecentProducts) recentArticles$: Observable<RecentArticleSearch[]>;
  @Select(ProcessSelectors.getProductFilters) filters$: Observable<ProductSerachFilters>;
  @Select(SharedSelectors.getFilters) allFilters$: Observable<Filter[]>;
  recentArticles: RecentArticleSearch[];
  products$: Observable<Product[]>;
  products: Product[];
  timer: any;
  showAutocomplete = false;
  autocompleteResults = [];
  @Select(ProcessSelectors.getProcesses) processes$: Observable<Process[]>;
  @Select(AutocompleteState.getAutocompleteResults)
  autocompleteResults$: Observable<AutocompleteResults[]>;
  destroy$ = new Subject();
  processes: Process[] = [];
  error = '';
  autoCompleteEnabled = true;
  inputForProcess: { [id: number]: string } = [];
  @Input()
  searchParams = '';
  radioButtonGroup: RadioButtonGroup;
  acrhiveFilter: boolean;
  isIPad = false;
  allFilters: Filter[] = [];

  get filters() {
    if (this.radioButtonGroup) {
      const selectedFilter = this.radioButtonGroup.radioButtons.filter((t) => t.selected === true);
      if (selectedFilter && selectedFilter.length === 0) {
        return 'qs';
      } else {
        return selectedFilter[0].key;
      }
    } else {
      return 'qs';
    }
  }

  @ViewChild('searchInput', { static: true }) searchInput: SearchInputComponent;

  constructor(private store: Store, private router: Router, private productService: ProductService, private appService: AppService) {}

  ngOnInit() {
    this.isIPad = this.appService.isIPadEnv();
    this.loadRecentArticles();

    this.filters$
      .pipe(
        filter((data) => !isNullOrUndefined(data)),
        takeUntil(this.destroy$)
      )
      .subscribe((filters: ProductSerachFilters) => {
        this.radioButtonGroup = filters.radioButtonGroup;
        this.acrhiveFilter = filters.archiveFilters;
      });

    this.searchInput.inputChange.subscribe((data) => {
      if (!data && this.error) {
        this.updateInputForProcess(data);
        this.store.dispatch(new SetArticleSearchErrorStatus(false));
      }
    });

    this.allFilters$
      .pipe(
        filter((data) => !isNullOrUndefined(data) && data.length > 0),
        takeUntil(this.destroy$),
        distinctUntilChanged((prev, curr) => prev && curr && prev !== curr)
      )
      .subscribe((allFilters: Filter[]) => {
        this.allFilters = allFilters;
      });

    this.store
      .select(AppState.getCurrentProcessId)
      .pipe(takeUntil(this.destroy$))
      .subscribe((t) => {
        if (!this.inputForProcess[t]) {
          this.inputForProcess = { ...this.inputForProcess, [t]: ' ' };
          this.searchInput.clear();
        } else if (this.inputForProcess[t] !== ' ') {
          this.searchInput.updateInput(this.inputForProcess[t]);
        } else {
          this.searchInput.clear();
        }
      });

    this.store
      .select(ProcessSelectors.getArticleSearchErrorStatus)
      .pipe(takeUntil(this.destroy$))
      .subscribe((status) => {
        if (status) {
          this.error = 'Ergibt keine Suchergebnisse';
        } else {
          this.error = '';
        }
      });

    this.autocompleteResults$.subscribe((res: AutocompleteResults[]) => {
      if (res) {
        this.autocompleteResults = res;
        this.showAutocomplete = true;
      }
    });
  }

  ngAfterViewInit() {
    this.searchInput.focus();
  }

  search(searchParams) {
    this.searchParams = searchParams;
    if (!this.searchParams) {
      return;
    }

    this.updateInputForProcess(searchParams);
    this.checkIfExistAndSumbit(searchParams);
  }

  private checkIfExistAndSumbit(searchParams: string) {
    const filters = this.activeFilters();

    const search: Search = {
      query: searchParams,
      skip: 0,
      take: 1,
      fitlers: filters.length > 0 ? filters : [],
      firstLoad: true,
      type:
        this.radioButtonGroup && this.radioButtonGroup.radioButtons && this.radioButtonGroup.radioButtons.find((t) => t.selected)
          ? this.radioButtonGroup.radioButtons.find((t) => t.selected).key
          : undefined,
      hits: true,
      archiveFilter: this.acrhiveFilter,
    };

    this.productService
      .searchItemsWithPagination(search, 0, 20, [], false)
      .pipe(takeUntil(this.destroy$), distinctUntilChanged())
      .subscribe((data: ListResponseArgsOfItemDTO) => {
        if (!data || !data.result || data.result.length === 0) {
          this.searchInput.stopLoading();
          this.store.dispatch(new SetArticleSearchErrorStatus(true));
        } else {
          this.store.dispatch(new SetArticleSearchErrorStatus(false));
          this.store.dispatch(new SetProductCachedResults(data));
          this.store.dispatch(new SetFilterType(FilterType.Full));
          this.submitSearch(data.result.length);
        }
      });
  }

  updateInputForProcess(input) {
    const currentProcessId = this.store.selectSnapshot(AppState.getCurrentProcessId);
    this.inputForProcess[currentProcessId] = input;
  }

  private submitSearch(hits: number) {
    const filters = this.activeFilters();

    const search = <Search>{
      query: this.searchParams,
      fitlers: filters.length > 0 ? filters : [],
      take: 5,
      skip: 0,
      firstLoad: true,
      type:
        this.radioButtonGroup && this.radioButtonGroup.radioButtons.find((t) => t.selected)
          ? this.radioButtonGroup.radioButtons.find((t) => t.selected).key
          : undefined,
      archiveFilter: this.acrhiveFilter,
    };

    this.store.dispatch(new AllowProductLoad());
    this.store.dispatch(new AddSearch(search));

    const newBread: Breadcrumb = {
      name: (search.query.length > 12 ? search.query.substring(0, 12) + '...' : search.query) + ` (${hits} Ergebnisse)`,
      path: '/product/results',
    };

    this.store.dispatch(new AddBreadcrumb(newBread, 'product'));
    this.searchInput.stopLoading();
    this.navigateToRoute('/product/results');
  }

  navigateToRoute(route: string) {
    sessionStorage.removeItem(PRODUCT_SCROLL_INDEX);
    this.store.dispatch(new ChangeCurrentRoute(route));
    this.router.navigate([route]);
  }

  clear() {
    this.store.dispatch(new SetArticleSearchErrorStatus(false));
    this.searchParams = null;
  }

  showRecentSearchResults(article: RecentArticleSearch) {
    this.createTab();
    this.searchInput.input = article.name;
    this.searchInput.focus();
    this.autocomplete(article.name);
  }

  searchProductsHandler(data: any) {
    if (data) {
      if (data.error) {
        console.error(data.error);
      } else {
        this.products = data;
      }
    }
  }

  loadRecentArticles() {
    this.store.dispatch(new LoadRecentProducts());
    this.recentArticles$.subscribe((data: RecentArticleSearch[]) => (this.recentArticles = data));
  }

  loadSearchResults() {
    this.store.select('products').subscribe((data: any) => this.searchProductsHandler(data));
  }

  loadProcesses() {
    this.processes$.subscribe((data: Process[]) => (this.processes = data));
  }

  createProcess() {
    const newProcess = <Process>{
      id: 1,
      name: 'Vorgang 1',
      currentRoute: '/product/search',
    };

    this.store.dispatch(new AddProcess(newProcess));
    this.store.dispatch(
      new AddBreadcrumb(
        <Breadcrumb>{
          name: 'Artikelsuche',
          path: '/product/search',
        },
        'product',
        true
      )
    );
  }

  createTab() {
    this.searchParams = this.searchInput.input;
    this.loadProcesses();
    if (!this.processes || !this.processes.length) {
      this.createProcess();
    }
  }

  autocomplete(search: string) {
    search = search.trim();
    this.autocompleteResults = [];
    this.store.dispatch(new SetArticleSearchErrorStatus(false));
    if (search.length > 2 && this.autoCompleteEnabled) {
      if (this.timer) {
        clearTimeout(this.timer);
      }
      this.store.dispatch(new CancelPendingAutocomplete());
      this.timer = setTimeout(() => this.store.dispatch(new LoadAutocomplete(search, this.filters)), 400);
    } else {
      this.autocompleteResults = [];
    }
  }

  closeAutocomplete() {
    this.showAutocomplete = false;
  }

  private activeFilters(): Filter[] {
    let filters = [];
    if (this.allFilters) {
      filters = this.allFilters.map((f: Filter) => {
        if (f.id === 'cattype') {
          const fil = {
            ...f,
            items: f.items.map((filterItm: FilterItem) => {
              if (filterItm.id === '2') {
                const itm = { ...filterItm, selected: this.acrhiveFilter };

                return itm;
              }
              return { ...filterItm, selected: false };
            }),
          };

          return fil;
        }
        return f;
      });
    }

    return filters;
  }

  ngOnDestroy() {
    this.destroy$.next();
  }
}
