export POSH_SHELL='bash'
export POSH_SHELL_VERSION=$BASH_VERSION
export POWERLINE_COMMAND='oh-my-posh'
export CONDA_PROMPT_MODIFIER=false
export OSTYPE=$OSTYPE

export VIRTUAL_ENV_DISABLE_PROMPT=1
export PYENV_VIRTUALENV_DISABLE_PROMPT=1

_omp_start_time=''
_omp_stack_count=0
_omp_job_count=0
_omp_execution_time=-1
_omp_no_status=true
_omp_status=0
_omp_pipestatus=0
_omp_executable=::OMP::

_omp_cursor_positioning=0
_omp_ftcs_marks=0

# start timer on command start
PS0='${_omp_start_time:0:$((_omp_start_time="$(_omp_milliseconds)",0))}$(_omp_ftcs_command_start)'

_omp_secondary_prompt=$(
    "$_omp_executable" print secondary \
        --shell=bash \
        --shell-version="$BASH_VERSION"
)

function _omp_set_cursor_position() {
    # not supported in Midnight Commander
    # see https://github.com/JanDeDobbeleer/oh-my-posh/issues/3415
    if [[ $_omp_cursor_positioning == 0 ]] || [[ -v MC_SID ]]; then
        return
    fi

    local oldstty=$(stty -g)
    stty raw -echo min 0

    local COL
    local ROW
    IFS=';' read -rsdR -p $'\E[6n' ROW COL

    stty "$oldstty"

    export POSH_CURSOR_LINE=${ROW#*[}
    export POSH_CURSOR_COLUMN=${COL}
}

function _omp_milliseconds() {
    if ((BASH_VERSINFO[0] >= 5)); then
        # EPOCHREALTIME is epoch time with microsecond precision and a
        # locale-dependent decimal separator, strip anything but the digits
        local epoch_micros=${EPOCHREALTIME//[!0-9]/}
        echo $((epoch_micros / 1000))
        return
    fi

    # EPOCHREALTIME requires bash 5.0 or newer
    "$_omp_executable" get millis
}

# percent-encode $1, byte-wise, keeping RFC 3986 unreserved characters literal
function _omp_urlencode() {
    local LC_ALL=C
    local str=$1 encoded='' ch i
    for ((i = 0; i < ${#str}; i++)); do
        ch=${str:i:1}
        case $ch in
        [A-Za-z0-9._~-])
            encoded+=$ch
            ;;
        *)
            printf -v ch '%%%02X' "'$ch"
            encoded+=$ch
            ;;
        esac
    done
    printf '%s' "$encoded"
}

function _omp_ftcs_command_start() {
    if [[ $_omp_ftcs_marks != 1 ]]; then
        return
    fi

    # the command comes from history: format is "  501  command", or
    # "  501* command" when the entry was modified; commands are missing
    # entirely when history is off or HISTCONTROL ignores them
    local cmd=''
    if [[ -o history ]]; then
        cmd=$(HISTTIMEFORMAT='' builtin history 1)
        cmd=${cmd#"${cmd%%[![:space:]]*}"} # strip the leading padding
        cmd=${cmd#"${cmd%%[!0-9]*}"}       # strip the history number
        cmd=${cmd#??}                      # strip the modified flag and separator
    fi

    if [[ -n $cmd ]]; then
        # advertise the command line via kitty's cmdline_url= extension
        printf '\e]133;C;cmdline_url=%s\a' "$(_omp_urlencode "$cmd")"
        return
    fi

    printf '\e]133;C\a'
}

# template function for context loading
function set_poshcontext() {
    return
}

function _omp_get_primary() {
    # Avoid unexpected expansions when we're generating the prompt below.
    shopt -u promptvars
    trap 'shopt -s promptvars' RETURN

    local prompt
    if shopt -oq posix; then
        prompt='[NOTICE: Oh My Posh prompt is not supported in POSIX mode]\n\u@\h:\w\$ '
    else
        prompt=$(
            "$_omp_executable" print primary \
                --save-cache \
                --shell=bash \
                --shell-version="$BASH_VERSION" \
                --status="$_omp_status" \
                --pipestatus="${_omp_pipestatus[*]}" \
                --no-status="$_omp_no_status" \
                --execution-time="$_omp_execution_time" \
                --job-count="$_omp_job_count" \
                --stack-count="$_omp_stack_count" \
                --terminal-width="${COLUMNS-0}" |
                tr -d '\0'
        )
    fi
    echo "${prompt@P}"
}

function _omp_get_secondary() {
    # Avoid unexpected expansions when we're generating the prompt below.
    shopt -u promptvars
    trap 'shopt -s promptvars' RETURN

    if shopt -oq posix; then
        echo '> '
    else
        echo "${_omp_secondary_prompt@P}"
    fi
}

function _omp_hook() {
    _omp_status=$? _omp_pipestatus=("${PIPESTATUS[@]}")

    if [[ -v BP_PIPESTATUS && ${#BP_PIPESTATUS[@]} -ge ${#_omp_pipestatus[@]} ]]; then
        _omp_pipestatus=("${BP_PIPESTATUS[@]}")
    fi

    _omp_stack_count=$((${#DIRSTACK[@]} - 1))
    local _omp_jobs=()
    _omp_jobs=($(jobs -p 2>/dev/null))
    _omp_job_count=${#_omp_jobs[@]}

    _omp_execution_time=-1
    _omp_no_status=true
    if [[ $_omp_start_time ]]; then
        local omp_now=$(_omp_milliseconds)
        _omp_execution_time=$((omp_now - _omp_start_time))
        _omp_no_status=false
    fi
    _omp_start_time=''

    if [[ ${_omp_pipestatus[-1]} != "$_omp_status" ]]; then
        _omp_pipestatus=("$_omp_status")
    fi

    set_poshcontext
    _omp_set_cursor_position

    PS1='$(_omp_get_primary)'
    PS2='$(_omp_get_secondary)'

    # Ensure that command substitution works in a prompt string.
    shopt -s promptvars

    return $_omp_status
}

function _omp_install_hook() {
    local cmd
    local prompt_command

    for cmd in "${PROMPT_COMMAND[@]}"; do
        if [[ $cmd = _omp_hook ]]; then
            return
        fi

        # avoid re-sourcing the same file multiple times
        if [[ $cmd = source* ]]; then
            continue
        fi

        prompt_command+=("$cmd")
    done

    # When VS Code shell integration is active, prepend so _omp_hook sets PS1 before
    # VS Code's __vsc_prompt_cmd_original wraps it with A/B shell integration sequences.
    if [[ "${TERM_PROGRAM-}" == "vscode" ]]; then
        PROMPT_COMMAND=(_omp_hook "${prompt_command[@]}")
    else
        PROMPT_COMMAND=("${prompt_command[@]}" _omp_hook)
    fi
}

_omp_install_hook
