import _ from 'lodash'
import { take, put, spawn, call, select } from 'redux-saga/effects'

import {
  TASK__START,
  TASK__PROGRESS,
  TASK__ERROR,
  TASK__CLEAR,
} from '../../actions'

function* taskSaga(task, action) {
  yield put({ ...action, type: TASK__PROGRESS })
  try {
    const result = yield call(task, action.payload)
    const { id, name, payload, onSuccessDispatch } = action
    if (onSuccessDispatch) {
      yield put({
        type: onSuccessDispatch,
        name,
        id,
        payload,
        result,
      })
    }
    yield put({ type: TASK__CLEAR, id, name })
  } catch (error) {
    const { id, name } = action
    yield put({
      type: TASK__ERROR,
      id,
      name,
      errorMessage: error.message,
    })
  }
}

export default (registry) =>
  function* tasksSaga() {
    while (true) {
      const action = yield take(TASK__START)
      const { name, id } = action
      const task = registry[action.name]
      if (!task) {
        throw Error(`Task "${name}" is not registered!`)
      }
      const status = yield select((state) =>
        _.get(state, ['tasks', name, id, 'status'])
      )
      if (status === 'progress') {
        throw Error(
          `Cannot start task "${name}.${id}" because it is already in progress!`
        )
      }
      yield spawn(taskSaga, task, action)
    }
  }

@@ -750,16 +750,250 @@
 %0A  %7D%0A%7D%0A%0A
+/**%0A * Creates the saga required for the %60Task%60 component%0A * @param %7BObject%7D registry - An object mapping _tasks_ to names.%0A * A task is a function which takes a payload and returns a %7BPromise%7D.%0A * @returns %7BGenerator%7D - The saga%0A */%0A
 export d

Add docstring to Task saga