# shellcheck shell=dash disable=2120

xrc:mod:lib     agent       request/workspace request/util

___x_cmd_agent_request(){
    # local retry=1

    local content=""
    local harness=""
    local filelist=""
    local NL="$___X_CMD_UNSEENCHAR_NEWLINE"
    local output_format="text"
    local output_file=""
    local overwrite=""
    local stdoutfile=""
    local stderrfile=""

    local pipe=""
    local user_session_id=""
    local workspace=""
    local reference_workspace=""
    local reference_name=""
    local is_no_thinking=""
    local is_no_workspace_session=""
    local is_debug=""
    local timeout_secs="3000"
    local skill_dirlist=""

    [ "$#" -gt 0 ] || set -- --help
    while [ $# -gt 0 ]; do
        case "$1" in
            -h|--help)      ___x_cmd help -m agent request "$@" ; return 0 ;;

            --harness)      harness="$2"  ;                     arg:2:shift ;;
            --file|-f)      filelist="${filelist}${NL}${2}" ;   arg:2:shift ;;
            --pipe)         pipe="$(___x_cmd_cmds cat)" ;       shift ;;

            --output|-o)    output_file="$2"   ;                arg:2:shift ;;
            --overwrite)    overwrite=1;                        shift ;;
            --json)         output_format=json;                 shift ;;
            --session)      user_session_id="$2";               arg:2:shift ;;
            --workspace)    workspace="$2";                     arg:2:shift ;;
            --no-workspace-session)
                            is_no_workspace_session=1;          shift ;;
            --reference-workspace)
                            reference_workspace="$2";           arg:2:shift ;;
            --stdout-file)  stdoutfile="$2";                    arg:2:shift ; ___x_cmd ensurefp "$stdoutfile";;
            --stderr-file)  stderrfile="$2";                    arg:2:shift ; ___x_cmd ensurefp "$stderrfile";;
            --timeout)      timeout_secs="$2";                  arg:2:int; arg:2:shift ;;

            --no-thinking)  is_no_thinking=1 ;                  shift ;;
            --debug)        is_debug=1 ;                        shift ;;
            # --retry)        retry="$2" ; arg:2:shift ;;
            --skill-dir)    skill_dirlist="${skill_dirlist}${NL}${2}" ;
                            arg:2:shift ;;

            --)             shift; break ;;
            *)              break ;;
        esac
    done

    timeout_secs="${timeout_secs:-3000}"

    ___x_cmd agent isready || {
        if ___x_cmd_runmode_allow_manual; then
            agent:info "Agent not initialized -- running 'x agent init' automatically"
            ___x_cmd agent init || return $?
        else
            agent:error "Agent is not ready. Please run 'x agent init' to setup the agent first."
            return 1
        fi
    }

    local x_=""
    if [ -z "$harness" ]; then
        x_=""; ___x_cmd_agent_harness_
        harness="$x_"
    fi

    ___x_cmd_agent_harness_validate "$harness" || return $?

    if [ -n "$pipe" ]; then
        content="${content}
<STDIN>
${pipe}
</STDIN>
"
    fi

    while read -r f; do
        [ -f "$f" ]  || continue
        content="${content}
<FILE path=\"${f}\">
$(___x_cmd_cmds cat "$f")
</FILE>
"
    done <<A
$filelist
A

    local session_output_dir="$___X_CMD_ROOT_TMP/agent/request/session/$harness"
    if [ -n "$workspace" ]; then
        [ -d "$workspace" ] || ___x_cmd mkdirp "$workspace" || return $?
        x_=""; ___x_cmd abspath_ "$workspace"
        workspace="${x_:-"$workspace"}"

        session_output_dir="$workspace/.x-cmd/agent/request/session"
        x_=""; ___x_cmd_agent_request___workspace_prompt_ "$workspace" || return $?
        content="${content}${x_}"
        if [ "$is_no_workspace_session" != "1" ]; then
            local workspace_user_session_file="$session_output_dir/metadata/user_session_id"
            if [ ! -f "$workspace_user_session_file" ]; then
                ___x_cmd ensurefp "$workspace_user_session_file"
                ___x_cmd uuid > "$workspace_user_session_file"
            fi
            read -r user_session_id < "$workspace_user_session_file"
        fi
    fi

    if [ -n "$reference_workspace" ]; then
        if [ ! -d "$reference_workspace" ]; then
            reference_workspace=""
        else
            x_=""; ___x_cmd abspath_ "$reference_workspace"
            reference_workspace="${x_:-"$reference_workspace"}"

            x_=""; ___x_cmd_agent_request___reference_name_ "$reference_workspace" "$reference_name"
            reference_name="${x_:-reference}"
            x_=""; ___x_cmd_agent_request___reference_workspace_prompt_ "${workspace:-$PWD}" "$reference_workspace" "$reference_name" || return $?
            content="${content}${x_}"
        fi
    fi

    x_=""; ___x_cmd_agent___skill_prompt_ "$skill_dirlist"
    content="${content}${x_}"

    local IFS=" " ; local msg="$*"
    [ -z "$msg" ] || {
        content="${content}
<USERMSG>
${msg}
</USERMSG>
"
    }

    if [ -z "$output_file" ]; then
        ___x_cmd_agent_request___run
        return $?
    else
        content="${content}
Output your response wrapped with:
<OUTPUT-CONTENT>
...
</OUTPUT-CONTENT>
"

        if [ -f "$output_file" ] && [ "${overwrite:-}" != "1" ]; then
            ___x_cmd bakman backup "$output_file"
        fi

        x_="$( ___x_cmd_agent_request___run )" || \
        case $? in
            130)    return 130 ;;
            0)      ;;
            *)      return $? ;;
        esac

        x_="${x_#*<OUTPUT-CONTENT>}"
        x_="${x_%</OUTPUT-CONTENT>*}"
        x_="${x_#"$NL"}"
        x_="${x_%"$NL"}"
        printf "%s" "$x_" > "$output_file"
    fi

}

____X_CMD_AGENT_ERR_AUTHFAILURE=77
____X_CMD_AGENT_ERR_SESSION_INVALID=78
____X_CMD_AGENT_ERR_RATE_LIMIT=79
____X_CMD_AGENT_ERR_NETWORK_TIMEOUT=124
____X_CMD_AGENT_ERR_SIGINT=130

___x_cmd_agent_request___run(){
    agent:info "Sending request to harness '$harness'"
    ___x_cmd_agent_request___run_validate || return $?
    ___x_cmd retry -i 3 -m 3 ___x_cmd_agent_request___run_attempt
}

___x_cmd_agent_request___run_validate(){
    case "$harness" in
        claude)
                local loggedIn=; loggedIn="$( ___x_cmd claude -- auth status | ___x_cmd jo .loggedIn )"
                if [ "$loggedIn" != "true" ]; then
                    agent:warn \
                        --tip1 "x claude auth login" \
                        --tip2 "x claude use -h" \
                        "Claude auth status is not logged in"
                    return "$____X_CMD_AGENT_ERR_AUTHFAILURE"
                fi
                ;;
        claude-*)
                local subcmd="${harness#claude-}"
                local loggedIn=; loggedIn="$( ___x_cmd claude "$subcmd" auth status | ___x_cmd jo .loggedIn )"
                if [ "$loggedIn" != "true" ]; then
                    agent:warn "Claude $subcmd auth status is not logged in"
                    return "$____X_CMD_AGENT_ERR_AUTHFAILURE"
                fi
                ;;
        codex)
                if [ "$( ___x_cmd codex -- login status )" = "Not logged in" ]; then
                    agent:warn \
                        --tip "x codex login" \
                        "Codex auth status is not logged in"
                    return "$____X_CMD_AGENT_ERR_AUTHFAILURE"
                fi
                ;;
        cursor)
                ___x_cmd hascmd cursor || ___x_cmd hascmd agent || {
                    agent:error "Not found cursor command"
                    return 1
                }

                if [ "$( ___x_cmd_agent_request___cursor_runcmd status --format json | ___x_cmd jo .isAuthenticated )" != "true" ]; then
                    agent:warn "Cursor auth status is not logged in"
                    return "$____X_CMD_AGENT_ERR_AUTHFAILURE"
                fi
                ;;
        gemini-cli)
                ___x_cmd hascmd gemini || ___x_cmd env use gemini-cli  || {
                    agent:error "Not found gemini command"
                    return 1
                }
                ;;
        opencode)
                ___x_cmd hascmd opencode || ___x_cmd env use opencode || {
                    agent:error "Not found opencode command"
                    return 1
                }
                ;;
        kimi-cli)
                ___x_cmd hascmd kimi-cli || ___x_cmd kimi --install  || {
                    agent:error "Not found kimi command"
                    return 1
                }
                ;;
    esac
}

___x_cmd_agent_request___run_attempt(){
    ___x_cmd_agent_request___run_exec "$harness" "$content" "$output_format" "$user_session_id" "$workspace" "$is_no_thinking" "$stdoutfile" "$stderrfile" "$reference_workspace"
    local ret=$?

    if [ $ret -eq 0 ]; then
        agent:debug "Request completed successfully"
        return 0
    fi

    if [ "$ret" = "$____X_CMD_AGENT_ERR_NETWORK_TIMEOUT" ]; then
        agent:error "Agent request timed out after ${timeout_secs}s, aborting"
        ___X_CMD_RETRY_ABORT=1
        return "$____X_CMD_AGENT_ERR_NETWORK_TIMEOUT"
    elif [ "$ret" = "$____X_CMD_AGENT_ERR_AUTHFAILURE" ]; then
        case "$harness" in
            kimi-cli)
                agent:info "Authentication failed, trying auto-login..."
                ___x_cmd timeout 10 x-cmd kimi login || {
                    ___X_CMD_RETRY_ABORT=1
                    return "$____X_CMD_AGENT_ERR_AUTHFAILURE"
                }

                ___x_cmd_agent_request___run_exec "$harness" "Say OK" "text" "" "" "1" "/dev/null" "/dev/null" "" || {
                    ret=$?
                    ___X_CMD_RETRY_ABORT=1
                    return $ret
                }

                agent:info "Auto-login succeeded, retrying original request"
                ___x_cmd_agent_request___run_exec "$harness" "$content" "$output_format" "$user_session_id" "$workspace" "$is_no_thinking" "$stdoutfile" "$stderrfile" "$reference_workspace"
                ret=$?
                ;;
            *)
                agent:warn "Authentication failed for harness '$harness', aborting"
                ___X_CMD_RETRY_ABORT=1
                return "$____X_CMD_AGENT_ERR_AUTHFAILURE"
                ;;
        esac
    elif [ "$ret" = "$____X_CMD_AGENT_ERR_RATE_LIMIT" ]; then
        agent:warn "Agent request hit rate limit, aborting"
        ___X_CMD_RETRY_ABORT=1
        return "$____X_CMD_AGENT_ERR_RATE_LIMIT"
    elif [ "$ret" = "$____X_CMD_AGENT_ERR_SIGINT" ]; then
        agent:warn "Agent request interrupted by user (SIGINT)"
        ___X_CMD_RETRY_ABORT=1
        return "$____X_CMD_AGENT_ERR_SIGINT"
    fi

    if [ -n "$user_session_id" ]; then
        session_id_map_file="$session_output_dir/metadata/session_id_map/$user_session_id"
        [ ! -f "$session_id_map_file" ] || {
            agent:debug "Cleaning up session map file"
            local real_session_id="" user_session_cwd=""
            { read -r real_session_id && read -r user_session_cwd; } < "$session_id_map_file"
            local x_=""; ___x_cmd date timestamp_
            printf "timestamp: %s\nuser_session_cwd: %s\nuser_session_id: %s\nreal_session_id: %s\n" "$x_" "$user_session_cwd" "$user_session_id" "$real_session_id" >> "$session_output_dir/metadata/session_id_map/breakage_session"
            ___x_cmd rmrf "$session_id_map_file"
        }
    fi

    return $ret
}

___x_cmd_agent_request___run_exec(){(
    local harness="$1"
    local content="$2"
    local output_format="$3"
    local user_session_id="$4"
    local workspace="$5"
    local is_no_thinking="$6"
    local stdoutfile="$7"
    local stderrfile="$8"
    local reference_workspace="$9"
    shift $#

    local session_id_map_file=""
    local real_session_id=""
    local user_session_cwd=""
    local is_session_first=""
    local ret=0

    [ -z "$stdoutfile" ] || exec >> "$stdoutfile"
    [ -z "$stderrfile" ] || exec 2>> "$stderrfile"

    if [ -n "$session_output_dir" ]; then
        ___x_cmd rmrf "$session_output_dir/metadata/status" "$session_output_dir/metadata/stderr.txt"
    fi

    if [ -n "$user_session_id" ]; then
        session_id_map_file="$session_output_dir/metadata/session_id_map/$user_session_id"
        [ ! -f "$session_id_map_file" ] || {
            { read -r real_session_id && read -r user_session_cwd; } < "$session_id_map_file"
        }

        if [ -z "$real_session_id" ] || [ -z "$user_session_cwd" ] || [ ! -d "$user_session_cwd" ]; then
            is_session_first=1
            agent:debug "Session is first time, creating a new session"
            if [ -n "$workspace" ]; then
                user_session_cwd="$workspace"
            else
                user_session_cwd="$PWD"
            fi
            [ ! -f "$session_id_map_file" ] || ___x_cmd rmrf "$session_id_map_file"
            ___x_cmd ensurefp "$session_id_map_file"
        fi

        ___x_cmd_cmds cd "$user_session_cwd" || return $?
        user_session_cwd="$PWD"
    fi

    case "$harness" in
        claude|claude-*)
            if [ -n "$user_session_id" ]; then
                if [ "$is_session_first" = "1" ]; then
                    real_session_id="$( ___x_cmd uuid )"
                    set -- --session-id "$real_session_id"
                    printf "%s\n" "$real_session_id" "$user_session_cwd" > "$session_id_map_file"
                else
                    set -- --resume "$real_session_id"
                fi
            fi

            local claude_subcmd="--"
            case "$harness" in
                claude-*)   claude_subcmd="${harness#claude-}" ;;
            esac

            if [ -n "$is_no_thinking" ]; then
                set -- "$@" --settings '{"alwaysThinkingEnabled": false}'
            fi

            {
                IS_SANDBOX=1 ___x_cmd timeout "$timeout_secs" x-cmd claude "$claude_subcmd" "$@" \
                --verbose --output-format stream-json \
                --dangerously-skip-permissions \
                --allowedTools "Write,Read,Edit,Bash(x *),Bash(x-cmd *),Bash(source ~/.x-cmd.root/X *),Bash(git add *),Bash(git commit *),Bash(git diff *),Bash(git log *),Bash(git status),Bash(git status *),Bash(git push *),Bash(git pull *),Bash(git fetch *),Bash(git checkout *),Bash(git branch *),Bash(git stash *),Bash(git merge *),Bash(git tag *),Bash(npm *),Bash(pytest)" \
                ${reference_workspace:+--add-dir "$reference_workspace"} \
                --print "$content" < /dev/null
                printf "%s\n" "[EXITCODE] $?"
            } | ___x_cmd_agent_request___handle_output claude "$output_format" "$is_session_first" "$user_session_cwd" "$session_id_map_file" "$session_output_dir"
            ret=$?

            if [ -n "$real_session_id" ]; then
                ___x_cmd claude session extract --session "$real_session_id" --output "$session_output_dir"
            fi
            return $ret
            ;;
        codex)
            set -- exec
            if [ -n "$user_session_id" ]; then
                if [ "$is_session_first" != "1" ]; then
                    set -- "$@" resume "$real_session_id"
                fi
            fi

            if [ -n "$is_no_thinking" ]; then
                set -- "$@" --config model_reasoning_effort=low
            fi

            {
                ___x_cmd timeout "$timeout_secs" x-cmd codex -- "$@" --json --full-auto --skip-git-repo-check \
                ${reference_workspace:+--add-dir "$reference_workspace"} \
                "$content" < /dev/null
                printf "%s\n" "[EXITCODE] $?"
            } | ___x_cmd_agent_request___handle_output codex "$output_format" "$is_session_first" "$user_session_cwd" "$session_id_map_file" "$session_output_dir"
            ;;
        cursor)
            if [ -n "$user_session_id" ]; then
                if [ "$is_session_first" = "1" ]; then
                    real_session_id="$( ___x_cmd_agent_request___cursor_runcmd create-chat )"
                    printf "%s\n" "$real_session_id" "$user_session_cwd" > "$session_id_map_file"
                fi
                set -- --resume "$real_session_id"
            fi

            if [ "$output_format" = "json" ]; then
                set -- --output-format stream-json
            fi

            ___x_cmd_agent_request___cursor_runcmd "$@" --trust --yolo --print "$content"
            ;;
        gemini-cli)
            if [ -n "$user_session_id" ]; then
                if [ "$is_session_first" != "1" ]; then
                    set -- --resume "$real_session_id"
                fi
            fi

            [ -z "$is_no_thinking" ] || GEMINI_CLI_SYSTEM_SETTINGS_PATH="$___X_CMD_ROOT_MOD/agent/lib/request/data/gemini-no-think.json"

            {
                ___x_cmd timeout "$timeout_secs" x-cmd gemini cli -- --yolo "$@" \
                ${reference_workspace:+--include-directories "$reference_workspace"} \
                --output-format stream-json --prompt "$content" < /dev/null
                printf "%s\n" "[EXITCODE] $?"
            } | ___x_cmd_agent_request___handle_output gemini-cli "$output_format" "$is_session_first" "$user_session_cwd" "$session_id_map_file" "$session_output_dir"
            ;;
        opencode)
            if [ -n "$user_session_id" ]; then
                if [ "$is_session_first" != "1" ]; then
                    set -- --session "$real_session_id"
                fi
            fi

            if [ -n "$is_no_thinking" ]; then
                set -- "$@" --variant low
            fi

            {
                OPENCODE_PERMISSION='{"*":"allow"}' ___x_cmd timeout "$timeout_secs" x-cmd opencode run "$@" --format json "$content" < /dev/null
                printf "%s\n" "[EXITCODE] $?"
            } | ___x_cmd_agent_request___handle_output opencode "$output_format" "$is_session_first" "$user_session_cwd" "$session_id_map_file" "$session_output_dir"
            ;;
        kimi-cli)
            if [ -n "$user_session_id" ]; then
                if [ "$is_session_first" = "1" ]; then
                    real_session_id="$( ___x_cmd uuid )"
                    printf "%s\n" "$real_session_id" "$user_session_cwd" > "$session_id_map_file"
                fi
                set -- --session "$real_session_id"
            fi

            if [ -n "$is_no_thinking" ]; then
                set -- "$@" --no-thinking
            fi

            # IS_DEBUG: remove --final-message-only to get full event stream
            if [ "$is_debug" != "1" ]; then
                set -- "$@" --final-message-only
            fi

            {
                ___x_cmd timeout "$timeout_secs" x-cmd kimi -- "$@" --yolo --print --output-format stream-json \
                ${reference_workspace:+--add-dir "$reference_workspace"} \
                --prompt "$content" < /dev/null
                printf "%s\n" "[EXITCODE] $?"
            } | ___x_cmd_agent_request___handle_output kimi-cli "$output_format" "$is_session_first" "$user_session_cwd" "$session_id_map_file" "$session_output_dir"
            ;;
    esac
)}

___x_cmd_agent_request___handle_output(){
    local harness="$1"
    local output_format="$2"
    local is_session_first="$3"
    local user_session_cwd="$4"
    local save_session_id_file="$5"
    local session_output_dir="$6"

    is_debug="$is_debug" \
    output_format="$output_format" \
    is_session_first="$is_session_first" \
    user_session_cwd="$user_session_cwd" \
    save_session_id_file="$save_session_id_file" \
    session_output_dir="$session_output_dir" \
    ____X_CMD_AGENT_ERR_AUTHFAILURE="$____X_CMD_AGENT_ERR_AUTHFAILURE" \
    ____X_CMD_AGENT_ERR_NETWORK_TIMEOUT="$____X_CMD_AGENT_ERR_NETWORK_TIMEOUT" \
    ____X_CMD_AGENT_ERR_RATE_LIMIT="$____X_CMD_AGENT_ERR_RATE_LIMIT" \
    ____X_CMD_AGENT_ERR_SIGINT="$____X_CMD_AGENT_ERR_SIGINT" \
    harness="$harness" \
    ___x_cmd awk0 -m j/json -m j/jiter \
        -f "$___X_CMD_ROOT_MOD/agent/lib/awk/handle_output.awk"
}

___x_cmd_agent_request___cursor_runcmd(){
    if ___x_cmd hascmd cursor; then
        ___x_cmd_agent_request___cursor_runcmd(){
            ___x_cmd timeout "$timeout_secs" cursor agent "$@"
        }
    elif ___x_cmd hascmd agent; then
        ___x_cmd_agent_request___cursor_runcmd(){
            ___x_cmd timeout "$timeout_secs" agent "$@"
        }
    else
        agent:error "Not found cursor or agent command"
        return 1
    fi

    ___x_cmd_agent_request___cursor_runcmd "$@"
}
