#!/usr/bin/env bash

# Opens the GitHub page for a repo/branch in your browser.
# https://github.com/paulirish/git-open/
#
# git open
# git open [remote] [branch]


# are we in a git repo?
if ! git rev-parse --is-inside-work-tree &>/dev/null; then
  echo "Not a git repository." 1>&2
  exit 1
fi

# Defaults
is_issue=0
protocol="https"

# If the first argument is 'issue', we want to load the issue page
if [[ "$1" == 'issue' ]]; then
  is_issue=1

  # Allow the user to provide other args, aka `git open issue upstream 79`
  shift
fi

# choose remote. priority to: provided argument, detected tracked remote, 'origin'
branch_name=$(git name-rev --name-only HEAD 2>/dev/null)
tracked_remote=$(git config "branch.$branch_name.remote")
remote=${1:-$tracked_remote}
remote=${remote:-"origin"}

# @TODO ls-remote will also expand "insteadOf" items `giturl=$(git ls-remote --get-url $remote)``
giturl=$(git config --get "remote.${remote}.url")

if [[ -z "$giturl" ]]; then
  echo "Git remote is not set for $remote" 1>&2
  exit 1
fi

# From git-fetch(5), native protocols:
# ssh://[user@]host.xz[:port]/path/to/repo.git/
# git://host.xz[:port]/path/to/repo.git/
# http[s]://host.xz[:port]/path/to/repo.git/
# ftp[s]://host.xz[:port]/path/to/repo.git/
# [user@]host.xz:path/to/repo.git/ - scp-like but is an alternative to ssh.

# Trim "/" and ".git" from the end of the url
giturl=${giturl%/} giturl=${giturl%.git}

# Trim before last '@' and protocol (*://) from beginning
uri=${giturl##*@} uri=${uri##*://}

# If there isn't a protocol, we can assume it's using the scp syntax which uses ':' to seperate the path.
[[ $giturl =~ :// ]] && pathsep='/' || pathsep=':'

# Seperate the domain and the urlpath on the first {pathsep}. This also removes the gitport from the domain.
domain=${uri%%[:$pathsep]*} urlpath=${uri#*$pathsep}

# Allow config options to replace the server or the protocol
openurl="$protocol://$domain"

function getConfig() {
  config=$(git config --get-urlmatch "open.$1" "$openurl")
  echo "${config:-${!1}}"
}

domain=$(getConfig "domain")
protocol=$(getConfig "protocol")

# Get current branch
branch=${2:-$(git symbolic-ref -q --short HEAD)}

# Split arguments on '/'
IFS='/' pathargs=($urlpath)

if (( is_issue )); then
  # For issues, take the numbers and preprend 'issues/'
  providerBranchRef="issues/${branch//[^0-9]/}"
else
  # Make # and % characters url friendly
  #   github.com/paulirish/git-open/pull/24
  branch=${branch//%/%25} branch=${branch//#/%23}
  providerBranchRef="tree/$branch"
fi

if [[ "$domain" == 'bitbucket.org' ]]; then
  # Bitbucket, see https://github.com/paulirish/git-open/issues/80 for why ?at is needed.
  providerBranchRef="src?at=$branch"
elif [[ ${pathargs[0]} == 'scm' ]]; then
  # Bitbucket server, which starts with 'scm'
  # Replace the first element, 'scm', with 'projects'. Keep the first argument, the string 'repos', and finally the rest of the arguments.
  pathargs=('projects' ${pathargs[1]} 'repos' "${pathargs[@]:2}")
  IFS='/' urlpath="${pathargs[*]}"
  providerBranchRef="browse?at=$branch"
fi

openurl="$protocol://$domain/$urlpath"

# simplify URL for master
if [[ $branch != "master" ]]; then
    openurl="$openurl/$providerBranchRef"
fi

# get current open browser command
case $( uname -s ) in
  Darwin)  open='open';;
  MINGW*)  open='start';;
  MSYS*)   open='start';;
  CYGWIN*) open='cygstart';;
  *)       open='xdg-open';;
esac

# Allow printing the url if BROWSER=echo
if [[ $BROWSER != "echo" ]]; then
  exec &>/dev/null
fi

# open it in a browser
${BROWSER:-$open} "$openurl"
