// @flow
/* eslint-disable no-undef */

export type State = { [string]: any }
type SetState = (state: State, callback: () => void) => void
export type CustomSetState = (
  action: string,
  state: State,
  args: {},
) => Promise<void>

type Self = {
  state: State,
  setState: SetState,
}

type Action = (State, {}) => any
type Actions = { [string]: Action }

type Config = {
  initialState: State,
  actionsCreators: Actions,
}

type Middleware = (
  {
    initialState: State,
    actionsCreators: Actions,
  },
  self: Self,
  actions: Actions,
) => (action: string, arg: string) => void

type InitializedMiddlewares = (action: string, args: any) => void

export type ProviderType = {
  setState: SetState,
  initializedMiddlewares: InitializedMiddlewares[],
}

type Consumer = React$ComponentType<{
  children: (state: State | void) => React$Node,
}>

export type Context = {
  Consumer: Consumer,
  Provider: React$ComponentType<*>,
}

type MapStateToProps = (state: State) => State

type Connect = (
  mapStateToProps: MapStateToProps,
) => (WrappedComponent: React$ComponentType<{}>) => React$ComponentType<{}>

export type CreateConnect = Consumer => Connect

export type SetProvider = any => any

type Provider = React$ComponentType<*>

export type CreateProvider = (
  setProvider: SetProvider,
  Provider: Provider,
  initialState: State,
) => React$ComponentType<*>

export type Subscription = (action: string, state: State, args: {}) => void

type Store = {
  Provider: Provider,
  connect: Connect,
  actions: Actions,
  subscribe: (subscription: Subscription) => void,
  unsubscribe: (subscription: Subscription) => void,
}

export type CreateStore = (config: Config, middlewares: Middleware[]) => Store

declare module 'react-waterfall' {
  declare export default CreateStore
}