

# refit a image ...


# x docker refit ubuntu ubuntu-x -- x env use jq yq
# x docker refit ubuntu ubuntu-x -- x ljh:refit/devinit

# x docker refit ubuntu ubuntu-x dev.init.sh

# x docker refit --code
#    RUN \
#    --mount=target=/var/lib/apt/lists,type=cache,sharing=locked \
#    --mount=target=/var/cache/apt,type=cache,sharing=locked \
#    rm -f /etc/apt/apt.conf.d/docker-clean \
#    && apt-get update \
#    && apt-get -y --no-install-recommends install \
#        ruby ruby-dev gcc

# x docker refit --from <newimage> --to <newimage>
# x docker refit --from <newimage> --to <newimage> --cmd apk add

# x docker refit --from <newimage> file

# <newimage> -> default is alpine or ubuntu or kali
# <toimage>  -> default is x-alpine-apk

___x_cmd_docker_refit___prepare_curl_(){
    local folder="$1"

    x_=""
    ___x_cmd os arch_
    ___x_cmd_docker_setup_prepare___get_pkg_path_ curl "linux/${x_}"
    ___x_cmd_cmds cp "$x_" "$folder/curl"

    ___x_cmd cacert which_
    ___x_cmd_cmds cp "$x_" "$folder/ca.crt"

    x_="
ADD curl        /bin/curl
RUN chmod +x    /bin/curl
ADD ca.crt      /etc/ssl/certs/ca-certificates.crt
"
}

___x_cmd_docker_refit___prepare_xcmd(){
    local folder="$1"

    x_=""
    ___x_cmd version archive prepare_ || return $?
    local latest="$x_"

    ___x_cmd_cmds cp "$x_" "$folder/"
    ___x_cmd_cmds cp "$___X_CMD_ROOT_MOD/x-cmd/lib/bin/x-cmd" "$folder/x-cmd"

    x_="
ADD     x-cmd           /bin/x-cmd
RUN     chmod +x        /bin/x-cmd
ADD     latest.tgz      /usr/share/x-cmd/v/latest
"

}

___X_CMD_DOCKER_SNAP_UID=501

___x_cmd_docker_refit(){
    [ "$#" -gt 0 ] || set - --help
    case "$1" in
        -h|--help)  ___x_cmd help -m docker refit; return ;;
    esac

    local debug=""

    local baseimage=""
    local newimage=""

    local apk=""
    local apt=""
    local yum=""
    local dnf=""
    local nix=""
    local pacman=""

    local go=""
    local cargo=""
    local zig=""

    local npm=""
    local deno=""
    local bun=""

    local pip=""
    local uv=""
    local pixi=""
    local xenv=""

    local ep=""
    local cmd=""
    local workdir=""

    local userabc=""
    local script=""

    local refitcnmirror=""

    arg:init docker
    while [ $# -gt 0 ]; do
        case "$1" in
            --debug)    debug=1;        shift 1 ;;

            --from)     baseimage="$2"; arg:2:shift  ;;
            --to)       newimage="$2";  arg:2:shift  ;;

            --apk)      apk="$2";       arg:2:shift  ;;
            --apt)      apt="$2";       arg:2:shift  ;;
            --yum)      yum="$2";       arg:2:shift  ;;
            --dnf)      dnf="$2";       arg:2:shift  ;;

            --pacman)   pacman="$2";    arg:2:shift  ;;

            --go)       go="$2";        arg:2:shift  ;;
            --cargo)    cargo="$2";     arg:2:shift  ;;
            --zig)      zig="$2";       arg:2:shift  ;;

            --npm)      npm="$2";       arg:2:shift  ;;
            --deno)     deno="$2";      arg:2:shift  ;;
            --bun)      bun="$2";       arg:2:shift  ;;

            --pip)      pip="$2";       arg:2:shift  ;;
            --uv)       uv="$2";        arg:2:shift  ;;

            --pixi)     pixi="$2";      arg:2:shift  ;;
            --xenv)     xenv="$2";      arg:2:shift  ;;
            # --pkgx)     pkgx="$2";      arg:2:shift  ;;  # TODO

            --userabc)  userabc=1;      shift ;;
            --workdir)  workdir="$2";   arg:2:shift  ;;

            --ep)       ep="$2";        arg:2:shift  ;;
            --epxbin)   ep="[ \"/bin/xbin.sh\" ]";
                                        shift  ;;
            --cmd)      cmd="$2";       arg:2:shift  ;;

            --script)   script="$2";    arg:2:shift  ;;

            *)          break ;;
        esac
    done

    [ -n "$baseimage" ] || baseimage="alpine:latest"
    [ -n "$newimage" ]  || N=docker M="Please from the name of new image after --to" log:ret:64
    [ -n "$refitcnmirror" ] || {
        refitcnmirror="$(___x_cmd docker --cur get refitcnmirror 2>/dev/null)"
        refitcnmirror="enable"
    }

    ___x_cmd_docker mirror pull --noupdate "$baseimage" || {
        local errcode="$?"
        case "$errcode" in
            130)    docker:warn "Intterrupted during pulling image -> $baseimage"; return 130 ;;
            *)      N=docker M="Fail to pull image -> $baseimage" log:ret:1 ;;
        esac
    }

    ___x_cmd docker cmdinfo update "$baseimage"

            [ -z "$bun" ]           || xenv="$xenv bun"
            [ -z "$uv"  ]           || xenv="$xenv uv"
            [ -z "$npm"  ]          || xenv="$xenv node"

            if ___x_cmd docker cmdinfo hascmd "$baseimage" apk; then
                [ -z "$go" ]        || apk="$apk go"
                [ -z "$cargo" ]     || apk="$apk cargo"

                # [ -z "$npm" ]       || apk="$apk npm"
                [ -z "$deno" ]      || apk="$apk deno"

                [ -z "$pip" ]       || apk="$apk py3-pip"   # TODO: add uv
                # [ -z "$pixi" ]      || apk="$apk python3"
            elif ___x_cmd docker cmdinfo hascmd "$baseimage" apt; then
                [ -z "$go" ]        || apt="$apt golang"
                [ -z "$cargo" ]     || apt="$apt cargo"

                # [ -z "$npm" ]       || apt="$apt npm"
                [ -z "$deno" ]      || apt="$apt deno"

                [ -z "$pip" ]       || apt="$apt python3"   # TODO: add uv
                # [ -z "$pixi" ]      || apk="$apk python3"
            elif ___x_cmd docker cmdinfo hascmd "$baseimage" dnf; then
                [ -z "$go" ]        || dnf="$dnf go"
                [ -z "$cargo" ]     || dnf="$dnf cargo"

                # [ -z "$npm" ]       || dnf="$dnf npm"
                [ -z "$deno" ]      || apk="$dnf deno"

                [ -z "$pip" ]       || dnf="$dnf python3"   # TODO: add uv
                # [ -z "$pixi" ]      || apk="$apk python3"
            fi


    local script_dir="$PWD"
    local dir="$PWD/.x-cmd.docker.refit.ws.$$"
    ___x_cmd mkdirp "$dir"
    (
        ___x_cmd_cmds_cd "$dir"
        ___x_cmd_cmds cp "$___X_CMD_ROOT_MOD/docker/lib/refit/dockerfile_template"/* ./

        {
            ___x_cmd_docker_refit_code_from             "$baseimage"

            ___x_cmd_docker_refit_code_user_workdir     root    /root
            local USHO=/root

            # ___x_cmd_docker_refit___prepare_curl_ . >/dev/null
            # printf "%s\n" "$x_"

            ___x_cmd_docker_refit___prepare_xcmd .
            printf "%s\n" "$x_"

            # Using x-cmd injection ...
            # printf "RUN %s\n" "sh -c '[ -d /root/.x-cmd.root ] || eval \"\$(curl -q https://get.x-cmd.com)\"'"

            printf "%s\n" "RUN ___X_CMD_ROOTBIN_SLEEP=0 x-cmd"

            [ -z "$userabc" ]       || ___x_cmd_docker_refit_code_adduser   "$baseimage"    abc abc   "$___X_CMD_DOCKER_SNAP_UID"   # normally 1000

            local xcmd="/root/.x-cmd.root/bin/___x_cmdexe"

            [ -z "$apk" ]   ||        ___x_cmd_docker_refit_code_run_apk    "$USHO" "$apk"
            [ -z "$apt" ]   ||        ___x_cmd_docker_refit_code_run_apt    "$USHO" "$apt"
            [ -z "$dnf" ]   ||        ___x_cmd_docker_refit_code_run_dnf    "$USHO" "$dnf"
            # [ -z "$yum" ]   ||        ___x_cmd_docker_refit_code_run      "--mount=type=cache,target=/var/cache/yum yum install -y $yum"

            ___x_cmd_docker_refit_code_addexe       ./xbin.sh                   /bin/xbin.sh
            ___x_cmd_docker_refit_code_addexe       ./foreversleep.sh           /bin/foreversleep.sh

            # [ -n "$ep" ]    ||  ep="[ \"/bin/xbin.sh\" ]"

            if [ -n "$script" ]; then
                [ -f "$script" ] || script="${script_dir}/$script"
                [ -f "$script" ] || {
                    ___x_cmd_docker_refit_cleanup
                    N=docker M="script not found -> $script" log:ret:64
                }

                ___x_cmd_cmds cp "${script}" "$dir"
                ___x_cmd_docker_refit_code_add      "${script##*/}"             /refit/script
                ___x_cmd_docker_refit_code_run      '/bin/sh -i /refit/script'
            fi

            [ -z "$userabc" ]       || {
                ___x_cmd_docker_refit_code_user_workdir     abc     /home/abc
                USHO=/home/abc
                ___x_cmd_docker_refit_code_run  "___X_CMD_ROOTBIN_SLEEP=0 x-cmd"
                # ___x_cmd_docker_refit_code_run  "sh -c '[ -d ${USHO}/.x-cmd.root ] || eval \"\$(curl -q https://get.x-cmd.com)\"'"
            }

            [ -z "$xenv" ]      ||          ___x_cmd_docker_refit_code_run_xenv     "$USHO"     "$xenv"
            [ -z "$pixi" ]      ||          ___x_cmd_docker_refit_code_run_pixi     "$USHO"     "$pixi"


            # Consider introducing go image
            [ -z "$go" ]        ||          ___x_cmd_docker_refit_code_run_go       "$USHO"     "$go"
            [ -z "$cargo" ]     ||          ___x_cmd_docker_refit_code_run_cargo    "$USHO"     "$cargo"
            # [ -z "$zig" ]   ||          ___x_cmd_docker_refit_code_run_npm      "$USHO"     "$zig"

            [ -z "$npm" ]       ||          ___x_cmd_docker_refit_code_run_npm      "$USHO"     "$npm"
            [ -z "$deno" ]      ||          ___x_cmd_docker_refit_code_run_deno     "$USHO"     "$deno"
            [ -z "$bun" ]       ||          ___x_cmd_docker_refit_code_run_bun      "$USHO"     "$bun"

            [ -z "$pip" ]       ||          ___x_cmd_docker_refit_code_run_pip      "$USHO"     "$pip"
            [ -z "$uv" ]        ||          ___x_cmd_docker_refit_code_run_uv       "$USHO"     "$uv"

            [ -z "$workdir" ]   ||          ___x_cmd_docker_refit_code_workdir   "$workdir"
            [ $# -eq 0 ]        ||          {   local IFS=' ';  ___x_cmd_docker_refit_code_run "$*";    }

            [ -z "$ep"  ]       ||          printf "ENTRYPOINT %s\n" "$ep"
            [ -z "$cmd" ]       ||          printf "CMD %s\n" "$cmd"
        } >Dockerfile

        # TODO: because docker build doesn't rec 130, so we have to trap sigint

        docker:info "Refitting image -> $newimage"
        ___x_cmd docker build -t "$newimage" . || {
            local errcode="$?"
            case "$errcode" in
                130)    docker:warn "Intterrupted during refit image -> $newimage" ;;
                *)      docker:warn "[ERR=$errcode] Fail to refit image -> $newimage" ;;
            esac

            # TODO: add --dev to preserve the directory
            ___x_cmd_docker_refit_cleanup "$dir"
            return "$errcode"
        }

        docker:info "Generate cmdinfo for image -> $newimage"
        ___x_cmd docker cmdinfo update "$newimage" || docker:warn "Fail to generate cmdinfo -> $newimage"
        return 0
    ) ||    return $?

    ___x_cmd_docker_refit_cleanup "$dir"
}

___x_cmd_docker_refit_cleanup(){
    local dir="$1"

    if [ -n "$debug" ]; then
        docker:warn "In debug mode, temporary workspace directory is preserved for futher diagnostics."
    else
        docker:info "[ERR=0] Removing temporary workspace directory -> $dir"
        ___x_cmd rmrf "$dir"
    fi
}

# Generate the dockerfile content to stdin ...
___x_cmd_docker_refit_dockerfile(){
    :
}


___x_cmd_docker_refit_code_from(){
    printf "FROM %s\n" "$1"
}


___x_cmd_docker_refit_code_adduser(){
    local baseimage="$1"
    local group="$2"
    local user="$3"
    local uid="$4"
    if ___x_cmd docker cmdinfo hascmd "$baseimage" useradd; then
        ___x_cmd_docker_refit_code_run  "[ -d /home/$user ] || { groupadd $group; useradd -r -u $uid -g $group $user; }"
    else
        ___x_cmd_docker_refit_code_run  "[ -d /home/$user ] || adduser -D -u $uid $user"
    fi
}

___x_cmd_docker_refit_code_user_workdir(){
    ___x_cmd_docker_refit_code_user     "$1"
    ___x_cmd_docker_refit_code_workdir  "$2"
}

___x_cmd_docker_refit_code_user(){
    printf "USER %s\n" "$1"
}

___x_cmd_docker_refit_code_workdir(){
    printf "WORKDIR %s\n" "$1"
}

___x_cmd_docker_refit_code_add(){
    printf "%s\n" "ADD $1 $2"
}

___x_cmd_docker_refit_code_addexe(){
    # printf "%s\n%s\n" "ADD ./xbin.sh            /bin/xbin.sh"           "RUN chmod +x /bin/xbin.sh"
    printf "%s\n" "ADD $1 $2" "RUN chmod +x $2"
}

___x_cmd_docker_refit_code_run(){
    printf "RUN %s\n" "$@"
}

___x_cmd_docker_refit_code_run_apk(){
    local USHO="$1"
    local apk="$2"

    local xcmd="${USHO}/.x-cmd.root/bin/___x_cmdexe"

    # ! ___x_cmd websrc testcn    ||      ___x_cmd_docker_refit_code_run  "$xcmd apk mirror set ustc || true"
    [ "$refitcnmirror" = disable ] ||   ___x_cmd_docker_refit_code_run  "if $xcmd websrc testcn; then $xcmd apk mirror set; else $xcmd apk mirror set official; fi"

    printf "RUN %s\n%s\n" \
        "--mount=type=cache,target=/etc/apk/cache,sharing=locked \\"    \
        "apk add $apk"
}

___x_cmd_docker_refit_code_run_apt(){
    local USHO="$1"
    local apt="$2"

    local xcmd="${USHO}/.x-cmd.root/bin/___x_cmdexe"

    ___x_cmd_docker_refit_code_run      'rm -f /etc/apt/apt.conf.d/docker-clean; mkdir -p /etc/apt/apt.conf.d/; echo '\''Binary::apt::APT::Keep-Downloaded-Packages "true";'\'' > /etc/apt/apt.conf.d/keep-cache'

    # ! ___x_cmd websrc testcn    ||      ___x_cmd_docker_refit_code_run  "$xcmd apt mirror set || true"
    [ "$refitcnmirror" = disable ] ||   ___x_cmd_docker_refit_code_run  "if $xcmd websrc testcn; then $xcmd apt mirror set; else $xcmd apt mirror unset 2>/dev/null || true; fi"

    # Consider judge whether need to apt update -- in 30 minutes, no update needed ... Or may be we should using mirror cache ...
    printf "RUN %s\n%s\n%s\n" \
        "--mount=type=cache,target=/var/cache/apt,sharing=locked \\"    \
        "--mount=type=cache,target=/var/lib/apt,sharing=locked \\"      \
        "apt update && apt --no-install-recommends install --yes $apt"
}

___x_cmd_docker_refit_code_run_yum(){
    :
}

___x_cmd_docker_refit_code_run_dnf(){
    local USHO="$1"
    local dnf="$2"

    local xcmd="${USHO}/.x-cmd.root/bin/___x_cmdexe"

    [ "$refitcnmirror" = disable ] ||   ___x_cmd_docker_refit_code_run  "if $xcmd websrc testcn; then $xcmd dnf mirror set; else $xcmd dnf mirror set official; fi"

    printf "RUN %s\n" \
        "--mount=type=cache,target=/var/cache/dnf dnf install -y $dnf"
}

___x_cmd_docker_refit_code_run_go(){
    local USHO="$1"
    local go="$2"

    local xcmd="${USHO}/.x-cmd.root/bin/___x_cmdexe"

    ___x_cmd_docker_refit_code_run  "if $xcmd websrc testcn; then $xcmd go proxy set; else $xcmd go proxy unset; fi || true"

    # ! ___x_cmd websrc testcn || ___x_cmd_docker_refit_code_run  "$xcmd go proxy set || true"
    [ "$refitcnmirror" = disable ]  ||  ___x_cmd_docker_refit_code_run  "$xcmd go proxy set || true"

    printf "%s\n" \
        "RUN --mount=type=cache,target=${USHO}/.cache/go-build,uid=$___X_CMD_DOCKER_SNAP_UID,gid=$___X_CMD_DOCKER_SNAP_UID \\"    \
        "go install $go"
}

___x_cmd_docker_refit_code_run_cargo(){
    local USHO="$1"
    local cargo="$2"

    local xcmd="${USHO}/.x-cmd.root/bin/___x_cmdexe"

    ___x_cmd_docker_refit_code_run  "mkdir -p ${USHO}/.cargo" # If we don't do this, it will fail with os-permission

    printf "%s\n" \
        "RUN --mount=type=cache,target=${USHO}/.cargo/registry,uid=$___X_CMD_DOCKER_SNAP_UID,gid=$___X_CMD_DOCKER_SNAP_UID \\"    \
        "cargo install $cargo"
}

___x_cmd_docker_refit_code_run_zig(){
    local USHO="$1"
    local zig="$2"

    local xcmd="${USHO}/.x-cmd.root/bin/___x_cmdexe"

    printf "%s\n" \
        "RUN --mount=type=cache,target=${USHO}/.cache/zig,uid=$___X_CMD_DOCKER_SNAP_UID,gid=$___X_CMD_DOCKER_SNAP_UID \\"    \
        "zig fetch $zig"
}

___x_cmd_docker_refit_code_run_pip(){
    local USHO="$1"
    local pip="$2"

    local xcmd="${USHO}/.x-cmd.root/bin/___x_cmdexe"

    # ___x_cmd_docker_refit_code_run      "if $xcmd websrc is cn; then $xcmd mirror pip set ali; else $xcmd mirror pip unset; fi || true"
    [ "$refitcnmirror" = disable ]  ||  ___x_cmd_docker_refit_code_run      "if $xcmd websrc testcn; then $xcmd mirror pip set ali; else $xcmd mirror pip unset; fi || true"

    printf "%s\n" \
        "RUN --mount=type=cache,target=${USHO}/.cache/pip,uid=$___X_CMD_DOCKER_SNAP_UID,gid=$___X_CMD_DOCKER_SNAP_UID \\"    \
        "python3 -m venv p && . p/bin/activate && pip3 install $pip"

    # TODO: "uv python3 -m venv p && . p/bin/activate && uv pip3 install $pip"
}

___x_cmd_docker_refit_code_run_uv(){
    local USHO="$1"
    local uv="$2"

    local xcmd="${USHO}/.x-cmd.root/bin/___x_cmdexe"

    # ___x_cmd_docker_refit_code_run  "$xcmd pkg update"

    # uv does not yet provide musl Python distributions. See https://github.com/astral-sh/uv/issues/6890 to track support.
    printf "%s\n" \
        "RUN --mount=type=cache,target=${USHO}/.cache/uv,uid=$___X_CMD_DOCKER_SNAP_UID,gid=$___X_CMD_DOCKER_SNAP_UID \\"    \
        "$xcmd uv tool install $uv"

}

___x_cmd_docker_refit_code_run_pixi(){
    local USHO="$1"
    local pixi="$2"

    local xcmd="${USHO}/.x-cmd.root/bin/___x_cmdexe"

    # [ "$refitcnmirror" = disable ]  ||  ___x_cmd_docker_refit_code_run      "if $xcmd websrc testcn; then $xcmd mirror pip set ali; else $xcmd mirror pip unset; fi || true"
    ___x_cmd_docker_refit_code_run      "[ -d $USHO/.pixi ] || $xcmd pixi --install"

    # "RUN --mount=type=cache,target=${USHO}/.cache/rattler/cache,uid=$___X_CMD_DOCKER_SNAP_UID,gid=$___X_CMD_DOCKER_SNAP_UID \\"    \
    ___x_cmd_docker_refit_code_run      "$xcmd pixi global install $pixi"
}

___x_cmd_docker_refit_code_run_xenv(){
    local USHO="$1"
    local xenv="$2"

    local xcmd="${USHO}/.x-cmd.root/bin/___x_cmdexe"

    # "RUN --mount=type=cache,target=${USHO}/.cache/rattler/cache,uid=$___X_CMD_DOCKER_SNAP_UID,gid=$___X_CMD_DOCKER_SNAP_UID \\"    \
    ___x_cmd_docker_refit_code_run      "$xcmd env use $xenv"
}

___x_cmd_docker_refit_code_run_npm(){
    local USHO="$1"
    local npm="$2"

    local xcmd="${USHO}/.x-cmd.root/bin/___x_cmdexe"

    [ "$refitcnmirror" = disable ]  ||      ___x_cmd_docker_refit_code_run  "if $xcmd websrc testcn; then $xcmd mirror npm set npmmirror; else $xcmd mirror npm unset; fi || true"

    printf "%s\n" \
        "RUN --mount=type=cache,target=${USHO}/.npm,uid=$___X_CMD_DOCKER_SNAP_UID,gid=$___X_CMD_DOCKER_SNAP_UID \\"    \
        "$xcmd npm install $npm"

    # bun install $npm
}

___x_cmd_docker_refit_code_run_deno(){
    local USHO="$1"
    local deno="$2"

    local xcmd="${USHO}/.x-cmd.root/bin/___x_cmdexe"

    # TODO: When installing globally, permission parameters need to be added.
                    # "RUN --mount=type=cache,target=${USHO}/.cache/deno,uid=1000,gid=1000 \\"    \
    ___x_cmd_docker_refit_code_run  "deno install -g -A $deno"
}

___x_cmd_docker_refit_code_run_bun(){
    local USHO="$1"
    local bun="$2"

    local xcmd="${USHO}/.x-cmd.root/bin/___x_cmdexe"

    printf "%s\n" \
            "RUN --mount=type=cache,target=${USHO}/.bun/install/cache,uid=1000,gid=1000 \\"    \
            "bun install -g $bun"
}
