import {
  addEventListener,
  FiltersMap,
  ReportBI,
  withoutDefaults,
} from '@wix/bex-core';
import { action } from 'mobx';
import {
  cairoFiltersPanelUsed,
  cairoManageViewActionSelected,
  cairoTryAgainClicked,
  cairoUndoClicked,
  cairoViewDeleted,
  cairoViewSaved,
  cairoViewSelected,
  cairoViewsUnsuccessfulUpdateInServer,
  wixPatternsClickOnViewDropdownSrc144Evid4,
} from '@wix/bex-core/bi';
import { CollectionViewsState } from './CollectionViewsState';
import { PrivateView, ViewActionNameBI, ViewBase } from '../model';
import isEqual from 'lodash/isEqual';

export interface CollectionViewsStateBIReporterParams<T, F extends FiltersMap> {
  reportBI: ReportBI;
  collectionViewState: CollectionViewsState<T, F>;
}

export class CollectionViewsStateBIReporter<T, F extends FiltersMap> {
  readonly collectionViewState: CollectionViewsState<T, F>;
  readonly reportBI: ReportBI;

  constructor(params: CollectionViewsStateBIReporterParams<T, F>) {
    this.collectionViewState = params.collectionViewState;
    this.reportBI = params.reportBI;
  }

  init() {
    const { reportBI, collectionViewState } = this;
    const { emitter, table, views } = collectionViewState;

    const disposers = [
      addEventListener(
        views.events,
        'beforeSelectView',
        action(() => {
          const previousViewName = views.currentView?.name;
          const previousFilters = JSON.stringify(
            table.collection.result.originQuery.filtersKey,
          );

          const isFromSearchView =
            !!views.localSearchState.bi.events.listeners('afterSelectView')
              .length;

          views.events.once('afterSelectView', ({ view }) => {
            reportBI(
              withoutDefaults(cairoViewSelected)({
                currentFilters: JSON.stringify(
                  table.collection.result.originQuery.filtersKey,
                ),
                filteredListSize: table.collection.query.activeFiltersCount,
                newViewName: view.name,
                prevViewName: previousViewName,
                prevFilters: previousFilters,
                isPredefined: view.isPreset,
                isFromSearchView,
                isDefault: view.id === views.defaultViewId,
              }),
            );
          });
        }),
      ),

      addEventListener(
        emitter,
        'openManageViewPopoverMenu',
        action(() => {
          reportBI(
            withoutDefaults(cairoFiltersPanelUsed)({
              isOpened: true,
              feature: 'Manage Views',
              origin: 'Manage Views',
            }),
          );
        }),
      ),
    ];

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

  _getViewChanges(view1: ViewBase<F>, view2: ViewBase<F>) {
    const { queryCompareHelper } = this.collectionViewState;
    const changes = [];
    if (!isEqual(view1.sortDirections, view2.sortDirections)) {
      changes.push('Sorting');
    }
    if (
      queryCompareHelper.isColumnsChanged(
        view1.selectedColumns,
        view2.selectedColumns,
      )
    ) {
      changes.push('Custom Columns');
    }
    if (view1.filters?.search?.value !== view2.filters?.search?.value) {
      changes.push('Search');
    }
    const { search: s1, ...filters1 } = view1.filters ?? {};
    const { search: s2, ...filters2 } = view2.filters ?? {};
    if (!isEqual(filters1, filters2)) {
      changes.push('Filters');
    }
    return changes.join(',');
  }

  _saveViewBI(
    view: PrivateView<F>,
    saveType: string,
    oldView?: PrivateView<F>,
  ) {
    const { table } = this.collectionViewState;
    const selectedColumns = table.selectedColumns.value.filter(
      (col) => col.isSelected,
    );
    this.reportBI(
      withoutDefaults(cairoViewSaved)({
        ...table._commonDynamicBiParams(),
        saveType,
        prevName: oldView?.name,
        newViewName: view.name,
        isPredefined: view.isPreset,
        changedAttributes: this._getViewChanges(view, oldView ?? {}),
        numColumnsInView: selectedColumns.length ?? 0,
        numFiltersInView: table.collection.result.originQuery.search?.length
          ? table.collection.query.activeFiltersCount - 1
          : table.collection.query.activeFiltersCount,
        searchQuery: table.collection.result.originQuery.search,
        viewFilters: JSON.stringify(
          table.collection.result.originQuery.nonPersistentFiltersKey,
        ),
        origin: 'MainToolbar',
        viewId: view.id,
        visibleColumnsOrder: selectedColumns.map((col) => col.id).join(','),
        isDefault: view.id === this.collectionViewState.views.defaultViewId,
      }),
    );
  }

  _actionSelectedBI(actionIndex: number, actionName: ViewActionNameBI) {
    const { table, views } = this.collectionViewState;
    this.reportBI(
      withoutDefaults(cairoManageViewActionSelected)({
        ...table._commonDynamicBiParams(),
        actionName,
        currentView: views.currentView?.id,
        actionIndex,
        numActions: 5,
      }),
    );
  }

  saveViewChangesSelectedBI() {
    this._actionSelectedBI(1, 'view-save-changes');
  }

  saveViewChangesBI(view: PrivateView<F>, oldView?: PrivateView<F>) {
    this._saveViewBI(view, 'save changes', oldView);
  }

  saveNewViewSelectedBI() {
    this._actionSelectedBI(2, 'view-save-new');
  }

  saveNewViewBI(view: PrivateView<F>) {
    this._saveViewBI(view, 'save as new view');
  }

  deleteViewSelectedBI() {
    this._actionSelectedBI(5, 'view-delete');
  }

  deleteViewBI(view: PrivateView<F>) {
    const { table, views } = this.collectionViewState;
    this.reportBI(
      withoutDefaults(cairoViewDeleted)({
        numFiltersInView: table.collection.result.originQuery.search?.length
          ? table.collection.query.activeFiltersCount - 1
          : table.collection.query.activeFiltersCount,
        viewFilters: JSON.stringify(view.filters),
        viewName: view.name,
        viewId: view.id,
        wasSelected: true,
        isDefault: view.id === views.defaultViewId,
      }),
    );
  }

  renameViewSelectedBI() {
    this._actionSelectedBI(3, 'view-rename');
  }

  renameViewBI(view: PrivateView<F>, oldName: string) {
    this._saveViewBI(view, 'rename', { ...view, name: oldName });
  }

  setAsDefaultViewSelectedBI(isDefault: boolean) {
    this._actionSelectedBI(
      4,
      isDefault ? 'view-set-as-default' : 'view-unset-as-default',
    );
  }

  setAsDefaultViewBI(isDefault: boolean, view: PrivateView<F>) {
    this._saveViewBI(
      view,
      isDefault ? 'set-as-default' : 'unset-as-default',
      view,
    );
  }

  undoActionBI({
    actionName,
    viewId,
    newName,
  }: {
    actionName: ViewActionNameBI;
    viewId: string;
    newName?: string;
  }) {
    const { views, queryCompareHelper } = this.collectionViewState;
    const view = views.getView(viewId);
    this.reportBI(
      withoutDefaults(cairoUndoClicked)({
        actionName,
        viewId: view?.id,
        viewName: view?.name,
        viewNameApplied: newName ?? view?.name,
        changedAttributes:
          view && actionName === 'view-save-changes'
            ? this._getViewChanges(
                view,
                queryCompareHelper.currentViewBase ?? {},
              )
            : undefined,
      }),
    );
  }

  tryAgainBI({ actionName }: { actionName: ViewActionNameBI }) {
    const { table } = this.collectionViewState;
    this.reportBI(
      withoutDefaults(cairoTryAgainClicked)({
        actionName,
        isFromSearch: !!table.collection.result.originQuery.search,
        numOfWaitingUpdates: 1,
      }),
    );
  }

  errorBI({
    actionName,
    createdAt,
    viewId,
  }: {
    actionName: ViewActionNameBI;
    createdAt: number;
    viewId: string;
  }) {
    const { table } = this.collectionViewState;

    this.reportBI(
      withoutDefaults(cairoViewsUnsuccessfulUpdateInServer)({
        actionName,
        errorType: 'Update Failed',
        timeFromEndAction: Date.now() - createdAt,
        numOfWaitingUpdates: 1,
        isFromSearch: !!table.collection.result.originQuery.search,
        viewId,
      }),
    );
  }

  clickOnViewDropdownBI() {
    this.reportBI(
      withoutDefaults(wixPatternsClickOnViewDropdownSrc144Evid4)({}),
    );
  }
}
