const btoa = require('btoa')
const groupBy = require('lodash.groupby')
const highwire = require('highwire')
const values = require('lodash.values')

const FailedStatusFoundError = require('./failed-status-found-error')
const PendingTimeoutError = require('./pending-timeout-error')

const GITHUB_TOKEN = process.env.GITHUB_TOKEN
const GITHUB_USER = process.env.GITHUB_USER
const GREENKEEPER_BOT_GITHUB_URL = 'https://github.com/greenkeeperio-bot'
const SQUASH_MERGES = process.env.SQUASH_MERGES || false
const DELETE_BRANCHES = process.env.DELETE_BRANCHES || true

const MINUTE = 1000 * 60
const HOUR = MINUTE * 60

const { get, put, post, del } = highwire

const headers = {
  'Authorization': `Basic ${btoa(GITHUB_USER + ':' + GITHUB_TOKEN)}`
}

const mergePR = (prUrl, prNumber, sha) => {
  const mergeData = {
    sha,
    commit_title: `greenkeeper-keeper(pr: ${prNumber}): :white_check_mark:`,
    commit_message: `greenkeeper-keeper(pr: ${prNumber}): :white_check_mark:`,
    squash: SQUASH_MERGES
  }

  put(`${prUrl}/merge`, mergeData, { headers })
}

const validatePR = (statusesUrl, timeout = MINUTE) =>
  get(statusesUrl, { headers })
    .then((response) => response.body)
    .then((statuses) => {
      const contexts = values(groupBy(statuses, 'context'))
      const latest = contexts.map((c) => c.sort((a, b) => a.created_at > b.created_at)[0])
      const failed = latest.filter((s) => s.state === 'failure')
      const pending = latest.filter((s) => s.state === 'pending')

      if (failed.length) {
        return Promise.reject(new FailedStatusFoundError())
      }

      if (pending.length) {
        if (timeout > HOUR) {
          return Promise.reject(new PendingTimeoutError())
        }

        return new Promise((resolve) => setTimeout(() => resolve(), timeout))
          .then(() => validatePR(statusesUrl, timeout * 2))
      }

      return Promise.resolve()
    })

const deleteBranch = (head) => {
  const { repo } = head
  const path = `/repos/${repo.full_name}/git/refs/heads/${head.ref}`
  const url = `https://api.github.com${path}`

  return del(url, { headers })
}

const openedByGreenKeeperBot = (sender) => {
  return sender.html_url === GREENKEEPER_BOT_GITHUB_URL
}

const buildErrorComment = (message, prNumber) => {
  return {
    body: `greenkeeper-keeper(pr: ${prNumber}): :x: \`${message}\``
  }
}

const commentWithError = (commentsUrl, prNumber, error) => {
  post(`${commentsUrl}`, buildErrorComment(error.message, prNumber), { headers })
}

module.exports.register = (server, options, next) => {
  server.route({
    method: 'POST',
    path: '/payload',
    handler (request, response) {
      response('ok')

      const { action, sender, pull_request, number } = request.payload

      if (action === 'opened' && openedByGreenKeeperBot(sender)) {
        request.log(['info', 'PR', 'validating'], pull_request.url)
        validatePR(pull_request.statuses_url)
          .then(() => request.log(['info', 'PR', 'validated']))
          .then(() => mergePR(
            pull_request.url,
            number,
            pull_request.head.sha
          ))
          .then(() => request.log(['info', 'PR', 'merged'], pull_request.url))
          .then(() => {
            if (DELETE_BRANCHES) {
              return deleteBranch(pull_request.head)
            }

            return Promise.resolve()
          })
          .catch((error) => {
            request.log(['error', 'PR'], error)
            commentWithError(pull_request.comments_url, number, error)
          })
      } else {
        request.log(['PR', 'skipping'])
      }
    }
  })

  next()
}

module.exports.register.attributes = {
  name: 'keeper',
  version: '0.0.1'
}

@@ -1498,28 +1498,229 @@
     
-if (failed.length) %7B
+console.log('validating PR', %7B%0A        timeout,%0A        statusesUrl,%0A        contexts,%0A        latest,%0A        failed,%0A        pending%0A      %7D)%0A%0A      if (failed.length) %7B%0A        console.log('found failed, rejecting...')
 %0A   
@@ -1839,24 +1839,88 @@
 t %3E HOUR) %7B%0A
+          console.log('pending timeout exceeded, rejecting...')%0A
           re
@@ -1969,32 +1969,91 @@
 r())%0A        %7D%0A%0A
+        console.log('retrying statuses for:', statusesUrl)%0A
         return n
@@ -2179,24 +2179,78 @@
 ))%0A      %7D%0A%0A
+      console.log('statuses verified, continuing...')%0A
       return

add better logging for validating PRs