# shellcheck shell=dash
# list is a diretory
# 1. to avoid conflicts
# 2. suitable performance for all

# ___x_cmd_pkg_sphere_safelist add --sphere X --osarch osarch <pkg name>=<version>

___x_cmd_pkg_sphere_safelist(){
    local op="$1"
    case "$op" in
        ls|exist|rm|add|isempty|rm_all)
            shift; ___x_cmd_pkg_sphere_safelist___"$op" "$@"  ;;
        *)  N=pkg M="sphere safelist no such option '$op'" log:ret:64 ;;
    esac
}

___x_cmd_pkg_sphere_safelist___add(){
    local sphere_name=; local osarch=; local reason=;
    while [ "$#" -gt 0 ]; do
        case "$1" in
            --sphere)
                    sphere_name="$2";
                    [ -n "$sphere_name" ] || M="Provide a sphere name" N=pkg log:ret:1
                    shift 2
                    ;;
            --sphereroot)
                    local ___X_CMD_PKG_ROOT_SPHERE="$2"
                    [ -n "$___X_CMD_PKG_ROOT_SPHERE" ] || M="Provide sphere root path" N=pkg log:ret:1
                    shift 2
                    ;;
            --osarch)
                    osarch="$2"; shift 2 ;;
            --reason)
                    reason="$2"; shift 2 ;;
            *)      break ;;
        esac
    done
    sphere_name="${sphere_name:-"X"}"
    [ -n "$osarch" ] || { ___x_cmd_pkg_osarch_ || return 1; osarch="$___X_CMD_PKG_OSARCH"; } || N=pkg M="Not found osarch" log:ret:1
    local safelist_rootpath="$___X_CMD_PKG_ROOT_SPHERE/$sphere_name/.x-cmd/safelist";
    local name=; local version=; local file=;
    while [ $# -gt 0 ]; do
        ___x_cmd_pkg_sphere_safelist___check_arg "$1" || return $?
        shift
        pkg:debug "Safelist adding $osarch $name $version"
        file="$safelist_rootpath/$osarch/${name}_${version}/X"
        ___x_cmd ensurefp "$file"
        printf "%s\n" "$reason" >> "$file"
    done
}

___x_cmd_pkg_sphere_safelist___rm(){
    pkg:sphere:parse:option
    sphere_name="${sphere_name:-"X"}"

    local safelist_rootpath="$___X_CMD_PKG_ROOT_SPHERE/$sphere_name/.x-cmd/safelist"
    [ -d "$safelist_rootpath" ] || return 0
    [ "$#" -gt 0 ] || {
        pkg:error "Please provide the pkg safelist to be deleted => <pkg-name>=<version>"
        return 64
    }

    ___x_cmd_pkg_sphere_safelist___parse_arg "$@" | \
        ___x_cmd_pkg_sphere_safelist___rm___inner
}

___x_cmd_pkg_sphere_safelist___exist(){
    pkg:sphere:parse:option
    sphere_name="${sphere_name:-"X"}"
    local safelist_rootpath="$___X_CMD_PKG_ROOT_SPHERE/$sphere_name/.x-cmd/safelist"
    local name=; local version=; local file=
    while [ $# -gt 0 ]; do
        ___x_cmd_pkg_sphere_safelist___check_arg "$1" || return $?
        shift
        file="$safelist_rootpath/$osarch/${name}_${version}/X";
        [ -f "$file" ] || return 1
    done
}

___x_cmd_pkg_sphere_safelist___ls(){
    pkg:sphere:parse:option
    sphere_name="${sphere_name:-"X"}"
    if ___x_cmd_is_stdout2tty; then
        ___x_cmd_pkg_sphere_safelist___ls_human --sphere "$sphere_name" --sphereroot "$___X_CMD_PKG_ROOT_SPHERE"
    else
        ___x_cmd_pkg_sphere_safelist___ls_inner --sphere "$sphere_name" --sphereroot "$___X_CMD_PKG_ROOT_SPHERE"
    fi
}

___x_cmd_pkg_sphere_safelist___ls_human(){
    pkg:sphere:parse:option
    sphere_name="${sphere_name:-"X"}"
    local l=; local osarch=; local name=; local version=; local x_=;
    ___x_cmd_pkg_sphere_safelist___ls_inner --sphere "$sphere_name" --sphereroot "$___X_CMD_PKG_ROOT_SPHERE" \
        | while ___x_cmd_readr l; do
        name="${l%%/*}"; l="${l#*/}"
        version="${l%%/*}";
        osarch="${l#*/}"

        x_=; ___x_cmd_pkg_sphere_populate get_exist_dir_ "$name" "$version" || continue
        # size="$( ___x_cmd_cmds du -sh "$x_" | ___x_cmd_cmds awk '{ print $1 }' 2>/dev/null )"
        x_=; ___x_cmd_pkg_default_version_ "$name" "$osarch" || continue
        [ "$version" != "$x_" ] || version="${version} (default)"
        printf "%s %s %s\n" "$osarch" "$name" "$version"
    done
}

___x_cmd_pkg_sphere_safelist___ls_inner()(
    pkg:sphere:parse:option
    sphere_name="${sphere_name:-"X"}"
    local dir="$___X_CMD_PKG_ROOT_SPHERE/$sphere_name/.x-cmd/safelist"
    local i=; local osarch=; local x_name=; local x_version=
    [ -d "$dir" ] || return 0
    ___x_cmd_cmds_cd "$dir" 2>/dev/null || return $?
    for i in */*/*; do
        [ -d "$i" ] || continue
        [ -f "$i/X" ] || continue
        osarch="${i%/*}"
        i="${i#"$osarch"/}"
        ___x_cmd_pkg___split_name_version_ "$i" || continue
        printf "%s\n" "$x_name/$x_version/$osarch"
    done 2>/dev/null
)

___x_cmd_pkg_sphere_safelist___isempty(){
    [ -z "$(___x_cmd_pkg_sphere_safelist___ls "$@")" ]
}

___x_cmd_pkg_sphere_safelist___parse_arg(){
    pkg:sphere:parse:option
    sphere_name="${sphere_name:-"X"}"
    local name=; local version=

    while [ $# -gt 0 ]; do
        if ___x_cmd_pkg_sphere_safelist___check_arg "$1" 2>/dev/null; then
            printf "%s\n" "$name/$version/$osarch"
        else
            ___x_cmd_pkg_sphere_safelist___ls_inner --sphere "$sphere_name" --sphereroot "$___X_CMD_PKG_ROOT_SPHERE" \
                | ___x_cmd_cmds grep -E "${1}/.*/$osarch" 2>/dev/null
        fi
        shift
    done
}

___x_cmd_pkg_sphere_safelist___check_arg(){
    case "$1" in
        *=*)    name="${1%%=*}"; version="${1#*=}" ;;
        *)      pkg:error "safelist expect '<pkg>=<version>' but get '$1'"; return 1 ;;
    esac
}

___x_cmd_pkg_sphere_safelist___rm_all(){
    pkg:sphere:parse:option
    sphere_name="${sphere_name:-"X"}"
    ___x_cmd_pkg_sphere_safelist___ls_inner --sphere "$sphere_name" --sphereroot "$___X_CMD_PKG_ROOT_SPHERE" \
        | ___x_cmd_pkg_sphere_safelist___rm___inner
}

___x_cmd_pkg_sphere_safelist___rm___inner(){
    local safelist_rootpath="$___X_CMD_PKG_ROOT_SPHERE/$sphere_name/.x-cmd/safelist"
    local fp=; local l=
    local osarch=; local name=; local version=
    while ___x_cmd_readr l; do
        name="${l%%/*}"; l="${l#*/}"
        version="${l%%/*}";
        osarch="${l#*/}"

        fp="$safelist_rootpath/$osarch/${name}_${version}"
        pkg:info "Remove $fp from safelist in [sphere=$sphere_name]"
        [ -e "$fp" ] || continue
        ___x_cmd rmrf "$fp"
    done
}
