#!/usr/bin/env node
'use strict';

/*
 * This script generates the template a changelog by comparing a current version
 * with master. Run this, copy what's logged into the `CHANGELOG.md` and update
 * the top section based on the changes listed in "Community Contributions"
 *
 * Usage:
 *
 * bin/changelog
 */

var EOL       = require('os').EOL;
var RSVP      = require('rsvp');
var Promise   = RSVP.Promise;
var GitHubApi = require('github');
var execSync  = require('child_process').execSync;

var github         = new GitHubApi({version: '3.0.0'});
var compareCommits = RSVP.denodeify(github.repos.compareCommits);
var currentVersion = process.env.PRIOR_VERSION;
var head = process.env.HEAD || 'master';

compareCommits({
  user: 'emberjs',
  repo: 'data',
  base: currentVersion,
  head: head
})
.then(processPages)
.then(console.log)
.catch(function(err) {
  console.error(err);
})

function getCommitMessage(commitInfo) {
  var message = commitInfo.commit.message;

  if (message.indexOf('cherry picked from commit') > -1) {
    var cherryPickRegex = /cherry picked from commit ([a-z0-9]+)/;
    var originalCommit = cherryPickRegex.exec(message)[1]

    try {
      // command from http://stackoverflow.com/questions/8475448/find-merge-commit-which-include-a-specific-commit
      message = execSync('commit=$((git rev-list ' + originalCommit + '..origin/master --ancestry-path | cat -n; git rev-list ' + originalCommit + '..origin/master --first-parent | cat -n) | sort -k2 | uniq -f1 -d | sort -n | tail -1 | cut -f2) && git show --format="%s\n\n%b" $commit', { encoding: 'utf8' });
    } catch(e) { }
  }

  return message;
}

function processPages(res) {
  var contributions = res.commits.filter(function(commitInfo) {
    var message = commitInfo.commit.message;

    return message.indexOf('Merge pull request #') > -1 || message.indexOf('cherry picked from') > -1;
  }).map(function(commitInfo) {
    var message = getCommitMessage(commitInfo);
    var match = message.match(/#(\d+) from (.*)\//);
    var result = {
      sha: commitInfo.sha
    };

    if (match) {
      var numAndAuthor = match.slice(1, 3);

      result.number =numAndAuthor[0];
      result.title = message.split('\n\n')[1];
    } else {
      result.title = message.split('\n\n')[0];
    }

    return result;
  }).sort(function(a, b) {
    return a.number > b.number;
  }).map(function(pr) {
    var title  = pr.title;
    var link;
    if (pr.number) {
      link = '[#' + pr.number + ']' + '(https://github.com/emberjs/data/pull/' + pr.number + ')';
    } else {
      link = '[' + pr.sha.slice(0, 8) + '](https://github.com/emberjs/data/commit/' + pr.sha + ')';
    }

    return '- ' + link + ' ' + title;
  }).join('\n');

  if (github.hasNextPage(res)) {
    return github.getNextPage(res)
      .then(function(nextPage) {
        contributions += processPages(nextPage);
      });
  } else {
    return RSVP.resolve(contributions);
  }
}
