#!/bin/bash

RELEASE_ASSETS_VERBOSE=yes

echo2() {
    echo "$@" >&2
}
verbose() {
    case "$RELEASE_ASSETS_VERBOSE" in
        1|yes) echo2 "$@" ;;
    esac
}
Usage() {
    echo2 "Usage: $(basename "$0") [--quietly] TAG asset-names"
    echo2 "where"
    echo2 "   TAG            release tag"
    echo2 "   asset-names    one or more asset names (without path) separated by space"
    echo2 "   --quietly      don't ask confirmation for deletions"
}
DIE() {
    local msg="$1"
    local file_to_delete="$2"      # optional file to delete
    test -n "$file_to_delete" && rm -f "$file_to_delete"
    echo2 "ERROR: $msg"
    Usage
    exit 1
}
WARN() {
    local msg="$1"
    echo2 "Warning: $msg"
}
Info() {
    local msg="$1"
    verbose "Info: $msg"
}

Prompt() { # prompt if a prompt value is given, no newline at end
    local prompt="$1"
    test -n "$prompt" && echo2 -n "$prompt: "
}
Promptln() { # prompt if a prompt value is given, newline at end
    local prompt="$1"
    test -n "$prompt" && echo2 "$prompt:"
}

GetValueFromPipe() { # return the value from pipe's output, second token
    awk '{print $2}' | sed -e 's|^"||' -e 's|",$||' -e 's|,$||'
}
GetValueFromPipeAndIndent() { # return the value from pipe's output, second token and indented by four spaces
    awk '{print $2}' | sed -e 's|^"|    |' -e 's|",$||' -e 's|,$||'
}

GetAssetNamesFromFile() {
    local file="$1"
    local prompt_optional="$2"
    Promptln "$prompt_optional"
    grep '^      "name":' "$file" | GetValueFromPipeAndIndent
}
GetReleaseIdFromFile() {
    local file="$1"
    local prompt_optional="$2"
    Prompt "$prompt_optional"
    grep '^  "id":'       "$1" | GetValueFromPipe
}
GetTagNamesFromFile() {
    local file="$1"
    local prompt_optional="$2"
    Promptln "$prompt_optional"
    grep '^  "tag_name":' "$1" | GetValueFromPipeAndIndent
}
GetAssetIdFromFile() {
    local file="$1"
    local assetname="$2"
    local prompt_optional="$3"       # optional
    Prompt "$prompt_optional"
    grep -B2 "\"$assetname\"," "$file" | grep '"id":' | GetValueFromPipe
}


declare -A GITHUB_INFO

PrepareGithubInfo() {   # put some useful values to GITHUB_INFO
    local reponame="$1"
    local tag="$2"

    if [ -n "$reponame" ] ; then
        GITHUB_INFO["reponame"]="$reponame"
    else
        test -r .git/config || { echo2 "Need repo name but cannot find .git/config under the working folder $PWD." ; return 1 ; }
        GITHUB_INFO["reponame"]="$(basename $(grep "https://github.com" .git/config 2>/dev/null | awk '{print $3}') .git)"
        test -n "${GITHUB_INFO["reponame"]}" || { echo2 "Repo name is not available." ; return 1 ; }
    fi
    if [ -n "$tag" ] ; then
        GITHUB_INFO["tag"]="$tag"
    else
        GITHUB_INFO["tag"]="LATEST"
    fi

    test -r ~/.config/hub || { echo2 "cannot find ~/.config/hub, is 'hub' installed and initialized?" ; return 1 ; }

    #GITHUB_INFO["owner"]="$(grep "user:" ~/.config/hub | awk '{print $NF}')"
    GITHUB_INFO["owner"]="$(grep "https://github.com" .git/config | awk '{print $NF}' | sed -e 's|^https://github.com/||' -e 's|/.*$||')"
    test -n "${GITHUB_INFO["owner"]}" || { echo2 "Owner info is not available." ; return 1 ; }

    GITHUB_INFO["oauth_token"]="$(grep "oauth_token:" ~/.config/hub | awk '{print $NF}')"
    test -n "${GITHUB_INFO["oauth_token"]}" || { echo2 "Github API token is not available." ; return 1 ; }
}

GetReleaseInfoToFile()
{
    local asset_info_file="$1"
    local tag="$2"
    local reponame="$3"
    local owner
    local oauth_token

    PrepareGithubInfo "$reponame" "$tag" || DIE "PrepareGithubInfo() failed." "$asset_info_file"

    tag="${GITHUB_INFO["tag"]}"
    reponame="${GITHUB_INFO["reponame"]}"
    owner="${GITHUB_INFO["owner"]}"
    oauth_token="${GITHUB_INFO["oauth_token"]}"

    local GH_REPO="https://api.github.com/repos/$owner/$reponame"
    local GH_TAG="$GH_REPO/releases/tags/$tag"
    local AUTH="Authorization: token $oauth_token"

    test "$tag" = "LATEST" && GH_TAG="$GH_REPO/releases/latest"

    if [ "$(stat -c %s "$asset_info_file")" = "0" ] ; then
        #Info "Fetching github info..."

        # Validate token.
        curl -o /dev/null -sH "$AUTH" $GH_REPO || DIE "Invalid repo, token or network issue!" "$asset_info_file"

        # Read asset info into the file.
        curl -sH "$AUTH" $GH_TAG > $asset_info_file || DIE "failed to fetch assets info from '$GH_TAG'."
    fi
}

DeleteAsset()
{
    local asset_info_file="$1"
    local asset_name="$2"
    local quietly="$3"       # if yes, then no questions are asked about deletion

    local asset_id="$(GetAssetIdFromFile "$asset_info_file" "$asset_name")"
    #local repo="${GITHUB_INFO["reponame"]}"
    #local owner="${GITHUB_INFO["owner"]}"
    #local oauth_token="${GITHUB_INFO["oauth_token"]}"
    local answer

    if [ "$asset_id" = "" ]; then
        WARN "asset id not found for '$asset_name'."
        return 1
    fi

    case "$quietly" in
        no)
            # Final chance to prevent deleting ...
            read -p "Delete asset '$asset_name' (Y/n)? " answer
            case "$answer" in
                y|Y|"") ;;
                *) return ;;
            esac
            ;;
        yes)
            echo "deleting asset $asset_name ..."
            ;;
    esac

    hub api -t -X "DELETE" "https://api.github.com/repos/{owner}/{repo}/releases/assets/$asset_id"

#    local GITHUB_OAUTH_BASIC=""  # ??
#    curl $GITHUB_OAUTH_BASIC -X "DELETE" -H "Authorization: token $oauth_token" \
#         "https://api.github.com/repos/$owner/$repo/releases/assets/$asset_id"
}

Main()  # parameters: [--quietly] TAG assetname...
{
    local xx
    local quietly=no
    local shifts=0

    for xx in "$@" ; do
        case "$xx" in
            --quietly) quietly=yes ; ((shifts++)) ;;
        esac
    done
    shift $shifts
    local tag="$1"
    shift              # other parameters are asset names, i.e. file names without any path
    local github_asset
    local asset
    local asset_info_file
    local matched_assets=()

    # Note: asset names can also be shortened, e.g. "yay-" or "downgrad".
    # Then all assets starting with that name are deleted, so be careful.

    test -n "$tag" || DIE "TAG is missing."
    test -n "$1" || DIE "Assets are missing."

    asset_info_file=$(mktemp)

    GetReleaseInfoToFile "$asset_info_file" "$tag"   # repo

    # Check that the given tag exists.
    for xx in $(GetTagNamesFromFile "$asset_info_file") ; do
        test "$tag" = "$xx" && break
    done
    test "$tag" = "$xx" || DIE "TAG '$tag' does not exist (find with 'hub release')." "$asset_info_file"

    # Match given assets to github assets.
    local github_assets="$(GetAssetNamesFromFile "$asset_info_file")"
    local delete_all=no

    case "$delete_all" in
        yes)
            for github_asset in $github_assets ; do
                matched_assets+=("$github_asset")
            done
            ;;
        no)
            for asset in "$@" ; do
                for github_asset in $github_assets ; do
                    case "$github_asset" in
                        ${asset}*)
                            for xx in "${matched_assets[@]}" ; do
                                test "$xx" = "$github_asset" && break
                            done
                            if [ "$xx" != "$github_asset" ] ; then
                                matched_assets+=("$github_asset")
                            fi
                            ;;
                    esac
                done
                test -n "$matched_assets" || DIE "Asset '$asset' does not match to any asset at github." "$asset_info_file"
            done
            ;;
    esac

    # Now delete given assets from github.
    for asset in "${matched_assets[@]}" ; do
        DeleteAsset "$asset_info_file" "$asset" "$quietly" || DIE "Failed to delete asset '$asset'." "$asset_info_file"
        #sleep 0.5
    done

    rm -f "$asset_info_file"  # file no more needed
}

Main "$@"  # tag asset(s)
