# shellcheck shell=dash disable=SC2154
# shellcheck disable=

___x_cmd_gh_repo_file(){
    param:scope  ___x_cmd_github
    param:subcmd ___x_cmd_gh_repo_file              \
        ls              "List repo files"           \
        tree            "List repo file tree"       \
        upload          "Upload file to repo"       \
        download        "Download file from repo"
    param:subcmd:try
    param:run

    ___x_cmd_gh_repo_file _param_help_doc
    return 1
}

# (limit 1000): https://docs.github.com/en/rest/repos/contents#get-repository-content
___x_cmd_gh_repo_file_ls(){
    param:scope     ___x_cmd_github
    param:dsl       '
options:
    #1              "repo path parameter"                                                   <>=""
    --repo|-r       "<owner_path>/<repo_path>"                                              <>:RepoName
    --ref           "The name of the commit/branch/tag. Default using default branch"       <>=""

    --json|-j       "output origin json data"
    --csv           "output csv data"
    --yml           "output yml data"
'
    param:run
    ___x_cmd_gh_param_init_owner_repo
    [ -n "$owner_repo" ] || M='Please provide --repo <owner/repo>"' arg:ret:64

    if ___x_cmd_gx_output_is_format; then
        ___x_cmd_gh_curl get "/repos/${owner_repo}/contents/${1}" ref | ___x_cmd_gx_output_format
    else
        ___x_cmd_gh_curl get "/repos/${owner_repo}/contents/${1}" ref | \
            x jo 2c .name | \
            if [ -n "$csv" ]; then  ___x_cmd_cmds cat
            else                    x csv static_tab
            fi
    fi
}

# https://docs.github.com/en/rest/git/trees#get-a-tree
___x_cmd_gh_repo_file_tree(){
    param:scope     ___x_cmd_github
    param:dsl       '
options:
    #1              "the target tree sha"                                                   <>=""
    --repo|-r       "<owner_path>/<repo_path>"                                              <>:RepoName
    --recursive     "Returns the objects or subtrees referenced by the tree"
    --json|-j       "output json data"
'
    param:run
    ___x_cmd_gh_param_init_owner_repo
    [ -n "$owner_repo" ] || M='Please provide --repo <owner/repo>"' arg:ret:64

    local x_="$1"
    if [ -z "$x_" ]; then
        ___x_cmd_gh_repo_file_ls___get_repo_root_tree_sha_ || return
    fi
    gh:debug "tree sha ==> $x_"
    [ -n "$x_" ] || { gh:error "Can not found repo${1:+" $1"} tree sha"; return 1; }

    if [ -n "$json" ] || [ -n "$ENFORCE_JSON" ]; then
        ___x_cmd_gh_curl get "/repos/${owner_repo}/git/trees/${x_}" recursive
    else
        ___x_cmd_gh_curl get "/repos/${owner_repo}/git/trees/${x_}" recursive | x jo .tree | \
            x jo 2c             .path | \
            x csv static_tab
    fi
}

___x_cmd_gh_repo_file_ls___get_repo_root_tree_sha_(){
    local NO_CACHE=1
    ___x_cmd_gh___get_x_repo_tree_sha_by_branch_tag_ "$ref"
}

___x_cmd_gh_repo_file_ls___get_repo_dir_tree_sha(){
    x ja -v dir_name="$1" \
        'END{
            l = O[ kp(1) L ]
            for (i=1; i<=l; ++i){
                name = juq(O[ kp(1, i, "name") ])
                type = juq(O[ kp(1, i, "type") ])
                if (name == dir_name && type == "dir"){
                    print juq(O[ kp(1, i, "sha") ])
                    exit(0)
                }
            }
        }'
}

# https://docs.github.com/en/rest/repos/contents#create-or-update-file-contents
# shellcheck disable=2154
___x_cmd_gh_repo_file_upload(){
    param:scope     ___x_cmd_github
    param:dsl       '
options:
    #1              "Upload to repo path"                              <>=""
    --repo|-r       "<owner_path>/<repo_path>"                         <>:RepoName
    --file          "base upload file path"                            <>
    --message       "The commit message"                               <>
    --branch        "The branch name. Default is repo default branch"  <>=""
    --json|-j       "output json data"
'
    param:run
    ___x_cmd_gh_param_init_owner_repo
    [ -n "$owner_repo" ] || M='Please provide --repo <owner/repo>"' arg:ret:64

    if [ -f "$file" ]; then
        file="$(x base64 < "$file")"
    else
        M="Not found $file file. Please check the file exist" arg:ret:64
    fi;
    # Required if you are updating a file.
    local sha=""; local ref="$branch";
    x jo env . sha=.sha <<A
        $(___x_cmd_gh_curl get "/repos/${owner_repo}/contents/${1}" ref 2>/dev/null)
A

    local gen_gh_json=""
    gen_gh_json="$(param:option2json -repo -json -file content=file ${sha+"+sha"})"
    gh:debug "$gen_gh_json"

    ___x_cmd_gh_curl put "/repos/${owner_repo}/contents/${1}" gen_gh_json | ___x_cmd_gh_repo_file____ui_handler Upload
}

___x_cmd_gh_repo_file_download(){
param:scope     ___x_cmd_github
    param:dsl       '
options:
    #1              "Download from repo path"                                       <>=""
    #2              "Output file path"                                              <>=""
    --repo|-r       "<owner_path>/<repo_path>"                                      <>:RepoName
    --ref           "The commit/branch/tag name. Default using default branch"      <>=""
    --endpoint      "Download endpoint"                                             <>="https://raw.githubusercontent.com"
    --yes|-y        "Ignore overwrite prompt interception"
'
    param:run
    ___x_cmd_gh_param_init_owner_repo
    [ -n "$owner_repo" ] || M='Please provide --repo <owner/repo>"' arg:ret:64
    local gh_output="$2"
    [ -n "$2" ] || gh_output="./${1##*/}"
    gh:debug "gh_output ==> $gh_output"
    [ ! -f "$gh_output" ] || [ "$yes" = "true" ]  || ___x_cmd_ui_yesno "Are you sure to overwrite local file $(___x_cmd_ui bold red "$gh_output") ?" || return

    if [ -z "$ref" ]; then
        local x_default_branch=""
        if ! ___x_cmd_gh___get_x_default_branch_; then
            gh:error "Can not get default branch of repo $owner_repo. Please have check it."
            return 1
        fi
        ref="$x_default_branch"
    fi

    local ___X_CMD_API_GH_ENDPOINT="$endpoint"
    if ! ___x_cmd_gh_curl download "/${owner_repo}/${ref}/${1}" "$gh_output"; then
        [ "$(___x_cmd_gh_resp_code)" != 404 ] || gh:warn "Possible the repository file no exist. Please have check it."
        x rmrf "$gh_output"
        return 1
    fi
}

___x_cmd_gh_repo_file____ui_handler(){
    if [ -n "$ENFORCE_JSON" ] || [ -n "$json" ]; then
        ___x_cmd_cmds_cat
        ___x_cmd_gh_http_error
        return
    fi
    (
        local _sha=""
        case "$1" in
            Upload)
                x jo env . _sha=.content.sha gh_resp_msg=.message gh_resp_err=.errors \
                    _path=.content.path
                _inf_msg="[OK]: $1 file to $owner_repo repo $_path successfully"
                _err_msg="[FAIL] $1 file to $owner_repo repo:"
                ;;
        esac
        if [ -n "$_sha" ]; then
            ___x_cmd_ui_tf  true "$_inf_msg"
        else
            ___x_cmd_ui_tf false "$_err_msg" >&2
            ___x_cmd_gh____handle_resp
            return 1
        fi
    )
}
