import {
  FiltersMap,
  UpdateManyParams,
  OptimisticActions,
  CreateManyParams,
  DeleteManyParams,
  UpdateAllParams,
  ToastConfig,
} from '@wix/bex-core';
import { NestedTableNodeState } from './NestedTableNodeState';
import once from 'lodash/once';

export class NestedTableNodeStateOptimisticActions<
  C extends string,
  T,
  F extends FiltersMap,
> implements OptimisticActions<T>
{
  readonly node;

  constructor(node: NestedTableNodeState<C, T, F>) {
    this.node = node;
  }

  _runAction<
    A extends {
      submit: (...args: any) => any;
      successToast?: ToastConfig | string;
      errorToast?: (
        err: unknown,
        params: { retry: () => void },
      ) => ToastConfig | string;
    },
  >(
    action: (optimisticActions: OptimisticActions<T>, params: A) => void,
    params: A,
  ) {
    const {
      node: { flatModeCollection, children },
    } = this;

    const submit = once(params.submit);

    if (flatModeCollection?._optimisticActions) {
      action(flatModeCollection._optimisticActions, {
        ...params,
        submit,
        successToast: undefined,
        errorToast: undefined,
      });
    }

    if (children?._optimisticActions) {
      action(children._optimisticActions, {
        ...params,
        submit,
      });
    }
  }

  createOne(item: T, params: CreateManyParams<T>) {
    this.createMany([item], params);
  }

  createMany(items: T[], params: CreateManyParams<T>) {
    this._runAction((a, p) => a.createMany(items, p), params);
  }
  updateAll<R>(patchOrFn: (item: T) => Partial<T>, params: UpdateAllParams<R>) {
    this._runAction((a, p) => a.updateAll(patchOrFn, p), params);
  }
  deleteMany<R>(items: T[], params: DeleteManyParams<T, R>) {
    this._runAction((a, p) => a.deleteMany(items, p), params);
  }
  deleteOne<R>(item: T, params: DeleteManyParams<T, R>) {
    this.deleteMany([item], params);
  }
  deleteAll<R>(params: UpdateAllParams<R>) {
    this._runAction((a, p) => a.deleteAll(p), params);
  }

  updateMany<R>(items: T[], params: UpdateManyParams<T, R>) {
    this._runAction((a, p) => a.updateMany(items, p), params);
  }

  updateOne<R>(item: T, params: UpdateManyParams<T, R>) {
    this.updateMany([item], params);
  }
}
