var exec = require('child_process').exec;
var logger = require('./logger')();

function fetchGitData(git, cb) {
  if (!cb){
    throw new Error("fetchGitData requires a callback");
  }

  //-- Malformed/undefined git object
  if ('undefined' === typeof git) {
    return cb(new Error('No options passed'));
  }
  if (!git.hasOwnProperty('head')) {
    return cb(new Error('You must provide the head'));
  }
  if (!git.head.hasOwnProperty('id')) {
    return cb(new Error('You must provide the head.id'));
  }

  //-- Set required properties of git if they weren"t provided
  if (!git.hasOwnProperty("branch")) {
    git.branch = "";
  }
  if (!git.hasOwnProperty("remotes")) {
    git.remotes = [];
  }

  //-- Assert the property types
  if ("string" !== typeof git.branch) {
    git.branch = "";
  }
  if (!(git.remotes instanceof Array)) {
    git.remotes = [];
  }

  //-- Use git?
  exec("git rev-parse --verify " + git.head.id, function(err, response){
    if (err){
      // git is not available...
      git.head.author_name = git.head.author_name || "Unknown Author";
      git.head.author_email = git.head.author_email || "";
      git.head.committer_name = git.head.committer_name || "Unknown Committer";
      git.head.committer_email = git.head.committer_email || "";
      git.head.message = git.head.message || "Unknown Commit Message";
      return cb(null, git);
    }

    fetchHeadDetails(git, cb);
  });
}

function fetchBranch(git, cb) {
  exec("git branch", function(err, branches){
    if (err)
      return cb(err);

    git.branch = (branches.match(/^\* (\w+)/) || [])[1];
    fetchRemotes(git, cb);
  });
}

var REGEX_COMMIT_DETAILS = /\nauthor (.+?) <(.+?)>.+\ncommitter (.+?) <(.+?)>.+\n?[\S\s]+?\n\n(.*)/m;;

function fetchHeadDetails(git, cb) {
  exec('git cat-file -p ' + git.head.id, function(err, response) {
    if (err)
      return cb(err);

    var items = response.match(REGEX_COMMIT_DETAILS).slice(1);
    var fields = ['author_name', 'author_email', 'committer_name', 'committer_email', 'message'];
    fields.forEach(function(field, index) {
      git.head[field] = items[index];
    });

    if (git.branch) {
      fetchRemotes(git, cb);
    } else {
      fetchBranch(git, cb);
    }
  });
}

function fetchRemotes(git, cb) {
  exec("git remote -v", function(err, remotes){
    if (err)
      return cb(err);

    var processed = {};
    remotes.split("\n").forEach(function(remote) {
      if (!/\s\(push\)$/.test(remote))
        return;
      remote = remote.split(/\s+/);
      saveRemote(processed, git, remote[0], remote[1]);
    });
    cb(null, git);
  });
}

function saveRemote(processed, git, name, url) {
  var key = name + "-" + url;
  if (processed.hasOwnProperty(key))
    return;

  processed[key] = true;
  git.remotes.push({ name: name, url: url });
}

module.exports = fetchGitData;
