import type { ModelName, User } from '@types'

import type { Action } from '../actions.types'

export type MutationId = string & { readonly ___type: 'Mutation' }

/**
 * Flags the given string as a MutationId.
 */
export const toMutationId = (id: string): MutationId => id as MutationId

/**
 * The interface of the action executor.
 */
export type IActionExecution = {
  name: string
  user: User
  init({ action, user }: { action: Action; user: User }): Promise<void>

  /**
   * Marks the ActionExecution as finished successfully.
   *
   * This method needs to accept anything that the actual dispatcher functions can return.
   * This is often "void" - but can also be any other type.
   */
  // eslint-disable-next-line @typescript-eslint/no-invalid-void-type
  success(result?: object | null | undefined | void): Promise<void>

  /**
   * Marks the ActionExecution as finished with an error.
   */
  error(error: unknown): Promise<void>

  startCreateMutation({ model, createObject }: { model: ModelName; createObject: object }): Promise<MutationId>

  startCreateManyMutation({ model, createObjects }: { model: ModelName; createObjects: object[] }): Promise<MutationId>

  startUpdateMutation({
    model,
    entityId,
    sourceObject,
    updateObject,
  }: {
    model: ModelName
    entityId: string
    sourceObject: object
    updateObject: object
  }): Promise<MutationId>

  startDeleteMutation({
    model,
    entityId,
    sourceObject,
  }: {
    model: ModelName
    entityId: string
    sourceObject: object
  }): Promise<MutationId>

  finishCreateMutation({
    mutationId,
    entityId,
    createdObject,
  }: {
    mutationId: MutationId
    entityId: string
    createdObject: object
  }): Promise<void>

  finishCreateManyMutation({
    mutationId,
    entityIds,
    createdObjects,
  }: {
    mutationId: MutationId
    entityIds: string[]
    createdObjects: object
  }): Promise<void>

  finishUpdateMutation({ mutationId, updatedObject }: { mutationId: MutationId; updatedObject: object }): Promise<void>

  finishDeleteMutation({ mutationId }: { mutationId: MutationId }): Promise<void>

  errorMutation({ mutationId, error }: { mutationId: MutationId; error: unknown }): Promise<void>
}
