import { ChangeDetectionStrategy, Component, OnDestroy, OnInit, ViewChild } from '@angular/core';
import { ApplicationService } from '@core/application';
import { EnvironmentService } from '@core/environment';
import { Observable, Subject } from 'rxjs';
import { map, takeUntil, withLatestFrom } from 'rxjs/operators';
import { ArticleSearchService } from '../article-search.store';
import { ActivatedRoute } from '@angular/router';
import { ProductCatalogNavigationService } from '@shared/services/navigation';
import { Filter, FilterComponent } from '@shared/components/filter';

@Component({
  selector: 'page-article-search-filter',
  templateUrl: 'search-filter.component.html',
  styleUrls: ['search-filter.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush,
  standalone: false,
})
export class ArticleSearchFilterComponent implements OnInit, OnDestroy {
  _processId$ = this._activatedRoute.parent.data.pipe(map((data) => Number(data.processId)));

  fetching$: Observable<boolean> = this.articleSearch.fetching$;

  filter$: Observable<Filter> = this.articleSearch.filter$;

  searchboxHint$ = this.articleSearch.searchboxHint$;

  @ViewChild(FilterComponent, { static: false })
  uiFilterComponent: FilterComponent;

  showFilter: boolean = false;

  get isTablet() {
    return this._environment.matchTablet();
  }

  get showFilterClose$() {
    return this._environment.matchDesktopLarge$.pipe(map((matches) => !(matches && this.sideOutlet === 'search')));
  }

  get sideOutlet() {
    return this._activatedRoute?.parent?.children?.find((childRoute) => childRoute?.outlet === 'side')?.snapshot
      ?.routeConfig?.path;
  }

  get primaryOutlet() {
    return this._activatedRoute?.parent?.children?.find((childRoute) => childRoute?.outlet === 'primary')?.snapshot
      ?.routeConfig?.path;
  }

  get closeFilterRoute() {
    const processId = Number(this._activatedRoute?.parent?.snapshot?.data?.processId);
    const itemId = this._activatedRoute.snapshot.params.id;
    if (!itemId) {
      if (this.sideOutlet === 'search') {
        return this._navigationService.getArticleSearchBasePath(processId).path;
      } else if (this.primaryOutlet === 'results' || this.sideOutlet === 'results') {
        return this._navigationService.getArticleSearchResultsPath(processId).path;
      }
    } else {
      return this._navigationService.getArticleDetailsPath({ processId, itemId }).path;
    }
  }

  private _onDestroy$ = new Subject<void>();

  constructor(
    private articleSearch: ArticleSearchService,
    private _environment: EnvironmentService,
    private _activatedRoute: ActivatedRoute,
    public application: ApplicationService,
    private _navigationService: ProductCatalogNavigationService,
  ) {}

  ngOnInit() {
    this.showFilter = this.sideOutlet !== 'search';
    this._activatedRoute.queryParams
      .pipe(takeUntil(this._onDestroy$))
      .subscribe(async (queryParams) => await this.articleSearch.setDefaultFilter(queryParams));

    // #4143 To make Splitscreen Search and Filter work combined
    this.articleSearch.searchStarted.pipe(takeUntil(this._onDestroy$)).subscribe(async (_) => {
      let queryParams = {
        ...this.articleSearch.filter.getQueryParams(),
        ...this.cleanupQueryParams(this.uiFilterComponent?.uiFilter?.getQueryParams()),
      };

      // Always override query if not in tablet mode
      if (!!this.articleSearch.filter.getQueryParams()?.main_qs && !this.isTablet) {
        queryParams = { ...queryParams, main_qs: this.articleSearch.filter.getQueryParams()?.main_qs };
      }

      await this.articleSearch.setDefaultFilter(queryParams);
    });

    this.articleSearch.searchCompleted
      .pipe(takeUntil(this._onDestroy$), withLatestFrom(this._processId$))
      .subscribe(async ([searchCompleted, processId]) => {
        if (searchCompleted.state.searchState === '') {
          const params = searchCompleted.state.filter.getQueryParams();
          if (searchCompleted.state.hits === 1) {
            const item = searchCompleted.state.items.find((f) => f);
            await this._navigationService
              .getArticleDetailsPath({
                processId,
                itemId: item.id,
                extras: { queryParams: params },
              })
              .navigate();
          } else {
            await this._navigationService.getArticleSearchResultsPath(processId, { queryParams: params }).navigate();
          }
        }
      });
  }

  ngOnDestroy(): void {
    this._onDestroy$.next();
    this._onDestroy$.complete();
  }

  applyFilter(value: Filter) {
    this.uiFilterComponent?.cancelAutocomplete();
    this.articleSearch.search({ clear: true });
    this.articleSearch.searchCompleted
      .pipe(takeUntil(this._onDestroy$), withLatestFrom(this._processId$))
      .subscribe(async ([searchCompleted, processId]) => {
        if (searchCompleted.state.searchState === '') {
          const params = searchCompleted.state.filter.getQueryParams();
          if (searchCompleted.state.hits === 1) {
            const item = searchCompleted.state.items.find((f) => f);
            await this._navigationService
              .getArticleDetailsPath({
                processId,
                itemId: item.id,
                extras: { queryParams: params },
              })
              .navigate();
          } else {
            await this._navigationService.getArticleSearchResultsPath(processId, { queryParams: params }).navigate();
          }
        }
      });
  }

  clearFilter(value: Filter) {
    value.unselectAllFilterOptions();
  }

  hasSelectedOptions(filter: Filter) {
    // Is Query available
    const hasInputOptions = !!filter.input.find(
      (input) => !!input.input.find((fi) => fi.hasFilterInputOptionsSelected()),
    );

    // Are filter or filterChips selected
    const hasFilterOptions = !!filter.filter.find(
      (input) => !!input.input.find((fi) => fi.hasFilterInputOptionsSelected()),
    );
    return hasInputOptions || hasFilterOptions;
  }

  resetFilter(value: Filter) {
    const queryParams = { main_qs: value?.getQueryParams()?.main_qs || '' };
    this.articleSearch.setDefaultFilter(queryParams);
  }

  cleanupQueryParams(params: Record<string, string> = {}) {
    const clean = { ...params };

    for (const key in clean) {
      if (Object.prototype.hasOwnProperty.call(clean, key)) {
        if (clean[key] == undefined) {
          delete clean[key];
        }
      }
    }

    return clean;
  }
}
