#!/usr/bin/env ruby
# encoding: UTF-8
#
# git-pull-request --
# 
#   Open a pull request for the current branch in your default browser
# 
#   Assumes the branches are named
#   <team>/<branch-title>-<story-id>
# 
require 'rubygems'
require 'pivotal-tracker'
require 'optparse'
require 'cgi'
require 'term/ansicolor'
require 'git-whistles/app'


class App < Git::Whistles::App

  Browsers = %w(xdg-open open firefox iceweasel)

  def initialize
    super
  end


  def main(args)
    super
    parse_args!(args)

    if args.count > 0
      die "Too many arguments", :usage => true
    end

    if options.from == options.to
      die "You cannot issue a pull request to the same branch (#{options.from})."
    end

    query = { }

    # guess team name
    if options.from =~ %r{^(\w+)/.*}
      team = $1.capitalize
    else
      team = nil
    end

    # guess title.
    title = options.from.split('/').last.split(/[_-]/).delete_if { |word| word =~ /^\d+$/ }.join(' ').capitalize
    query[:"pull_request[title]"] = team ? "#{team}: #{title}" : title

    # add Pivotal infos
    add_pivotal_info(query, $1.to_i) if options.from =~ /(\d+)$/

    query_string = query.map { |key,value|
      "#{CGI.escape key.to_s}=#{CGI.escape value}"
    }.join('&')
    url = "https://github.com/#{repo}/compare/#{options.to}...#{options.from}?#{query_string}"
    puts "Preparing a pull request for branch #{options.from}"
    
    unless launch_browser(url)
      log.warn "Sorry, I don't know how to launch a web browser on your system. You can open it yourself and paste this URL:\n#{url}"
    end
  end


  private


  def defaults
    {
      :from   => run!('git symbolic-ref HEAD').strip.gsub(%r(^refs/heads/), ""),
      :to     => 'master',
      :remote => 'origin'
    }
  end

  def option_parser
    @option_parser ||= OptionParser.new do |op|
      op.banner = "Usage: git pull-request [options]"

      op.on("-f", "--from YOUR_BRANCH", "Branch to issue pull request for [head]") do |v|
        options.from = v
      end

      op.on("-to", "--to UPSTREAM_BRANCH", "Branch into which you want your code merged [master]") do |v|
        options.to = v
      end

      op.on("-r", "--remote NAME", "The remote you're sending this to [origin]") do |v|
        options.to = v
      end
    end
  end


  def origin_url
    @origin_url ||= begin
      run!("git config --get remote.#{options.remote}.url").strip.tap do |url|
        url =~ /github\.com/ or die "origin does not have a Github URL !"
      end
    end
  end    


  def repo
    @repo ||= origin_url.sub(/.*github\.com[\/:]/,'').sub(/\.git$/,'')
  end


  def add_pivotal_info(query, story_id)
    token = `git config pivotal-tracker.token`.strip
    if token.empty?
      puts Term::ANSIColor.yellow %Q{
        Your branch appears to have a story ID,
        but I don't know your Pivotal Tracker token!
        Please set it with:
        $ git config [--global] pivotal-tracker.token <token>
      }
      die "Aborting."
    end

    log.info "Finding your project and story¬"

    PivotalTracker::Client.token = token
    story, project = PivotalTracker::Project.all.find do |project|
      log.info '.¬'
      story = project.stories.find(story_id) and break story, project
    end
    log.info '.'

    if story.nil?
      log.warn "Apologies... I could not find story #{story_id}."
      return
    end

    log.info "Found story #{story_id} in '#{project.name}'"

    headline = "Pivotal tracker story [##{story_id}](#{story.url}) in project *#{project.name}*:"
    description = story.description.split("\n").map { |line| "> #{line}" }.join("\n")
    body = "#{headline}\n\n#{description}"
    title = "#{project.name}: #{story.name} [##{story.id}]"
    query.merge! :subject => story.name, :"pull_request[body]" => body, :"pull_request[title]" => title
    return
  end

  def launch_browser(url)
    Browsers.each do |command|
      next if run("which #{command}").strip.empty?
      system command, url
      return true
    end
    return false
  end


end

############################################################################

App.run!