import {
  CollectionOptimisticActions,
  CollectionState,
  FiltersMap,
  TaskState,
  WixPatternsContainer,
  WixPatternsContainerParams,
} from '@wix/bex-core';
import { computed, makeObservable, runInAction } from 'mobx';
import {
  EditableTableState,
  EditableTablePermissions,
  EditableTableMutationHandlers,
} from './EditableTable';
import { GridState } from './GridState';
import { ICollectionComponentState } from './ICollectionComponentState';
import { ILayoutSwitchState } from './ILayoutSwitchState';
import { TableState } from './TableState';
import { ToolbarCollectionState } from './ToolbarCollectionState';
import { ViewType, ViewTypeState } from './ViewTypeState';
import type { FieldActions } from '../types/SchemaConfig';

export interface TableLayoutConfig {}

export interface GridLayoutConfig {}

export interface SpreadsheetLayoutConfig<T, F extends FiltersMap> {
  mutations: EditableTableMutationHandlers<T>;
  permissions?: EditableTablePermissions;
  fieldActions?: FieldActions;
  createOptimisticActions: (
    collection: CollectionState<T, F>,
  ) => CollectionOptimisticActions<T, F>;
}

export interface LayoutSwitchStateParams<T, F extends FiltersMap> {
  collection: CollectionState<T, F>;
  container: WixPatternsContainer;
  containerOverrides: Partial<WixPatternsContainerParams>;
  table?: TableLayoutConfig;
  grid?: GridLayoutConfig;
  spreadsheet?: SpreadsheetLayoutConfig<T, F>;
}

const componentType = 'LayoutSwitch';

export class LayoutSwitchState<T, F extends FiltersMap>
  implements ICollectionComponentState, ILayoutSwitchState<T, F>
{
  readonly collection: CollectionState<T, F>;
  readonly toolbar: ToolbarCollectionState<T, F>;
  readonly containerOverrides: Partial<WixPatternsContainerParams>;
  readonly tableState: TableState<T, F> | undefined;
  readonly gridState: GridState<T, F> | undefined;
  readonly spreadsheetState: EditableTableState<T, F> | undefined;
  readonly viewTypeState: ViewTypeState;
  readonly initTask = new TaskState();

  get viewType(): ViewType {
    return this.viewTypeState.viewType;
  }

  set viewType(v: ViewType) {
    runInAction(() => {
      this.viewTypeState.viewType = v;
    });
  }

  get options(): ViewType[] {
    return this.viewTypeState.options;
  }

  constructor(params: LayoutSwitchStateParams<T, F>) {
    this.collection = params.collection;
    this.containerOverrides = params.containerOverrides;

    this.toolbar = new ToolbarCollectionState({
      componentType,
      collection: this.collection,
      container: params.container,
      reportBi: (biParams) =>
        params.container.reportBi({
          ...biParams,
          params: {
            ...biParams.params,
            componentStatus: this.viewTypeState.viewType,
          },
        }),
    });

    this.tableState = params.table
      ? new TableState({
          collection: this.collection,
          container: params.container,
          toolbar: this.toolbar,
        })
      : undefined;

    this.gridState = params.grid
      ? new GridState({
          collection: this.collection,
          container: params.container,
          toolbar: this.toolbar,
        })
      : undefined;

    this.spreadsheetState = params.spreadsheet
      ? new EditableTableState({
          collection: this.collection,
          container: params.container,
          toolbar: this.toolbar,
          mutations: params.spreadsheet.mutations,
          permissions: params.spreadsheet.permissions,
          fieldActions: params.spreadsheet.fieldActions,
          createOptimisticActions: params.spreadsheet.createOptimisticActions,
        })
      : undefined;

    const enabledLayouts: ViewType[] = [
      params.table ? 'table' : null,
      params.grid ? 'grid' : null,
      params.spreadsheet ? 'spreadsheet' : null,
    ].filter(Boolean) as ViewType[];

    this.viewTypeState = new ViewTypeState({
      container: params.container,
      dataCapsule: this.toolbar.dataCapsule,
      componentType,
      collection: this.collection,
      options: enabledLayouts,
    });

    this.toolbar.layoutState = this;

    makeObservable(this, {
      viewType: computed,
      options: computed,
    });
  }

  init() {
    const { viewTypeState, initTask } = this;
    viewTypeState.init();

    initTask.runOnce(async () => {
      viewTypeState.initTask.runOnce();
      await viewTypeState.initTask.status.promise;
    });
  }
}
