import { fetchBuckets, fetchMetrics, fetchServices } from 'modules/api_data/actions'
import { getStartTime } from 'modules/user_session/actions'
import { BucketType, RangeType } from 'modules/api_data/types'
import UrlUtils from 'utils/UrlUtils'

export const DEFAULT_REDUCER_KEY = 'metrics_data'

export function hideMetricId (metricId, reducerKey = DEFAULT_REDUCER_KEY, urlStr) {
  return function (dispatch, getState) {
    let metricIds = getState()[reducerKey].curMetricIds.slice(0)
    metricIds.splice(metricIds.indexOf(metricId), 1)
    if (metricIds.length === 0) {
      return
    }
    return dispatch(fetchMetricsData(undefined, metricIds, undefined, undefined, reducerKey, urlStr))
      .then(() => { dispatch(setCurMetricIds(metricIds)) })
  }
}

export function showMetricId (metricId, reducerKey = DEFAULT_REDUCER_KEY, urlStr) {
  return function (dispatch, getState) {
    let metricIds = getState()[reducerKey].curMetricIds.slice(0)
    metricIds.push(metricId)
    return dispatch(fetchMetricsData(undefined, metricIds, undefined, undefined, reducerKey, urlStr))
      .then(() => { dispatch(setCurMetricIds(metricIds)) })
  }
}

export const SET_CUR_METRIC_IDS = 'SET_CUR_METRIC_IDS'
export const setCurMetricIds = (metricIds, reducerKey = DEFAULT_REDUCER_KEY) => {
  return {
    type: SET_CUR_METRIC_IDS,
    metricIds: metricIds,
    reducerKey: reducerKey
  }
}

export const SET_CUR_SERVICE_IDS = 'SET_CUR_SERVICE_IDS'
export const setCurServiceIds = (serviceIds, reducerKey = DEFAULT_REDUCER_KEY) => {
  return {
    type: SET_CUR_SERVICE_IDS,
    serviceIds: serviceIds,
    reducerKey: reducerKey
  }
}

export const SET_CUR_BUCKET_ID = 'SET_CUR_BUCKET_ID'
export const setCurBucketId = (bucketId, reducerKey = DEFAULT_REDUCER_KEY) => {
  return {
    type: SET_CUR_BUCKET_ID,
    bucketId: bucketId,
    reducerKey: reducerKey
  }
}

export const SET_CUR_BUCKET_TYPE = 'SET_CUR_BUCKET_TYPE'
export function setCurBucketType (bucketType, reducerKey = DEFAULT_REDUCER_KEY, doFetchBuckets = true) {
  return function (dispatch, getState) {
    dispatch(reallySetCurBucketType(bucketType, reducerKey))
    if (doFetchBuckets) {
      const bucketType = getState()[reducerKey].curBucketType
      const startTime = getState().user_session.startTime
      const endTime = getState()[reducerKey].curRangeEnd
      return dispatch(fetchBuckets(bucketType, startTime, endTime)).then(() => {
        dispatch(
          function (dispatch, getState) {
            let bucketId = ''
            const existingBuckets = getState().api_data.ranges
            const buckets = existingBuckets[startTime][endTime][bucketType].buckets
            if (buckets.length > 0) {
              bucketId = buckets[buckets.length - 1]
            }
            dispatch(setCurBucketId(bucketId, reducerKey))
          }
        )
      })
    }
  }
}

const reallySetCurBucketType = (bucketType, reducerKey = DEFAULT_REDUCER_KEY) => {
  return {
    type: SET_CUR_BUCKET_TYPE,
    bucketType: bucketType,
    reducerKey: reducerKey
  }
}

export const SET_CUR_TIME_RANGE = 'SET_CUR_TIME_RANGE'
export function setCurTimeRange (rangeType, reducerKey = DEFAULT_REDUCER_KEY, doFetchBuckets = true) {
  return function (dispatch, getState) {
    let startTime = getState().user_session.startTime
    if (startTime === '') {
      dispatch(getStartTime())
    }
    startTime = getState().user_session.startTime
    dispatch(reallySetCurTimeRange(rangeType, startTime, reducerKey))
    if (doFetchBuckets) {
      const state = getState()
      const bucketType = state[reducerKey].curBucketType
      const startTime = state.user_session.startTime
      const endTime = state[reducerKey].curRangeEnd
      dispatch(fetchBuckets(bucketType, startTime, endTime))
    }
  }
}

function reallySetCurTimeRange (rangeType, startEpoc, reducerKey = DEFAULT_REDUCER_KEY) {
  let startTime = new Date()
  startTime.setTime(startEpoc)
  let endTime = new Date()
  endTime.setTime(startTime.getTime())
  if (rangeType === RangeType.LAST_DAY) {
    endTime.setHours(0)
    endTime.setMinutes(0)
    endTime.setSeconds(0)
  }
  if (rangeType === RangeType.LAST_WEEK) {
    endTime.setHours(startTime.getHours() - 168)
  }
  if (rangeType === RangeType.LAST_MONTH) {
    endTime.setHours(startTime.getHours() - 730)
  }
  if (rangeType === RangeType.LAST_YEAR) {
    endTime.setHours(startTime.getHours() - 8760)
  }
  return {
    type: SET_CUR_TIME_RANGE,
    rangeType: rangeType,
    endTime: `${endTime.getTime()}`,
    reducerKey: reducerKey
  }
}

function handleBucketTypeBasedOnRangeType (rangeType, bucketType) {
  if (rangeType === RangeType.LAST_DAY && bucketType !== BucketType.DAY) {
    return BucketType.DAY
  } else if (rangeType === RangeType.LAST_WEEK) {
    if (!(bucketType === BucketType.DAY || bucketType === BucketType.WEEK)) {
      return BucketType.WEEK
    }
  } else if (rangeType === RangeType.LAST_MONTH && bucketType === BucketType.YEAR) {
    return BucketType.MONTH
  } else if (rangeType === RangeType.LAST_YEAR && bucketType === BucketType.DAY) {
    return BucketType.WEEK
  }
  return bucketType
}

export const REQUEST_METRICS_DATA = 'REQUEST_METRICS_DATA'
const requestMetricsData = (reducerKey = DEFAULT_REDUCER_KEY) => {
  return {
    type: REQUEST_METRICS_DATA,
    reducerKey
  }
}

export const RECEIVE_METRICS_DATA = 'RECEIEVE_METRICS_DATA'
const receiveMetricsData = (reducerKey = DEFAULT_REDUCER_KEY) => {
  return {
    type: RECEIVE_METRICS_DATA,
    reducerKey
  }
}

export const RECEIVE_METRICS_DATA_ERROR = 'RECEIVE_METRICS_DATA_ERROR'
const receiveMetricsDataError = (error, reducerKey = DEFAULT_REDUCER_KEY) => {
  return {
    type: RECEIVE_METRICS_DATA_ERROR,
    error: error,
    reducerKey
  }
}

export function fetchMetricsData (serviceIds, metricIds, rangeType, bucketType,
  reducerKey = DEFAULT_REDUCER_KEY, urlToUpdate) {
  return function (dispatch, getState) {
    dispatch(requestMetricsData(reducerKey))

    let tasks = []

    // Set our params if either weren't defined.
    if (rangeType === undefined) {
      rangeType = getState()[reducerKey].curRangeType
    }
    if (bucketType === undefined) {
      bucketType = getState()[reducerKey].curBucketType
    }
    if (metricIds === undefined) {
      metricIds = getState()[reducerKey].curMetricIds
    } else {
      tasks.push(dispatch(setCurMetricIds(metricIds, reducerKey)))
    }
    if (serviceIds === undefined) {
      serviceIds = getState()[reducerKey].curServiceIds
    } else {
      tasks.push(dispatch(setCurServiceIds(serviceIds, reducerKey)))
    }
    tasks.push(dispatch(setCurTimeRange(rangeType, reducerKey, false)))
    tasks.push(dispatch(fetchMetrics()))
    tasks.push(dispatch(fetchServices()))
    return Promise.all(tasks).then(() => {
      bucketType = handleBucketTypeBasedOnRangeType(rangeType, bucketType)
      if (urlToUpdate !== undefined) {
        urlToUpdate += `?bucketType=${bucketType.name.toLowerCase()}`
        urlToUpdate += `&rangeType=${rangeType.name.toLowerCase()}`
        urlToUpdate += `&metrics=${metricIds}`
        UrlUtils.updateUrl(urlToUpdate)
      }
      dispatch(setCurBucketType(bucketType, reducerKey, false))
      const startTime = getState().user_session.startTime
      const endTime = getState()[reducerKey].curRangeEnd
      return dispatch(fetchBuckets(bucketType, startTime, endTime, serviceIds, metricIds))
    })
    .then(() => {
      const bucketType = getState()[reducerKey].curBucketType
      const startTime = getState().user_session.startTime
      const endTime = getState()[reducerKey].curRangeEnd
      let bucketId = ''
      const existingBuckets = getState().api_data.ranges
      const buckets = existingBuckets[startTime][endTime][bucketType].buckets
      if (buckets.length > 0) {
        bucketId = buckets[buckets.length - 1]
      }
      return dispatch(setCurBucketId(bucketId, reducerKey))
    })
    .then(() => {
      dispatch(receiveMetricsData(reducerKey))
    }).catch(
      (error) => {
        dispatch(receiveMetricsDataError(error, reducerKey))
        return Promise.reject(error)
      }
    )
  }
}
