#!/usr/bin/env ruby

require "ircinch"
require "sinatra"
require "yaml"
require "json"
require "net/http"

config_file = ARGV.shift || "config.yml"
if not File.exists? config_file
  puts "Can't find config file #{config_file}"
  puts "Either create it or specify another config file with: #{File.basename $0} [filename]"
  exit
end

$config = YAML.load_file config_file
$secret = $config["env"]["secret"]

$bot = Cinch::Bot.new do
  configure do |c|
    c.nick = $config["irc"]["nick"]
    c.user = "Scummette"
    c.realname = "Razor"
    c.server = $config["irc"]["server"]
    c.port = $config["irc"]["port"]
    c.password = $config["irc"]["password"]
    c.channels = $config["irc"]["channels"]
    c.ping_interval = 120
    c.timeouts.read = 480
  end
end

Thread.new do
  $bot.start
end

def verify_signature(payload_body, github_signature)
  signature = 'sha1=' + OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha1'), $secret, payload_body)
  github_signature = "" if github_signature.nil?
  return halt 500, "Signatures didn't match!" unless Rack::Utils.secure_compare(signature, github_signature)
end

def say(repo,msg)
  $config["irc"]["channels"].each do |chan|
    unless $config["filters"].include? chan and not $config["filters"][chan].include? repo
      $bot.Channel(chan).send msg
    end
  end
end

def join()
  $config["irc"]["channels"].each do |chan|
    unless $config["filters"].include? chan and not $config["filters"][chan].include? repo
      $bot.join(chan)
    end
  end
end

def part()
  $config["irc"]["channels"].each do |chan|
    unless $config["filters"].include? chan and not $config["filters"][chan].include? repo
      $bot.part(chan)
    end
  end
end

configure do
  set :bind, $config["http"]["host"]
  set :port, $config["http"]["port"]
  set :host_authorization, { permitted_hosts: [] }
  set :logging, false
  set :lock, true
end

get "/" do
  "GitBot lives here. Direct your hooks to /github."
end

post "/github" do
  request.body.rewind
  payload_body = request.body.read
  verify_signature(payload_body, request.env['HTTP_X_HUB_SIGNATURE'])

  $bot.nick = $config["irc"]["nick"]

  eventType = request.env['HTTP_X_GITHUB_EVENT']
  push = JSON.parse(params[:payload])

  repo = push["repository"]["name"]
  sender = push["sender"]["login"]

  case eventType
  when "pull_request"
    return halt 200 unless ["opened", "closed", "reopened"].include?(push["action"])
    res = Net::HTTP.post_form(URI('https://is.gd/create.php'), { 'format' => 'simple', 'url' => push["pull_request"]["html_url"] })
    case res
    when Net::HTTPSuccess, Net::HTTPRedirection
        url = res.body
        say repo, "[%s] %s %s pull request #%s: %s (%s) %s" % [
          $bot.Format(:purple, repo),
          sender,
          $bot.Format(:bold, push["action"]),
          $bot.Format(:bold, push["number"].to_s),
          push["pull_request"]["title"],
          $bot.Format(:purple, "%s...%s" % [
            push["pull_request"]["base"]["ref"],
            push["pull_request"]["head"]["ref"]
          ]),
          $bot.Format(:aqua, $bot.Format(:underline, url))
        ]
    else
        # Post Failed i.e. 502
        # FIXME: do say with error message? i.e. res.value
    end
  when "push"
    res = Net::HTTP.post_form(URI('https://is.gd/create.php'), { 'format' => 'simple', 'url' => push["compare"] })
    case res
    when Net::HTTPSuccess, Net::HTTPRedirection
        url = res.body
        branch = push["ref"].gsub(/^refs\/heads\//,"")
        numberOfCommits = push["commits"].length
        forced = push["forced"]
        say repo, "[%s] %s %s %s new commits to %s: %s" % [
          $bot.Format(:purple, repo),
          sender,
          forced ? "force pushed" : "pushed",
          $bot.Format(:bold, numberOfCommits.to_s),
          $bot.Format(:purple, branch),
          $bot.Format(:aqua, $bot.Format(:underline, url))
        ]
        push["commits"][0..2].each do |c|
          say repo, "%s/%s %s %s: %s" % [
            $bot.Format(:purple, repo),
            $bot.Format(:purple, branch),
            $bot.Format(:grey, c["id"].slice(0..6)),
            c["author"]["username"],
            c["message"].split("\n")[0]
          ]
        end
    else
        # Post Failed i.e. 502
        # FIXME: do say with error message? i.e. res.value
    end
  end



  push.inspect
end
