import { Primitive } from '../'

export interface IContext<TProps> {
  props: TProps
}

export interface IBranchContext<TPaths, TProps> extends IContext<TProps> {
  path: { [key in keyof TPaths]: (props: TPaths[key]) => TPaths[key] }
}

export declare class SequenceBuilder<TContext = {}, TProps = {}, TState = {}> {
  private sequenceArray
  constructor(sequenceArray: any[])
  action<TOutput>(
    ...action: ((
      props: TContext & IContext<TProps>
    ) => TOutput | Promise<TOutput>)[]
  ): SequenceBuilder<TContext, TProps & TOutput>
  action<TOutput>(
    name: string,
    ...action: ((
      props: TContext & IContext<TProps>
    ) => TOutput | Promise<TOutput>)[]
  ): SequenceBuilder<TContext, TProps & TOutput>
  branch<TPaths, TOutput = {}>(
    action: (
      props: TContext & IBranchContext<TPaths, TProps>
    ) => TOutput | Promise<TOutput>
  ): {
    paths: (paths: {
      [key in keyof TPaths]: (
        props: SequenceBuilder<TContext, TProps & TPaths[key]>
      ) => SequenceBuilder<TContext, TProps & TPaths[key]>
    }) => SequenceBuilder<TContext, TProps & TOutput>
  }
  parallel<TOutput>(
    name: string,
    chain: (
      props: SequenceBuilder<TContext, TProps>
    ) => SequenceBuilder<TContext, TOutput>
  ): SequenceBuilder<TContext, TProps & TOutput>
  parallel<TOutput>(
    chain: (
      props: SequenceBuilder<TContext, TProps>
    ) => SequenceBuilder<TContext, TOutput>
  ): SequenceBuilder<TContext, TProps & TOutput>
  sequence<TOutput = void>(
    seq: (props: TProps) => TOutput | (() => TOutput)
  ): SequenceBuilder<TContext, TProps & TOutput>
  when<TPaths extends { true: {}; false: {} }>(
    callback: (input: TContext & IBranchContext<TPaths, TProps>) => boolean
  ): {
    paths: (paths: {
      [key in keyof TPaths]: (
        input: SequenceBuilder<TContext, TProps & TPaths[key]>
      ) => SequenceBuilder<TContext, TProps & TPaths[key]>
    }) => SequenceBuilder<TContext, TProps>
  }
  debounce<TPaths extends { continue: {}; discard: {} }>(
    ms: number
  ): {
    paths: (paths: {
      [key in keyof TPaths]: (
        input: SequenceBuilder<TContext, TProps & TPaths[key]>
      ) => SequenceBuilder<TContext, TProps & TPaths[key]>
    }) => SequenceBuilder<TContext, TProps>
  }
  equals<TPaths extends { [key: string]: {} }, TValue>(
    callback: (input: TContext & IBranchContext<TPaths, TProps>) => TValue
  ): {
    paths: (paths: {
      [key in keyof TPaths]: (
        input: SequenceBuilder<TContext, TProps & TPaths[key]>
      ) => SequenceBuilder<TContext, TProps & TPaths[key]>
    }) => SequenceBuilder<TContext, TProps>
  }
  wait(ms: number): ContinueSequenceBuilder<TContext, TProps>
}

export declare class ContinueSequenceBuilder<
  TContext = {},
  TProps = {},
> extends SequenceBuilder<TContext, TProps> {
  continue(
    arg: (
      builder: SequenceBuilder<TContext, TProps>
    ) => SequenceBuilder<TContext, TProps>
  ): SequenceBuilder<TContext, TProps>
}

export declare function sequenceFactory<TContext, TProps>(
  arg: (
    props: SequenceBuilder<TContext, TProps>
  ) => SequenceBuilder<TContext, TProps>
): Primitive

export declare function Sequence<Context, Output = {}>(
  arg: (props: SequenceBuilder<Context, {}>) => SequenceBuilder<Context, Output>
): () => Output

export declare function SequenceWithProps<Context, Props, Output = Props>(
  arg: (
    props: SequenceBuilder<Context, Props>
  ) => SequenceBuilder<Context, Output>
): (props: Props) => Output

export declare function SequenceFactory<Context>(): <Output = {}>(
  arg: (props: SequenceBuilder<Context, {}>) => SequenceBuilder<Context, Output>
) => () => Output

export declare function SequenceWithPropsFactory<Context>(): <
  Props,
  Output = Props,
>(
  arg: (
    props: SequenceBuilder<Context, Props>
  ) => SequenceBuilder<Context, Output>
) => (props: Props) => Output
