# shellcheck shell=dash

___x_cmd_worker_id_(){
    x_="$1"
    if [ "$___X_CMD_SHELL" != dash ]; then
        # shellcheck disable=SC3060
        x_="${x_//\//_}"
    else
        local part=
        while [ -n "$x_" ]; do
            part="${x_%%/*}"
            [ "$part" != "$x_" ] || break
            x_="${part}_${x_#*/}"
        done
    fi
}

xrc:mod:lib     worker   ls

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

    local op="$1" ;         shift
    case "$op" in
        -h|--help)          ___x_cmd help -m worker "$@" ; return 0 ;;
        isalive|info|run|stop|ls)
                            ___x_cmd_worker_"$op"  "$@" ;;
        *)                  N=worker M="Unknown subcmd -> $op" log:ret:64
    esac
}

___x_cmd_worker_isalive(){
    local ns="x-worker-default"
    local name=""
    local x_=""

    while [ $# -gt 0 ]; do
        case "$1" in
            --help|-h)  ___x_cmd help -m worker isalive ; return 0 ;;
            --ns)       ns="$2" ;   arg:2:shift ;;
            --name)     name="$2" ; arg:2:shift ;;
            --)         shift ; break ;;
            *)          break ;;
        esac
    done

    [ -n "$name" ] || N=worker M="Please provide runner name" log:ret:64
    ___x_cmd_worker_id_ "$ns"; ns="$x_"
    ___x_cmd_worker_id_ "$name"; name="$x_"
    local dir="$___X_CMD_ROOT_DATA/worker/$ns"
    local runnerfile_pid="$dir/runner.$name/_PIDFILE"
    [ -f "$runnerfile_pid" ] || return 1


    local process_id=""
    local fingerprint=""
    {
        read -r process_id
        read -r fingerprint
    } < "$runnerfile_pid"

    ___x_cmd ps fingerprint check "$process_id" "$fingerprint"
}

___x_cmd_worker_info(){
    local ns="x-worker-default"
    local name=""
    local x_=""

    while [ $# -gt 0 ]; do
        case "$1" in
            --help|-h)  ___x_cmd help -m worker info ; return 0 ;;
            --ns)       ns="$2" ;   arg:2:shift ;;
            --name)     name="$2" ; arg:2:shift ;;
            --)         shift ; break ;;
            *)          break ;;
        esac
    done

    [ -n "$name" ] || N=worker M="Please provide runner name" log:ret:64
    ___x_cmd_worker_id_ "$ns"; ns="$x_"
    ___x_cmd_worker_id_ "$name"; name="$x_"
    local dir="$___X_CMD_ROOT_DATA/worker/$ns"
    local runnerfile_pid="$dir/runner.$name/_PIDFILE"
    [ -f "$runnerfile_pid" ] || return 1

    local process_id=""
    local fingerprint=""
    local stime=""
    {
        read -r process_id
        read -r fingerprint
        read -r stime
    } < "$runnerfile_pid"

    local state="ongoing"
    ___x_cmd ps fingerprint check "$process_id" "$fingerprint" || state="done"

    printf "%s\t" "$process_id" "$fingerprint" "$stime"
    printf "%s\n" "$state"
}

___x_cmd_worker_run(){
    local ns="x-worker-default"
    local name=""
    local x_=""

    while [ $# -gt 0 ]; do
        case "$1" in
            --help|-h)  ___x_cmd help -m worker run ; return 0 ;;
            --ns)       ns="$2" ;   arg:2:shift   ;;
            --name)     name="$2" ; arg:2:shift ;;
            --)         shift ; break ;;
            *)          break ;;
        esac
    done

    [ -n "$name" ] || N=worker M="Please provide runner name" log:ret:64

    ___x_cmd_worker_id_ "$ns"; ns="$x_"
    ___x_cmd_worker_id_ "$name"; name="$x_"

    ___x_cmd fslock run "x-cmd-worker-pid-file-lock-$ns-$name" ___x_cmd_worker_run___locked "$@"
}

___x_cmd_worker_run___locked(){
    if ___x_cmd_worker_isalive --ns "$ns" --name "$name" 2>/dev/null; then
        ___x_cmd log :worker warn "Worker already running -> $ns/$name, stopping it first"
        ___x_cmd_worker_stop___locked || return $?
    fi

    local dir="$___X_CMD_ROOT_DATA/worker/$ns"
    local runnerfile_dir="$dir/runner.$name"
    local runnerfile_pid="$runnerfile_dir/_PIDFILE"

    ___x_cmd mkdirp "$runnerfile_dir"

    local process_id

    (
        trap ":;" HUP ;

        ___x_cmd epoch get_

        printf "%s\n" "$*" >"$runnerfile_dir/_CMD.${x_}.$$.txt"
        "$@" >>"$runnerfile_dir/_LOG.${x_}.$$.txt" 2>&1 </dev/null &

        process_id="$!"

        ___x_cmd ps fingerprint get_ "$process_id"
        local fingerprint="$x_"

        ___x_cmd ps fingerprint toepoch_ "$fingerprint"
        local stime="$x_"

        printf "%s\n" "$process_id" "$fingerprint" "$stime">"$runnerfile_pid"
    )

}

___x_cmd_worker_stop(){
    local ns="x-worker-default"
    local name=""
    local timeout=3
    local x_=""

    while [ $# -gt 0 ]; do
        case "$1" in
            --help|-h)  ___x_cmd help -m worker stop ; return 0 ;;
            --ns)       ns="$2" ;   arg:2:shift ;;
            --name)     name="$2" ; arg:2:shift ;;
            --timeout)  timeout="$2" ; arg:2:shift ;;
            --)         shift ; break ;;
            *)          break ;;
        esac
    done

    [ -n "$name" ] || N=worker M="Please provide runner name" log:ret:64
    ___x_cmd_worker_id_ "$ns"; ns="$x_"
    ___x_cmd_worker_id_ "$name"; name="$x_"

    ___x_cmd fslock run "x-cmd-worker-pid-file-lock-$ns-$name" ___x_cmd_worker_stop___locked
}

___x_cmd_worker_stop___locked(){
    local dir="$___X_CMD_ROOT_DATA/worker/$ns"
    local runnerfile_dir="$dir/runner.$name"
    local runnerfile_pid="$runnerfile_dir/_PIDFILE"
    [ -f "$runnerfile_pid" ] || return 0

    local process_id=""
    local fingerprint=""
    {
        read -r process_id
        read -r fingerprint
    } < "$runnerfile_pid"

    if ___x_cmd ps fingerprint check "$process_id" "$fingerprint"; then
        if ! ___x_cmd kill tree "$process_id" 2>/dev/null; then
            ___x_cmd ps fingerprint check "$process_id" "$fingerprint" || return 0
            return 1
        fi

        local elapsed=0
        while [ "$elapsed" -lt "$timeout" ]; do
            ___x_cmd_cmds sleep 1
            elapsed=$((elapsed + 1))
            ___x_cmd ps fingerprint check "$process_id" "$fingerprint" || break
        done

        if ___x_cmd ps fingerprint check "$process_id" "$fingerprint"; then
            ___x_cmd kill tree -s -9 "$process_id" 2>/dev/null || return 1
        fi
    fi

    # ___x_cmd rmrf "$runnerfile_pid"
}
