#!/usr/bin/env bash

# Print summary information about a Git repository

# A better class of script...
set -o errexit          # Exit on most errors (see the manual)
set -o errtrace         # Make sure any error trap is inherited
set -o nounset          # Disallow expansion of unset variables
set -o pipefail         # Use last non-zero exit code in a pipeline
#set -o xtrace          # Trace the execution of the script (debug)

# DESC: Usage help
# ARGS: None
# OUTS: None
function script_usage() {
    cat << EOF
Usage: [OPTIONS] [PATHS]
     -h|--help                  Displays this help
     -v|--verbose               Displays verbose output
    -nc|--no-colour             Disables colour output

     -b|--branches              Show Git branches
     -r|--remotes               Show Git remotes
     -s|--status                Show Git status
EOF
}

# DESC: Parameter parser
# ARGS: $@ (optional): Arguments provided to the script
# OUTS: Variables indicating command-line parameters and options
function parse_params() {
    local param
    declare -g -a git_repos

    while [[ $# -gt 0 ]]; do
        param="$1"
        shift
        case $param in
            -h | --help)
                script_usage
                exit 0
                ;;
            -v | --verbose)
                verbose=true
                ;;
            -nc | --no-colour)
                no_colour=true
                ;;
            -b | --branches)
                git_branches=true
                ;;
            -r | --remotes)
                git_remotes=true
                ;;
            -s | --status)
                git_status=true
                ;;
            *)
                git_repos+=("$param")
                ;;
        esac
    done

    if [[ -n ${git_repos[*]-} ]]; then
        for dir in "${git_repos[@]}"; do
            if [[ ! -d $dir ]]; then
                script_exit "Path is not a directory: $dir"
            fi
        done
    fi

    if ! [[ -n ${git_branches-} || -n ${git_remotes-} || -n ${git_status-} ]]; then
        git_branches=true
        git_remotes=true
        git_status=true
    fi
}

# DESC: Find some important paths we need before script_init() is called
# ARGS: None
# OUTS: $script_real_path: The full canonicalized path to the script
#       $script_real_dir: The canonicalized directory path of the script
#       $script_real_name: The canonicalized file name of the script
#       $dotfiles_path: The dotfiles directory path
#       $dotfiles_name: The dotfiles directory name
# shellcheck disable=SC2034
function early_init() {
    # Determine the physical directory this script resides in. This approach is
    # necessarily clumsy as simple methods like "readlink -f" and "realpath"
    # are not platform independent. We have to work on Linux, BSD, OS X, etc...
    script_real_path="$(perl -MCwd -le 'print Cwd::abs_path(shift)' "${BASH_SOURCE[0]}")"
    script_real_dir="$(dirname "$script_real_path")"
    script_real_name="$(basename "$script_real_path")"
    readonly script_real_path script_real_dir script_real_name

    # Dotfiles directory path & name
    dotfiles_path="$(cd -P "$script_real_dir/../../" && pwd)"
    dotfiles_name="$(basename "$dotfiles_path")"
    readonly dotfiles_path dotfiles_name
}

# DESC: Show selected summary information for a Git repository
# ARGS: $1 (required): Directory path to run in
# OUTS: None
function git_repo_summary() {
    local repo_dir="$1"

    (
        cd -- "$repo_dir"

        local repo_root
        if ! repo_root="$(git rev-parse --git-dir 2> /dev/null)"; then
            exit
        fi

        local repo_name
        if [[ $repo_root == '.git' ]]; then
            repo_name="$(basename "$PWD")"
        else
            repo_name="$(basename "$(dirname "$repo_root")")"
        fi

        pretty_print "*** $repo_name ***"

        if [[ -n ${git_status-} ]]; then
            pretty_print 'Status:'
            git status --short --branch
        fi

        if [[ -n ${git_remotes-} ]]; then
            pretty_print 'Remotes:'
            git remote -v
        fi

        if [[ -n ${git_branches-} ]]; then
            pretty_print 'Branches:'
            git --no-pager branch -vv
        fi

        echo
    )
}

# DESC: Main control flow
# ARGS: $@ (optional): Arguments provided to the script
# OUTS: None
function main() {
    early_init

    # shellcheck source=scripts/bin/bash-template.sh
    source "$dotfiles_path/scripts/bin/bash-template.sh"

    trap script_trap_err ERR
    trap script_trap_exit EXIT

    script_init "$@"
    parse_params "$@"
    colour_init

    check_binary git fatal

    shopt -s nullglob
    if [[ -n ${git_repos[*]-} ]]; then
        for git_repo in "${git_repos[@]}"; do
            git_repo_summary "$git_repo"
        done
    else
        if git rev-parse --git-dir > /dev/null 2>&1; then
            git_repo_summary .
        else
            for dir in */; do
                git_repo_summary "$dir"
            done
        fi
    fi
}

# Make it rain
main "$@"

# vim: syntax=sh cc=80 tw=79 ts=4 sw=4 sts=4 et sr
