# shellcheck shell=dash

xrc ui
xrc fsiter

___x_cmd log init eget

xrc:mod:lib     eget            \
    api         cache   detect  \
    extract     verify          \
    manifest    snap    which   \
    ls/_index   ls/ls_install   \
    resolve use upgrade download

___X_CMD_EGET_TMP="$___X_CMD_ROOT_TMP/eget"
___X_CMD_EGET_DATA="$___X_CMD_ROOT_DATA/eget"
___x_cmd mkdirp "${___X_CMD_EGET_DATA}" "${___X_CMD_EGET_TMP}"

# Newline constant for list accumulators in detect/extract. $NL is NOT a
# shell builtin (dash has no such variable); left unset, expressions like
# ${list:+$NL} join entries with NO separator, so multi-entry candidate
# lists collapse into one mangled line whose basename is the last file —
# breaking Tier-1 name matching on multi-binary archives.
NL='
'

___x_cmd_eget___main(){
    [ "$#" -gt 0 ] || set -- --help

    local op="$1"; shift
    case "$op" in
        -h|--help)          ___x_cmd help -m eget; return 0 ;;
        --version|-v)       ___x_cmd_eget___version; return 0 ;;
        snap)               ___x_cmd_eget_snap "$@"; return ;;
        ls|list)            ___x_cmd_eget_ls "$@"; return ;;
        resolve)            ___x_cmd_eget_resolve "$@"; return ;;
        detect-test)        ___x_cmd_eget_subcmd_detect_test "$@"; return ;;
        detect-orig)        ___x_cmd_eget_subcmd_detect_orig "$@"; return ;;
        which)              ___x_cmd_eget_which "$@"; return ;;
        use)                ___x_cmd_eget_use "$@"; return ;;
        unuse)              ___x_cmd_eget_unuse "$@"; return ;;
        usels)              ___x_cmd_eget_usels "$@"; return ;;
        upgrade|update)     ___x_cmd_eget_upgrade "$@"; return ;;
        cache)              ___x_cmd_eget_cache "$@"; return ;;
        extract)            ___x_cmd_eget_subcmd_extract "$@"; return ;;
        verify)             ___x_cmd_eget_subcmd_verify "$@"; return ;;
        rate)               ___x_cmd_eget_api_rate "$@"; return ;;
        html)               ___x_cmd_eget_subcmd_html "$@"; return ;;
        remove)             ___x_cmd_eget___remove "$@"; return ;;
        download|run|get)   ___x_cmd_eget_download "$@"; return ;;
        *)                  ___x_cmd_eget_download "$op" "$@" ;;
    esac
}

___x_cmd_eget___version(){
    printf "x eget (x-cmd pure shell implementation)\nInspired by zyedidia/eget\n"
}

___x_cmd_eget_subcmd_detect_test(){
    # Run detect using scoring algorithm, print result
    local _target="" _system="" _tag=""
    while [ $# -gt 0 ]; do
        case "$1" in
            -s|--system) shift; _system="$1" ;;
            -t|--tag)    shift; _tag="$1" ;;
            *)           _target="$1" ;;
        esac
        shift
    done
    [ -z "$_target" ] && { N=eget M="Usage: x eget detect-test <owner/repo> [-s system] [-t tag]" log:ret:64; return; }

    [ -z "$_system" ] && {
        local x_=""
        ___x_cmd os name_;  local osname="$x_"
        ___x_cmd os arch_;  local osarch="$x_"
        _system="${osname}/${osarch}"
    }

    ___X_CMD_EGET_VERBOSE="1" ___X_CMD_EGET_DETECT_MODE="scoring"
    ___x_cmd_eget_resolve_ "$_target" "github" "$_tag" "$_system" "" "0" "0" || {
        N=eget M="No asset found" log:ret:1; return;
    }
    local _pick="$x_"
    local asset_name="${_pick%%
*}"
    printf "\n[scoring] Selected: %s\n" "$asset_name"
}

___x_cmd_eget_subcmd_detect_orig(){
    # Run detect using original tier algorithm, print result
    local _target="" _system="" _tag=""
    while [ $# -gt 0 ]; do
        case "$1" in
            -s|--system) shift; _system="$1" ;;
            -t|--tag)    shift; _tag="$1" ;;
            *)           _target="$1" ;;
        esac
        shift
    done
    [ -z "$_target" ] && { N=eget M="Usage: x eget detect-orig <owner/repo> [-s system] [-t tag]" log:ret:64; return; }

    [ -z "$_system" ] && {
        local x_=""
        ___x_cmd os name_;  local osname="$x_"
        ___x_cmd os arch_;  local osarch="$x_"
        _system="${osname}/${osarch}"
    }

    ___X_CMD_EGET_VERBOSE="1" ___X_CMD_EGET_DETECT_MODE="original"
    ___x_cmd_eget_resolve_ "$_target" "github" "$_tag" "$_system" "" "0" "0" || {
        N=eget M="No asset found" log:ret:1; return;
    }
    local _pick="$x_"
    local asset_name="${_pick%%
*}"
    printf "\n[original] Selected: %s\n" "$asset_name"
}

___x_cmd_eget___remove(){
    case "${1:-}" in -h|--help) ___x_cmd help -m eget remove; return 0 ;; esac
    local target_dir="${EGET_BIN:-.}"
    local file="$1"
    [ -n "$file" ] || { N=eget M="Missing file name for remove" log:ret:64; return; }
    local path="$target_dir/$file"
    [ -f "$path" ] || { N=eget M="File not found: $path" log:ret:1; return; }
    ___x_cmd rmrf "$path"
    eget:info "Removed $path"
}

# --- Subcommands ---

# html — scrape the GitHub releases page for release info. The diagnostic
# counterpart of the API path: when api.github.com is rate-limited or
# otherwise unreachable, the release page and its expanded_assets view are
# much more leniently throttled. Exposed as a subcmd so the parser is
# directly testable (and so the user can see what the HTML fallback sees).
# Mirrors the grep approach in edwinjhlee's comment on issue #33.
___x_cmd_eget_subcmd_html(){
    case "${1:-}" in -h|--help) ___x_cmd help -m eget html; return 0 ;; esac

    local target="" _tag=""
    while [ $# -gt 0 ]; do
        case "$1" in
            -t|--tag) shift; _tag="$1" ;;
            -*)       N=eget M="html: unknown option: $1" log:ret:64; return ;;
            *)        [ -z "$target" ] && target="$1" || { N=eget M="html: unexpected argument: $1" log:ret:64; return; } ;;
        esac
        shift
    done

    [ -n "$target" ] || { N=eget M="html: missing target (user/repo)" log:ret:64; return; }
    case "$target" in
        */*) ;;
        *)    N=eget M="html: invalid target format: $target (expected user/repo)" log:ret:64; return ;;
    esac

    local owner="${target%%/*}" repo="${target#*/}"
    local json
    json="$( ___x_cmd_eget_api_release_html "github" "$owner" "$repo" "$_tag" )" || {
        N=eget M="html: failed to fetch release info for $target" log:ret:1; return
    }
    printf "%s" "$json" | ___x_cmd jq .
}

___x_cmd_eget_subcmd_extract(){
    case "${1:-}" in -h|--help) ___x_cmd help -m eget extract; return 0 ;; esac
    [ "$#" -gt 0 ] || { N=eget M="extract: missing archive file" log:ret:64; return; }
    local archive="$1"; shift
    local file_glob="" all="0" to="." name=""
    while [ $# -gt 0 ]; do
        case "$1" in
            -f|--file)  shift; file_glob="$1" ;;
            --all)      all="1" ;;
            --to)       shift; to="$1" ;;
            --name)     shift; name="$1" ;;
            *)          name="$1" ;;
        esac
        shift
    done
    : "${name:=$( basename "$archive" )}"
    name="${name%%.*}"
    ___x_cmd_eget_extract "$archive" "$file_glob" "$all" "$to" "$name"
}

___x_cmd_eget_subcmd_verify(){
    case "${1:-}" in -h|--help) ___x_cmd help -m eget verify; return 0 ;; esac
    [ "$#" -ge 2 ] || { N=eget M="verify: usage: x eget verify <file> <expected_hash>" log:ret:64; return; }
    local filepath="$1" expected="$2"
    ___x_cmd_eget_verify "$filepath" "$expected"
}
