import {
  CollectionState,
  FiltersMap,
  SortOrder,
  WixPatternsContainer,
} from '@wix/bex-core';
import {
  ToolbarCollectionState,
  ToolbarCollectionStateParamsInitParams,
} from './ToolbarCollectionState';
import { TableVirtualState } from './TableVirtualState';
import { DragAndDropState } from '../components/DragAndDrop';
import { ICollectionComponentState } from './ICollectionComponentState';
import { LoadingRowState } from '../components/LoadingRow/LoadingRowState';

export interface TableStateParams<T, F extends FiltersMap> {
  readonly collection: CollectionState<T, F>;
  readonly container: WixPatternsContainer;
  readonly toolbar?: ToolbarCollectionState<T, F>;
}

interface TableDragAndDropStateBase<T, F extends FiltersMap> {
  getStickyColumnsCount: (params: { stickyColumns: number }) => number;
  init: () => void;
  dnd: DragAndDropState<T, F>;
}

export interface TableStateInitParams
  extends ToolbarCollectionStateParamsInitParams {
  hasMultiLevelSorting?: boolean;
}

export interface TableStatePublicAPI<T, F extends FiltersMap> {
  /**
   * Underlying [CollectionState](./?path=/story/common-state--collectionstate) instance
   * @external
   */
  readonly collection: CollectionState<T, F>;
  /**
   * Underlying [ToolbarCollectionState](./?path=/story/common-state--toolbarcollectionstate) instance
   * @external
   */
  readonly toolbar: ToolbarCollectionState<T, F>;
  /**
   * Reset active filters & sorting and adds new items to the collection.
   * @external
   * @param items - new items to add to the collection
   */
  onAddItemActionComplete(items: T[]): void;

  /**
   * Visible columns as selected via [CustomColumns](./?path=/story/features-display--customcolumns)
   * @external
   */
  readonly visibleColumns: { id: string }[];

  /**
   * Sorts the collection by a specified column and optional sort direction.
   * @external
   */
  sort: (columnId: string, params: { forceDirection?: SortOrder }) => void;
}

export class TableState<T, F extends FiltersMap>
  implements ICollectionComponentState, TableStatePublicAPI<T, F>
{
  readonly toolbar;
  readonly virtual;
  readonly loadingRowState;

  tableDragAndDropState: TableDragAndDropStateBase<T, F> | null = null;

  /** The sticky table header element (column headers row) */
  headerElement: HTMLElement | null = null;

  constructor(params: TableStateParams<T, F>) {
    this.toolbar =
      params.toolbar ??
      new ToolbarCollectionState({
        collection: params.collection,
        container: params.container,
        componentType: 'Table',
      });

    this.virtual = new TableVirtualState({
      table: this,
    });

    this.loadingRowState = new LoadingRowState();
  }

  get visibleColumns() {
    return this.toolbar.selectedOrderedColumnsOrAll;
  }

  // backwards compat
  get table() {
    return this.toolbar;
  }

  get collection() {
    return this.table.collection;
  }

  get tableState() {
    return this;
  }

  get itemsContentWidth() {
    return this.toolbar.itemsContentRect.rect.width ?? 0;
  }

  get itemsToRenderCount() {
    return this.collection.result.size;
  }

  init(params: TableStateInitParams) {
    return this.table.init(params);
  }

  get keyedItems() {
    return this.collection.result.keyedItems;
  }

  getStickyColumnsCount(params: {
    stickyColumns?: number;
    horizontalScroll?: boolean;
    showSelection?: boolean;
    stickySelectionColumn?: boolean;
  }) {
    const { horizontalScroll } = params;

    if (!horizontalScroll) {
      return params.stickyColumns;
    }

    const { tableDragAndDropState, toolbar } = this;

    const {
      customColumnsState,
      customColumnsProps,
      customColumnsStateInitialized,
    } = toolbar;

    const { stickySelectionColumn, showSelection } = params;

    let stickyColumns = params.stickyColumns ?? 0;

    const customColumnsIsEffective =
      customColumnsProps && customColumnsState && customColumnsStateInitialized;

    const reorderDisabledColumnsIsEffective =
      !!customColumnsState?.dragAndDrop?.orderedColumnsByReorderDisabled
        .reorderDisabled?.length;

    if (customColumnsIsEffective) {
      stickyColumns = customColumnsState.getStickyColumnsCount({
        ...params,
        stickyColumns,
      });
    }

    if (tableDragAndDropState) {
      stickyColumns = tableDragAndDropState.getStickyColumnsCount({
        ...params,
        stickyColumns,
      });
    }

    const checkboxColumnStickyCompat =
      reorderDisabledColumnsIsEffective ||
      stickySelectionColumn ||
      tableDragAndDropState != null;

    if (showSelection && checkboxColumnStickyCompat) {
      stickyColumns += 1;
    }

    return stickyColumns;
  }

  get showEmptyState() {
    return this.toolbar.multi.showEmptyState;
  }

  get hasAvailableItems() {
    return this.toolbar.multi.hasAvailableItems;
  }

  get resultOriginQuerySearch() {
    return this.toolbar.multi.resultOriginQuerySearch;
  }

  get hasNonPersistentActiveFilters() {
    return this.toolbar.multi.hasNonPersistentActiveFilters;
  }

  get showErrorState() {
    return this.toolbar.multi.showErrorState;
  }

  get errorStatus() {
    return this.toolbar.multi.errorStatus;
  }

  get showLoadingState() {
    const { initTask, toolbar } = this;
    return (
      initTask.status.isIdle ||
      initTask.status.isLoading ||
      toolbar.multi.showLoadingState
    );
  }

  get initTask() {
    return this.toolbar.initTask;
  }

  retryErrorState = () => this.toolbar.retryErrorState();

  onAddItemActionComplete = async (items: T[]) => {
    return this.toolbar.onAddItemActionComplete(items);
  };

  sort = (
    columnId: string,
    { forceDirection }: { forceDirection?: SortOrder } = {},
  ) => {
    this.collection.sort({ id: columnId }, { forceDirection });
  };
}
