require('isomorphic-fetch')
const { createStack, createFetch, header, base, query, parseJSON, onResponse } = require('http-client')
const invariant = require('invariant')

const CloudflareKey = process.env.CLOUDFLARE_KEY
const CloudflareEmail = process.env.CLOUDFLARE_EMAIL

invariant(
  CloudflareKey,
  'Missing $CLOUDFLARE_KEY environment variable'
)

invariant(
  CloudflareEmail,
  'Missing $CLOUDFLARE_EMAIL environment variable'
)

const createRangeQuery = (since, until) =>
  query({
    since: since.toISOString(),
    until: until.toISOString()
  })

const createNameQuery = (name) =>
  query({ name })

const getResult = () =>
  createStack(
    parseJSON(),
    onResponse(response => response.jsonData.result)
  )

const commonStack = createStack(
  header('X-Auth-Key', CloudflareKey),
  header('X-Auth-Email', CloudflareEmail),
  base('https://api.cloudflare.com/client/v4'),
  getResult()
)

const getZones = (domainName) =>
  createFetch(
    commonStack,
    createNameQuery(domainName)
  )('/zones')

const getZoneAnalyticsDashboard = (zone, since, until) =>
  createFetch(
    commonStack,
    createRangeQuery(since, until)
  )(`/zones/${zone.id}/analytics/dashboard`)

const getAnalyticsDashboards = (domainNames, since, until) =>
  Promise.all(
    domainNames.map(domainName => getZones(domainName))
  ).then(
    domainZones => domainZones.reduce((memo, zones) => memo.concat(zones))
  ).then(
    zones => Promise.all(zones.map(zone => getZoneAnalyticsDashboard(zone, since, until)))
  ).then(
    results => results.reduce(reduceResults)
  )

const reduceResults = (target, results) => {
  Object.keys(results).forEach(key => {
    const value = results[key]

    if (typeof value === 'object' && value) {
      target[key] = reduceResults(target[key] || {}, value)
    } else if (typeof value === 'number') {
      target[key] = (target[key] || 0) + results[key]
    }
  })

  return target
}

const OneMinute = 1000 * 60
const ThirtyDays = OneMinute * 60 * 24 * 30

const fetchStats = (callback) => {
  const since = new Date(Date.now() - ThirtyDays)
  const until = new Date(Date.now() - OneMinute)

  getAnalyticsDashboards([ 'npmcdn.com', 'unpkg.com' ], since, until)
    .then(result => callback(null, result), callback)
}

module.exports = {
  getZones,
  getZoneAnalyticsDashboard,
  getAnalyticsDashboards,
  fetchStats
}