# shellcheck    shell=dash disable=SC2034,SC1090

# TODO: Multiple thread
# TODO: Download Manager and more strategy
# TODO: Maybe using a P2P share connection for mirror downloading.
___x_cmd_pkg_download(){
    x:trace pkg/download
    local X_help_cmd='___x_cmd help -m pkg download';   help:arg-null:parse

    case "$1" in
        */*)
            ___x_cmd_pkg___appoint "$@"
            return
            ;;
    esac
    ___x_cmd_pkg_download___inner "$@"
}


___x_cmd_pkg_download___inner(){
    local name="$1";    [ -n "$name" ] || N=pkg M="Provide a package name" log:ret:1
    local osarch="$3";  [ -n "$osarch" ] || { ___x_cmd_pkg_osarch_ || return 1; osarch="$___X_CMD_PKG_OSARCH"; } || N=pkg M="Not found osarch" log:ret:1
    local version="$2"; [ -n "$version" ] || {
        local x_=; ___x_cmd_pkg_default_version_ "$name" "$osarch";
        version="$x_";
    }
    [ -n "$version" ] || {
        pkg:warn "Not found candidate => $name"
        pkg:warn "Please use 'x pkg update' and 'x pkg ll' to check available candidate"
        return 1
    }

    ___x_cmd fslock run "pkg_${name}_${version}_${osarch}" ___x_cmd_pkg_download___inner_ "$name" "$version" "$osarch"
}

# ___X_CMD_PKG_DOWNLOAD_SOURCE=
# http://
# github
# npmmirror
# npm

___x_cmd_pkg_download___inner_(){
    local name="$1";    local version="$2";     local osarch="$3"
    local download_file_ext=; local md5= ; local sha1= ; local sha256=; local sha512=;
    local unpack=; local npm=; local npmurl_cn=; local npmurl_internet=; local url_cn=; local url_internet=; local tree=;
    ___x_cmd_pkg___attr "$name" "$version" "$osarch" "md5,sha1,sha256,sha512,download_file_ext,unpack,npm,url.${___X_CMD_WEBSRC_REGION:-internet},npmurl.${___X_CMD_WEBSRC_REGION:-internet},tree" || return $?
    [ -n "$unpack" ] || {
        pkg:debug "Skip download"
        return 0
    }

    local os="${osarch%/*}";  local arch="${osarch#*/}"; local ball
    if [ "$unpack" = "none" ] && [ -z "$download_file_ext" ]; then
        ball="$___X_CMD_PKG_DOWNLOAD_PATH/$name/$name.${tree}"
    else
        ball="$___X_CMD_PKG_DOWNLOAD_PATH/$name/${version}.${tree}.$download_file_ext"
    fi


    ___x_cmd mkdirp "$___X_CMD_PKG_DOWNLOAD_PATH/$name" || {
        pkg:error "Create $___X_CMD_PKG_DOWNLOAD_PATH/$name failed" ; return 1
    }

    pkg:info "Trying download ==> '$name $version'"
    if [ -f "$ball" ]; then
        if ___x_cmd_pkg_download___check_hashsum "$ball" "$md5" "$sha1" "$sha256" "$sha512"; then
            pkg:info "File already downloaded => $ball"
            return 0
        fi

        pkg:warn "Download the $ball again"
    fi

    local url_strategy="${___X_CMD_PKG_DOWNLOAD_SOURCE}"
    if [ -z "$url_strategy" ]; then
        if [ -n "$___X_CMD_GHACTION_INSIDE" ] || ___x_cmd websrc is internet; then
            url_strategy=github
        else
            url_strategy=npm
        fi
    fi

    local url=
    if [ "$url_strategy" = npm ] && [ "$npm" = yes ]; then
        ball="$___X_CMD_PKG_DOWNLOAD_PATH/$name/${version}.${tree}.tgz"
        eval url="\$npmurl_${___X_CMD_WEBSRC_REGION:-internet}"
    else
        eval url="\$url_${___X_CMD_WEBSRC_REGION:-internet}"
    fi

    if [ -z "$url" ]; then
        pkg:error "Not found url for $name $version"
        pkg:error "Please use 'x pkg ll' or 'x pkg ls -a <candidate>' to check available candidate and version"
        return 1
    fi

    pkg:info \
        -m "download $name=$version, thanks to the courtesy of ${url%/"${url#*//*/}"}" \
        --url "$url" --ball "$ball" --name "$name" --version "$version"

    ___x_cmd ensurefp "$ball" || return 1
    ___x_cmd curl -I "$url" | {
        trap 'printf "\r\n"; pkg:error "Download interrupted"; ___x_cmd_pkg_sphere_gc --remove ball $name $version $osarch; return 130;' INT
        ___x_cmd_readr head;
        head="${head#* }"; head="${head%% *}"
        case "$head" in
            2??|3??)
                if ! ___x_cmd curl --progress-bar --location --retry-max-time 10 --retry 0 "$url" > "$ball"; then
                    pkg:error "Fail to download from $url"
                    ___x_cmd rmrf "$ball"
                    return 1
                fi
                ;;
            *)
                printf "\r"
                pkg:error "resource invalid => $url"
                return 1
                ;;
        esac
    } || return $?

    if [ "$url_strategy" = npm ] && [ "$npm" = yes ]; then
        local npm_package="$___X_CMD_PKG_DOWNLOAD_PATH/$name/package"
        ___X_CMD_ZUZ_QUIET=1 ___x_cmd uz "$ball"  "$___X_CMD_PKG_DOWNLOAD_PATH/$name" || M='Unzip npm package failed' N=pkg log:ret:1
        local x_=; ___x_cmd fsiter --file01_ "$npm_package/dist" || return $?
        ___x_cmd mv "$npm_package/dist/$x_" "$___X_CMD_PKG_DOWNLOAD_PATH/$name/${version}.${tree}.$download_file_ext" ||  M='Move npm package failed' N=pkg log:ret:1
        ___x_cmd rmrf "$ball" "$npm_package" || M='Remove npm package failed' N=pkg log:ret:1
        ball="$___X_CMD_PKG_DOWNLOAD_PATH/$name/${version}.${tree}.$download_file_ext"
    fi

    ___x_cmd_pkg_download___check_hashsum "$ball" "$md5" "$sha1" "$sha256" "$sha512"
}

___x_cmd_pkg_download___check_hashsum(){
    local filepath="${1}"
    [ -n "$filepath" ] || M='Please priovide filepath' N=pkg log:ret:1
    local sha
    [ -z "$2" ]  ||   sha="$(___x_cmd md5       "$filepath")"
    [ -z "$3" ]  ||   sha="$(___x_cmd sha1      "$filepath")"
    [ -z "$4" ]  ||   sha="$(___x_cmd sha256    "$filepath")"
    [ -z "$5" ]  ||   sha="$(___x_cmd sha512    "$filepath")"

    [ "$sha" = "$2$3$4$5" ]  ||  {
        pkg:error "File corrupted, except [$2$3$4$5] equal to [${sha%% *}]"
        ___x_cmd rmrf "$filepath"
        return 1
    }
    return 0
}


# <name> <version>
# <yml dir path> <name> <version>
___x_cmd_pkg___appoint(){
    pkg:sphere:parse:option
    sphere_name="${sphere_name:-"X"}"

    local yml_dir="${1}"
    [ -d "$yml_dir" ] || M='Provide a folder path' N=pkg log:ret:1
    local meta_input="$yml_dir/meta.yml";           local meta_output="$yml_dir/meta.tt.json"
    local version_intput="$yml_dir/version.yml";    local version_output="$yml_dir/version.tt.json"
    local name="${yml_dir##*/}"
    local CUSTOMIZE_PKG_NAME="$name"
    local CUSTOMIZE_PKG_PATH="tmp/$name"

    ___x_cmd ccmd --convert "$meta_input" "$meta_output"           eval "___x_cmd_pkg___appoint_handle_data \"\$meta_input\" \"\$meta_output\""
    ___x_cmd ccmd --convert "$version_intput" "$version_output"    eval "___x_cmd_pkg___appoint_handle_data \"\$version_intput\" \"\$version_output\""

    ___x_cmd_pkg___tmp_move "$yml_dir" "$meta_output" "$version_output"
    # Use add
    ___x_cmd_pkg_sphere_add --prebuild --protection use --reason "use,appoint"      \
        --sphere "$sphere_name" --sphereroot "$___X_CMD_PKG_ROOT_SPHERE"    \
        --osarch "$osarch" "$name" "$version"

    ___x_cmd_pkg___download "$name" || return $?
    ___x_cmd_pkg_sphere_populate run "$name" || return $?
    pkg:info "Download and populate $name successfully"
}

___x_cmd_pkg___appoint_handle_data(){
    local input="${1:? Provide a file path}"
    local output="${2:? Provide a file path}"
    pkg:debug INPUT_PATH="$input" OUTPUT_PATH="${output}"

    if [ "${input}" = "version.sh" ]; then
        . "${input}" > "${output}"
    else
        < "${input}"  ___x_cmd y2j | ___x_cmd ja t "\t" > "${output}"
    fi
}


___x_cmd_pkg___tmp_move(){
    local yml_dir="$1"
    local name="${yml_dir##*/}"
    local meta_j_path="$2"
    local version_j_path="$3"
    ___x_cmd mkdirp "$___X_CMD_PKG_METADATA_PATH/tmp/$name"
    ___x_cmd cp "$meta_j_path" "$___X_CMD_PKG_METADATA_PATH/tmp/$name"
    ___x_cmd cp "$version_j_path" "$___X_CMD_PKG_METADATA_PATH/tmp/$name"

    ___x_cmd mkdirp "$___X_CMD_PKG_METADATA_PATH/tmp/$name/.x-cmd"
    ! [ -d "$yml_dir/.x-cmd" ] || ___x_cmd cp "$yml_dir/.x-cmd/"* "$___X_CMD_PKG_METADATA_PATH/tmp/$name/.x-cmd"
    ___x_cmd rmrf "$meta_j_path" "$version_j_path"

}

