import { action, computed, makeObservable, reaction } from 'mobx';
import { ToolbarBIReporter } from './ToolbarBIReporter';
import {
  BulkActionModalState,
  FiltersMap,
  KeyedItem,
  MultiCollectionSupport,
  Translate,
} from '@wix/bex-core';
import { SidePanelsState } from './SidePanelsState';
import { createRef, RefObject } from 'react';

interface SelectAllLocationParams {
  location: 'TableToolbar CTA' | 'Checkbox';
}

export interface BulkActionToolbarStateParams<T, F extends FiltersMap> {
  readonly toolbarBIReporter: ToolbarBIReporter<T, F>;
  readonly panels: SidePanelsState;
  readonly multi: MultiCollectionSupport<F>;
  readonly translate: Translate;
  readonly scrollToTop: () => unknown;
}

export type SelectionDisabledProp =
  | ((rowData: KeyedItem<unknown>) => boolean | void)
  | boolean;

export type CheckboxTooltipContentProp = (
  rowData: KeyedItem<unknown>,
) => string | undefined;

export class BulkActionToolbarState<T, F extends FiltersMap> {
  readonly toolbarBIReporter;
  readonly panels;
  readonly multi;

  readonly modals;

  readonly bulkSelectionCheckboxRef: RefObject<HTMLInputElement> =
    createRef<HTMLInputElement>();

  selectionDisabledProp: SelectionDisabledProp = () => false;
  checkboxTooltipContentProp?: CheckboxTooltipContentProp;
  shouldIncludeCollection?: (collection: any) => boolean;

  selectionDisabledFn = ({ key }: { key: string }) => {
    const { selectionDisabledProp } = this;

    if (typeof selectionDisabledProp === 'function') {
      const keyedItem = this._getCollectionOf(key)?.result.get(key);
      if (keyedItem == null) {
        return false;
      }
      return Boolean(selectionDisabledProp(keyedItem));
    }

    return () => !!selectionDisabledProp;
  };

  getCheckboxTooltipContent = ({
    key,
  }: {
    key: string;
  }): string | undefined => {
    const { checkboxTooltipContentProp } = this;
    if (typeof checkboxTooltipContentProp === 'function') {
      const keyedItem = this._getCollectionOf(key)?.result.get(key);
      if (keyedItem != null) {
        return checkboxTooltipContentProp(keyedItem);
      }
    }

    return undefined;
  };

  constructor(params: BulkActionToolbarStateParams<T, F>) {
    this.toolbarBIReporter = params.toolbarBIReporter;
    this.panels = params.panels;
    this.multi = params.multi;
    this.modals = new BulkActionModalState({
      translate: params.translate,
      scrollToTop: params.scrollToTop,
    });

    makeObservable(this, {
      hasClickableRows: computed,
      reachedMaxSelection: computed,
      total: computed,
      selectedCountOrTotal: computed,
      selectedIds: computed,
    });
  }

  maxSelection?: number;

  _selectionStartTime = 0;

  private get filteredCollections() {
    return this.shouldIncludeCollection
      ? this.multi.collections.filter(this.shouldIncludeCollection)
      : this.multi.collections;
  }

  get selectedIds() {
    return this.multi.collections.reduce(
      (a, { bulkSelect }) => [...a, ...bulkSelect.selectedIds],
      [] as string[],
    );
  }

  get selectedValues() {
    return this.multi.collections.reduce(
      (a, { bulkSelect }) => [...a, ...bulkSelect.selectedValues],
      [] as unknown[],
    );
  }

  get uncheckedValues() {
    return this.multi.collections.reduce(
      (a, { bulkSelect }) => [...a, ...bulkSelect.uncheckedValues],
      [] as unknown[],
    );
  }

  get selectedCount() {
    return this.filteredCollections.reduce(
      (s, { bulkSelect }) => s + bulkSelect.selectedCount,
      0,
    );
  }

  get selectedCountOrTotal() {
    if (this.allSelected) {
      return this.filteredCollections.reduce(
        (s, { bulkSelect }) => s + bulkSelect.selectedCountOrTotal,
        0,
      );
    }

    return this.selectedCount;
  }

  get hasClickableRows() {
    return this.filteredCollections.some(({ bulkSelect, ...collection }) =>
      collection.result.keyedItems.some(
        (row) =>
          !bulkSelect.select.isChecked(row.key) &&
          !this.isRowCheckboxDisabled(row),
      ),
    );
  }

  get allSelected() {
    return this.filteredCollections.every(
      ({ bulkSelect }) => bulkSelect.allSelected,
    );
  }

  get reachedMaxSelection(): boolean {
    const { maxSelection, selectedCount } = this;
    if (maxSelection != null) {
      return selectedCount >= maxSelection;
    }
    return false;
  }

  get total() {
    return this.filteredCollections.reduce(
      (s, { result: { total } }) => s + total,
      0,
    );
  }

  isChecked(key: string) {
    return this.multi.collections.some(({ bulkSelect }) =>
      bulkSelect.isChecked(key),
    );
  }

  clearSelection = () => {
    this.multi.collections.forEach(({ bulkSelect }) => {
      bulkSelect.resetToDefaults();
    });
  };

  isRowCheckboxDisabled = action((row: { key: string }) => {
    return (
      (this.reachedMaxSelection && !this.isChecked(row.key)) ||
      this.selectionDisabledFn(row)
    );
  });

  toggleSelectAll = action((params: SelectAllLocationParams) => {
    if (!this.hasClickableRows) {
      this.deselectAll(params);
    } else if (this.maxSelection != null) {
      this.selectAllUpToMaxSelection();
    } else {
      this.selectAll(params);
    }
  });

  selectAllUpToMaxSelection() {
    for (const collection of this.filteredCollections) {
      if (this.reachedMaxSelection) {
        break;
      }
      for (const item of collection.result.keyedItems) {
        if (this.reachedMaxSelection) {
          break;
        }

        if (!this.isRowCheckboxDisabled(item)) {
          collection.bulkSelect.select.set(item);
        }
      }
    }
  }

  selectAll({ location }: SelectAllLocationParams) {
    const onSelectAllToggledEnd = this.toolbarBIReporter.selectAllToggledStart({
      location,
    });

    this.filteredCollections.forEach((collection) =>
      collection.bulkSelect.selectAll(),
    );
    onSelectAllToggledEnd();
  }

  deselectAll({ location }: SelectAllLocationParams) {
    const onSelectAllToggledEnd = this.toolbarBIReporter.selectAllToggledStart({
      location,
    });
    this.filteredCollections.forEach((collection) =>
      collection.bulkSelect.deselectAll(),
    );
    onSelectAllToggledEnd();
    this.bulkSelectionCheckboxRef.current?.focus();
  }

  _getCollectionOf(id: string) {
    return this.multi.collections.find((collection) =>
      collection.result.has(id),
    );
  }

  selectOne(id: string) {
    const onSelectionToggledEnd =
      this.toolbarBIReporter.itemSelectionToggledStarted({
        itemId: id,
        clickType: 'Selection',
      });

    this._getCollectionOf(id)?.bulkSelect.selectOne(id);

    onSelectionToggledEnd();
  }

  deselectOne(id: string) {
    const onSelectionToggledEnd =
      this.toolbarBIReporter.itemSelectionToggledStarted({
        itemId: id,
        clickType: 'Deselection',
      });

    this._getCollectionOf(id)?.bulkSelect.deselectOne(id);

    onSelectionToggledEnd();
  }

  init() {
    const disposers = [
      ...this.multi.collections.map(({ bulkSelect }) =>
        reaction(
          () => ({
            selectedValues: bulkSelect.select.selectedValues,
          }),
          ({ selectedValues }) => {
            if (this.selectionDisabledFn == null) {
              return;
            }

            for (const keyedItem of selectedValues) {
              const collectionItem = bulkSelect.getCollectionItem(
                keyedItem.key,
              );

              if (collectionItem && this.selectionDisabledFn(collectionItem)) {
                bulkSelect.deselectOneItem(keyedItem);
              }
            }
          },
        ),
      ),
    ];

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