import Bucket from '../objects/Bucket'
import ApiUtil from 'utils/ApiUtil'

export const REQUEST_BUCKETS = 'REQUEST_BUCKETS'
export const RECEIVE_BUCKETS = 'RECEIVE_BUCKETS'

const requestBuckets = () => ({
  type: REQUEST_BUCKETS
})

function receiveBuckets (buckets, bucketType, startTime, endTime, serviceIds, metricIds) {
  return {
    type: RECEIVE_BUCKETS,
    buckets,
    bucketType,
    startTime,
    endTime,
    serviceIds,
    metricIds
  }
}

function getBucketsForServiceMetric (serviceId, metricId, bucketType, startTime, endTime, json) {
  let buckets = []
  json.time_series.forEach((data) => {
    let bucket = new Bucket(bucketType, serviceId, metricId, data, startTime, endTime, json.time_series_units)
    buckets.push(bucket)
  })
  return buckets
}

const fetchBucketsForServiceMetric = (service, metricId, bucketType, startTime, endTime) => {
  return function (dispatch, getState) {
    return ApiUtil.getBuckets(service.id, service.type.name.toLowerCase(), metricId, startTime, endTime, bucketType)
    .then(
      json => {
        const buckets = getBucketsForServiceMetric(service.id, metricId, bucketType, startTime, endTime, json)
        dispatch(receiveBuckets(buckets, bucketType, startTime, endTime, [service.id], [metricId]))
        return buckets
      }
    )
    .catch(error => {
      if (error.message === '501') {
        dispatch(receiveBuckets([], bucketType, startTime, endTime, [service.id], [metricId]))
        return []
      } else if (error.message === '404') {
        dispatch(receiveBuckets([], bucketType, startTime, endTime, [service.id], [metricId]))
        // error = new Error(`Could not find '${metricId}' data for '${service.id}'`)
        // return Promise.reject(error)
      } else {
        return Promise.reject(error)
      }
    })
  }
}

export function fetchBuckets (bucketType, startTime, endTime, serviceIds, metricIds) {
  return function (dispatch, getState) {
    dispatch(requestBuckets())
    const state = getState()
    // Replace missing params with thats in our state.
    if (serviceIds === undefined) {
      serviceIds = Object.keys(state.api_data.services)
    }
    if (metricIds === undefined) {
      metricIds = state.api_data.metricIds
    }

    // Now for each service+metric, fetch the buckets if we don't already have data for this pair.
    let tasks = []
    serviceIds.forEach((serviceId) => {
      const service = state.api_data.services[serviceId]
      metricIds.forEach((metricId) => {
        if (!hasBuckets(state.api_data.ranges, serviceId, metricId, bucketType, startTime, endTime)) {
          let task = null
          const metric = state.api_data.metrics[metricId]
          if (service.hasMetrics && metric.isValidForService(service)) {
            task = dispatch(fetchBucketsForServiceMetric(service, metricId, bucketType, startTime, endTime))
          } else {
            task = dispatch(receiveBuckets([], bucketType, startTime, endTime, [service.id], [metricId]))
          }
          tasks.push(task)
        }
      })
    })
    return Promise.all(tasks)
    // HACK: Normally we'd just return the Promise, but adding an extra then here to calculate the project health
    //  for each service in each bucket.  This is added as a new 'metric' for that bucket called 'service_heath'
    // return Promise.all(tasks).then(() => {
    //   const buckets = getState().api_data.buckets
    //   Object.keys(buckets).forEach((bucketId) => {
    //     const bucket = buckets[bucketId]
    //     const serviceIds = Object.keys(bucket.values)
    //     serviceIds.forEach((serviceId) => {
    //       const metricValues = bucket.values[serviceId]
    //       let total = 1
    //       if (metricValues['collect_coverage_results'].value === true) {
    //         total += 1
    //       }
    //       if (metricValues['has_test_results'].value === true) {
    //         total += 1
    //       }
    //       if (metricValues['tests_passing_percent'].value !== null) {
    //         total += metricValues['tests_passing_percent'].value
    //       }
    //       total = total / 4
    //       bucket.addValue(serviceId, 'service_health', total, '%')
    //     })
    //   })
    // })
  }
}

function hasBuckets (ranges, serviceId, metricId, bucketType, startTime, endTime) {
  if (ranges[startTime] === undefined || ranges[startTime][endTime] === undefined) {
    return false
  }
  if (ranges[startTime][endTime][bucketType] === undefined) {
    return false
  }
  const cached = ranges[startTime][endTime][bucketType].cached
  return (cached[serviceId] !== undefined && cached[serviceId][metricId] !== undefined)
}
