import { get, orderBy } from 'lodash'
import { selectCurrentUser } from 'xpub-selectors'
import {
  get as apiGet,
  create,
  remove,
  update,
} from 'pubsweet-client/src/helpers/api'
import { orderReviewers } from './utils'

const GET_REVIEWERS_REQUEST = 'GET_REVIEWERS_REQUEST'
const GET_REVIEWERS_ERROR = 'GET_REVIEWERS_ERROR'
const GET_REVIEWERS_SUCCESS = 'GET_REVIEWERS_SUCCESS'

export const getReviewersRequest = () => ({
  type: GET_REVIEWERS_REQUEST,
})

export const getReviewersError = error => ({
  type: GET_REVIEWERS_ERROR,
  error,
})

export const getReviewersSuccess = reviewers => ({
  type: GET_REVIEWERS_SUCCESS,
  payload: { reviewers },
})

// reviewer invite constants and action creators
const INVITE_REVIEWER_REQUEST = 'INVITE_REVIEWER_REQUEST'
const INVITE_REVIEWER_SUCCESS = 'INVITE_REVIEWER_SUCCESS'
const INVITE_REVIEWER_ERROR = 'INVITE_REVIEWER_ERROR'

const inviteRequest = () => ({
  type: INVITE_REVIEWER_REQUEST,
})

const inviteSuccess = () => ({
  type: INVITE_REVIEWER_SUCCESS,
})

const inviteError = error => ({
  type: INVITE_REVIEWER_ERROR,
  error,
})

// reviewer decision constants and action creators
const REVIEWER_DECISION_REQUEST = 'REVIEWER_DECISION_REQUEST'
const REVIEWER_DECISION_ERROR = 'REVIEWER_DECISION_ERROR'
const REVIEWER_DECISION_SUCCESS = 'REVIEWER_DECISION_SUCCESS'

const reviewerDecisionRequest = () => ({ type: REVIEWER_DECISION_REQUEST })
const reviewerDecisionError = error => ({
  type: REVIEWER_DECISION_ERROR,
  error,
})
const reviewerDecisionSuccess = () => ({ type: REVIEWER_DECISION_SUCCESS })

const initialState = {
  fetching: {
    decision: false,
    invite: false,
    reviewers: false,
  },
  error: null,
  reviewers: [],
}

// selectors
export const selectReviewers = state => get(state, 'reviewers.reviewers') || []
export const selectReviewersError = state => get(state, 'reviewers.error')
export const selectFetchingReviewers = state =>
  get(state, 'reviewers.fetching.reviewers') || false
export const selectFetchingInvite = state =>
  get(state, 'reviewers.fetching.invite') || false
export const selectFetchingDecision = state =>
  get(state, 'reviewers.fetching.decision') || false

export const selectInvitation = (state, collectionId) => {
  const currentUser = selectCurrentUser(state)
  const collection = state.collections.find(c => c.id === collectionId)
  const invitations = get(collection, 'invitations') || []
  return invitations.find(
    i => i.userId === currentUser.id && i.role === 'reviewer' && !i.hasAnswer,
  )
}

export const getCollectionReviewers = collectionId => dispatch => {
  dispatch(getReviewersRequest())
  return apiGet(`/collections/${collectionId}/invitations?role=reviewer`).then(
    r => dispatch(getReviewersSuccess(orderBy(r, orderReviewers))),
    err => dispatch(getReviewersError(err)),
  )
}

// invitation actions
export const inviteReviewer = (reviewerData, collectionId) => dispatch => {
  dispatch(inviteRequest())
  return create(`/collections/${collectionId}/invitations`, {
    ...reviewerData,
    role: 'reviewer',
  }).then(
    () => dispatch(inviteSuccess()),
    err => dispatch(inviteError(get(JSON.parse(err.response), 'error'))),
  )
}

export const setReviewerPassword = reviewerBody => dispatch => {
  dispatch(reviewerDecisionRequest())
  return create(`/users/reset-password`, reviewerBody).then(r => {
    dispatch(reviewerDecisionSuccess())
    return r
  })
}

export const revokeReviewer = (invitationId, collectionId) => dispatch => {
  dispatch(inviteRequest())
  return remove(
    `/collections/${collectionId}/invitations/${invitationId}`,
  ).then(() => dispatch(inviteSuccess()), err => dispatch(inviteError(err)))
}

// reviewer decision actions
export const reviewerDecision = (
  invitationId,
  collectionId,
  agree = true,
) => dispatch => {
  dispatch(reviewerDecisionRequest())
  // 'accept api call'
  return update(`/collections/${collectionId}/invitations/${invitationId}`, {
    isAccepted: agree,
  }).then(
    res => {
      dispatch(reviewerDecisionSuccess())
      return res
    },
    err => {
      dispatch(reviewerDecisionError(err.message))
      throw err
    },
  )
}

export const reviewerDecline = (
  invitationId,
  collectionId,
  invitationToken,
) => dispatch => {
  dispatch(reviewerDecisionRequest())
  return update(
    `/collections/${collectionId}/invitations/${invitationId}/decline`,
    {
      invitationToken,
    },
  ).then(
    res => {
      dispatch(reviewerDecisionSuccess())
      return res
    },
    err => {
      dispatch(reviewerDecisionError(err.message))
      throw err
    },
  )
}

export default (state = initialState, action = {}) => {
  switch (action.type) {
    case GET_REVIEWERS_REQUEST:
      return {
        ...state,
        fetching: {
          ...state.fetching,
          reviewers: true,
        },
        reviewers: [],
      }
    case GET_REVIEWERS_ERROR:
      return {
        ...state,
        fetching: {
          ...state.fetching,
          reviewers: false,
        },
        error: action.error,
      }
    case GET_REVIEWERS_SUCCESS:
      return {
        ...state,
        fetching: {
          ...state.fetching,
          reviewers: false,
        },
        reviewers: action.payload.reviewers,
      }
    case INVITE_REVIEWER_REQUEST:
      return {
        ...state,
        fetching: {
          ...state.fetching,
          invite: true,
        },
      }
    case INVITE_REVIEWER_SUCCESS:
      return {
        ...state,
        fetching: {
          ...state.fetching,
          invite: false,
        },
        error: null,
      }
    case INVITE_REVIEWER_ERROR:
      return {
        ...state,
        fetching: {
          ...state.fetching,
          invite: false,
        },
        error: action.error,
      }
    case REVIEWER_DECISION_REQUEST:
      return {
        ...state,
        fetching: {
          ...state.fetching,
          decision: true,
        },
      }
    case REVIEWER_DECISION_ERROR:
      return {
        ...state,
        fetching: {
          ...state.fetching,
          decision: false,
        },
        error: action.error,
      }
    case REVIEWER_DECISION_SUCCESS:
      return {
        ...state,
        fetching: {
          ...state.fetching,
          decision: false,
        },
        error: null,
      }
    default:
      return state
  }
}