import {
  CollectionOptimisticActions,
  CollectionState,
  Filter,
  FiltersMap,
} from '@wix/bex-core';
import { addEventListener } from '@wix/bex-core/util';
import mapValues from 'lodash/mapValues';
import { action, makeObservable } from 'mobx';

export interface FilterValueTotalStateParams<T, F extends FiltersMap, V> {
  readonly filter: Filter<V[]>;
  readonly collection: CollectionState<T, F>;
  readonly value: V | null | undefined;
  readonly optimisticActions?: CollectionOptimisticActions<T, F>;
  readonly ignoreSearch?: boolean;
  readonly fetchData?: CollectionState<T, F>['fetchData'];
}

export class FilterValueTotalState<T, F extends FiltersMap, V> {
  readonly collection;

  readonly totalsCollection;
  readonly optimisticActions;
  readonly ignoreSearch;

  tabFilter: Filter<V[]> | null | undefined;
  value: V | null | undefined;

  constructor(params: FilterValueTotalStateParams<T, F, V>) {
    this.collection = params.collection;
    this.optimisticActions = params.optimisticActions;
    this.ignoreSearch = params.ignoreSearch;
    this.value = params.value;

    const {
      errorMonitor,
      errorHandler,
      onlineState,
      history,
      translate,
      queryCache,
      lodash,
      queryName,
      itemKey,
      itemName,
      paginationMode,
      selectionConsistencyMode,
      query: { customFilters, search },
      fetchData: fetchDataCollection,
    } = params.collection.result.fetchTotal?._totalsCollection ??
    params.collection;

    const fetchData = params.fetchData ?? fetchDataCollection;

    const filters = mapValues(customFilters, (filter) => {
      if (filter === params.filter) {
        const tabFilter = filter.clone();
        this.tabFilter = tabFilter;
        if (params.value != null) {
          tabFilter.setValue([params.value]);
        } else {
          tabFilter.reset();
        }

        return tabFilter;
      }

      return filter;
    }) as F;

    this.totalsCollection = new CollectionState<T, F>({
      errorMonitor,
      errorHandler,
      onlineState,
      history,
      translate,
      queryCache,
      lodash,
      queryName,
      itemKey,
      itemName,
      limit: 1,
      fetchData: async (query) => {
        // const fetchDataPromise = fetchData(query);
        //
        // const collectionUpdateResultPromise = new Promise<void>((resolve) => {
        //   this.collection.emitter.on('refreshUpdateResult', resolve);
        // });
        //
        // await Promise.all([fetchDataPromise, collectionUpdateResultPromise]);

        return fetchData(query);
      },
      paginationMode: paginationMode.id,
      selectionConsistencyMode,
      search: params.ignoreSearch ? undefined : search,
      filters,
    });

    makeObservable(this, {
      init: action,
    });
  }

  refresh(value: V | null | undefined) {
    const { tabFilter } = this;
    this.value = value;

    if (tabFilter) {
      if (value != null) {
        tabFilter.refresh([value]);
      } else {
        tabFilter.reset();
      }
    }
  }

  init() {
    const { totalsCollection, optimisticActions, ignoreSearch, collection } =
      this;

    const disposers = [
      totalsCollection.init(),
      addEventListener(collection.emitter, 'search', () => {
        if (!ignoreSearch) {
          totalsCollection.clearResultAndMoveToStart();
        }
      }),
      addEventListener(collection.emitter, 'clearSearch', () => {
        if (!ignoreSearch) {
          totalsCollection.clearResultAndMoveToStart();
        }
      }),
      addEventListener(collection.emitter, 'refreshAllPages', () => {
        totalsCollection.refreshAllPages();
      }),
      addEventListener(collection.emitter, 'refreshCurrentPage', () => {
        totalsCollection.refreshCurrentPage();
      }),
      ...(optimisticActions
        ? [optimisticActions.initCollection(totalsCollection)]
        : []),
    ];

    return () => {
      disposers.forEach((d) => d());
    };
  }
}
