#!/usr/bin/env bash
# echo "entering: ${BASH_SOURCE[0]}"
# echo "remove all echos to preseve output"
# echo ""

export PS4='\e[90m  ${BASH_SOURCE[0]##*/} -> ${BASH_SOURCE[1]##*/}: ${FUNCNAME[0]}:${LINENO}   - ${BASH_SOURCE[@]##*/} \e[0m'
if [ -n "$SH_OPT" ]; then set $SH_OPT; fi # force debug


# Set group-writable umask for multi-user installs (detected by 'dev' group membership)
if id -nG 2>/dev/null | grep -qw dev; then
  umask 002
fi

if [ -z "$LOG_LEVEL" ]; then
  export LOG_LEVEL=3
fi
if [ -z "$LOG_DEVICE" ] || [ ! -w "$LOG_DEVICE" ] || { [ "$LOG_DEVICE" = "/dev/null" ] && [ -t 1 ]; }; then
  if [ -t 1 ] && [ -w "$(tty 2>/dev/null)" ]; then
    export LOG_DEVICE="$(tty)"
  elif [ -w /proc/self/fd/1 ]; then
    export LOG_DEVICE=/proc/self/fd/1
  elif [ -w /dev/tty ]; then
    export LOG_DEVICE=/dev/tty
  else
    export LOG_DEVICE=/dev/null
  fi
fi


if [ -z "$EXPECTED_RETURN_VALUE" ]; then
  export EXPECTED_RETURN_VALUE=1
fi

if [ "$EXPECTED_RETURN_VALUE" -lt 1 ]; then
  export EXPECTED_RETURN_VALUE=1
fi


if [ -z "$OOSH_DIR" ]; then
  OOSH_DIR=$( cd "$(dirname ${BASH_SOURCE[0]})" ; pwd )
  if [ "$OOSH_DIR" = "." ]; then
    OOSH_DIR=$(pwd)
  fi
  if [ "$OOSH_DIR" = "$USERHOME/init" ]; then
    OOSH_DIR="$USERHOME/oosh"
  fi
  PATH="$OOSH_DIR:$PATH"
fi

# Ensure $SUDO is set for ALL oosh contexts. bashrcTemplate exports it
# for interactive shells, but ssh-with-command (e.g. ossh exec.tty) on
# distros without Debian's SSH_SOURCE_BASHRC bash patch (Alpine/musl)
# won't source bashrc — leaving privileged ops like user.create's
# `$SUDO useradd` to run unprivileged and fail with "Permission
# denied". Self-heal here so every oosh script invocation has a
# reliable $SUDO contract regardless of shell-startup quirks.
# Use ${SUDO+x} to distinguish unset from explicitly-empty (root sets
# SUDO="" intentionally; we must not clobber that).
if [ -z "${SUDO+x}" ]; then
  if [ "$(id -u 2>/dev/null)" = "0" ]; then
    export SUDO=""
  else
    export SUDO="sudo "
  fi
fi

private.log.install.append() # <prefix> <messageBody> # idempotent guarded append to $LOG_INSTALL: skip silently when LOG_INSTALL is unset OR not writable. <prefix> is the level tag (INFO/CONSOLE/SUCCESS/...); <messageBody> is the message body. Eliminates the 11-site copy-paste of `[ -n "$LOG_INSTALL" ] && [ -w "$LOG_INSTALL" ] && echo -e "..." >>"$LOG_INSTALL" 2>/dev/null` previously duplicated across log + this. Lives in `this` (not `log`) so info.log can reach it during early bootstrap before `log` is sourced. Output byte-identical to the prior pattern (BASH_SOURCE[1] = caller log function file, BASH_SOURCE[2] = user script, FUNCNAME[2] = user function, BASH_LINENO[1] = user line).
{
  [ -n "$LOG_INSTALL" ] && [ -w "$LOG_INSTALL" ] || return 0
  echo -e "$1: ${BASH_SOURCE[1]##*/} -> ${BASH_SOURCE[2]##*/}: ${FUNCNAME[2]}:${BASH_LINENO[1]} > $2" >>"$LOG_INSTALL" 2>/dev/null
}

info.log() {
  private.log.install.append "INFO" "$*"
  if [ "$LOG_LEVEL" -gt "3" ]; then
    echo -e "\e[90mINFO> $*\e[0m" >>$LOG_DEVICE ## normal
  fi
}

this.isNumber() {
  [[ "$1" =~ ^[0-9]+$ ]]
}

private.ensure.groupWrite() { # <file...> # ensure files are group-writable (multi-user installs)
  local f
  for f in "$@"; do
    chmod g+w "$f" 2>/dev/null
    # Fix group ownership if dev group exists (multi-user installs)
    if getent group dev >/dev/null 2>&1; then
      chgrp dev "$f" 2>/dev/null
    fi
  done
}

private.this.group.create() { # <groupName> # cross-platform create a system group if it doesn't exist. Idempotent — succeeds silently when the group is already there. Tries groupadd (RHEL/Debian/most Linux), falls back to addgroup (Alpine/busybox-based images), then to a /etc/group append if neither command is available.
  # Sibling to private.this.group.exists. Used by install state machine
  # (state 31 step 1) to ensure the `dev` group exists before any
  # user.group.add invocation. On Alma minimal `groupadd` is present;
  # on Alpine 3.x only `addgroup` (busybox) is — neither image ships both.
  if private.this.group.exists "$1"; then
    return 0
  fi
  if command -v groupadd >/dev/null 2>&1; then
    groupadd -f "$1" 2>/dev/null && return 0
  fi
  if command -v addgroup >/dev/null 2>&1; then
    addgroup "$1" 2>/dev/null && return 0
  fi
  warn.log "private.this.group.create: neither groupadd nor addgroup found — trying /etc/group append"
  # Last-resort fallback: derive next free GID >=500, append the line.
  # Sufficient for OOSH's needs (just owning the group); login-shell
  # group resolution will pick it up.
  if [ -w /etc/group ] || [ "$(id -u 2>/dev/null)" = "0" ]; then
    local nextGid=500
    while grep -qE "^[^:]*:[^:]*:${nextGid}:" /etc/group 2>/dev/null; do
      nextGid=$((nextGid + 1))
    done
    echo "$1:x:${nextGid}:" >> /etc/group 2>/dev/null && return 0
  fi
  error.log "private.this.group.create: cannot create group '$1' — no groupadd, no addgroup, can't write /etc/group"
  return 1
}

private.this.group.exists() { # <groupName> # cross-platform check if a system group exists (returns 0 if found)
  # Kernel-level helper so any script can call it without depending on `os`
  # or `user` being sourced. $OSTYPE is a bash builtin — available everywhere.
  # macOS uses dscl (Directory Services); Linux uses getent (NSS) with a
  # /etc/group fallback for minimal images that lack getent.
  case "$OSTYPE" in
    darwin*)
      command -v dscl >/dev/null 2>&1 && dscl . -read /Groups/"$1" >/dev/null 2>&1
      ;;
    *)
      if command -v getent >/dev/null 2>&1; then
        getent group "$1" >/dev/null 2>&1
      else
        grep -qE "^${1}:" /etc/group 2>/dev/null
      fi
      ;;
  esac
}

private.this.path.canonical() { # <path> # echo canonical absolute path; portable across GNU readlink -f and BSD/macOS
  # Tries GNU `readlink -f` first (Linux, macOS 12.3+) then falls back to
  # `cd && pwd -P` for older BSD readlink that lacks -f. For non-existent
  # paths echoes the input unchanged (matches readlink -f semantics on input
  # that exists at the leaf level only).
  local p="$1"
  [ -z "$p" ] && return 1
  local r
  r=$(readlink -f "$p" 2>/dev/null)
  if [ -n "$r" ]; then
    printf '%s\n' "$r"
    return 0
  fi
  if [ -d "$p" ]; then
    r=$(cd "$p" 2>/dev/null && pwd -P) && [ -n "$r" ] && { printf '%s\n' "$r"; return 0; }
  fi
  if [ -L "$p" ]; then
    local target
    target=$(readlink "$p" 2>/dev/null)
    case "$target" in
      /*) r=$(cd "$target" 2>/dev/null && pwd -P) && [ -n "$r" ] && { printf '%s\n' "$r"; return 0; } ;;
      *)  r=$(cd "$(dirname "$p")/$target" 2>/dev/null && pwd -P) && [ -n "$r" ] && { printf '%s\n' "$r"; return 0; } ;;
    esac
  fi
  printf '%s\n' "$p"
}

private.this.symlink.with.backup() { # <linkPath> <target> <ts> # ensure <linkPath> is a symlink to <target>; preserve any pre-existing real entry as <linkPath>.orig.<ts>; idempotent; fail-loud on every step
  # Shared by state 31's private.oo.user.shared.symlinks.ensure (oo) and
  # config.init.user (config). Both want the same convergence: end with a
  # symlink at <linkPath> pointing to <target>, never silently overwrite a
  # real entry, never collide with a pre-existing .orig.<ts> (the macstudio
  # `.initial` collision bug — see commit 4e1bd9f).
  #
  # Behaviour:
  #   - <linkPath> is already a symlink to <target>     → no-op (return 0)
  #   - <linkPath> is a stale symlink to something else → rm + relink
  #   - <linkPath> is a real entry (dir/file)           → mv to <linkPath>.orig.<ts>, then link
  #   - <linkPath> is absent                            → link
  #
  # Each step fails loud (no `2>/dev/null` suppression on the operations
  # we depend on for convergence). Caller checks the return code.
  local linkPath="$1"
  local target="$2"
  local ts="$3"
  if [ -z "$linkPath" ] || [ -z "$target" ] || [ -z "$ts" ]; then
    create.result 1 "private.this.symlink.with.backup requires <linkPath> <target> <ts>"
    error.log "$RESULT"
    return $(result)
  fi
  if [ -L "$linkPath" ]; then
    [ "$(readlink "$linkPath")" = "$target" ] && return 0
    if ! rm -f "$linkPath"; then
      create.result 1 "could not remove stale symlink $linkPath"
      error.log "$RESULT"; return $(result)
    fi
  elif [ -e "$linkPath" ]; then
    if ! mv "$linkPath" "$linkPath.orig.$ts"; then
      create.result 1 "could not preserve $linkPath as $linkPath.orig.$ts"
      error.log "$RESULT"; return $(result)
    fi
  fi
  if ! ln -s "$target" "$linkPath"; then
    create.result 1 "could not symlink $linkPath → $target"
    error.log "$RESULT"; return $(result)
  fi
  return 0
}

private.ensure.sharedTree() { # <dir> # ensure <dir> is group dev, recursively g+w; drop self-loops
  # Used by `config init.shared` to bring a tampered sharedConfig tree back to
  # the canonical install layout. Strict mirror of the install at oo:1462-1463
  # (chown -R developking:dev + chmod -R g+w on $CONFIG_PATH) plus a
  # corruption-fix that removes any self-referential symlink left over from
  # `cp -r ~/config sharedConfig` at oo:1405 when ~/config was already a
  # symlink at copy time.
  #
  # NOTE: install does NOT set SGID 2775 on these dirs — see commented-out
  # oo:1273-1274. Group ownership is preserved at write-time by every writer
  # calling `private.ensure.groupWrite` (this:79). Don't add SGID here.
  #
  # Elevation: only sudo when the caller doesn't own the target (i.e. the real
  # `sharedConfig/` dir typically owned developking:dev). Test fixtures and
  # caller-owned dirs use the unprivileged path — important so the test-suite
  # can run without an interactive sudo prompt.
  local dir="$1"
  if [ -z "$dir" ] || [ ! -e "$dir" ]; then
    error.log "private.ensure.sharedTree: directory missing: ${RED}$dir${NORMAL}"
    return 1
  fi
  if ! private.this.group.exists dev; then
    warn.log "private.ensure.sharedTree: dev group not present — skipping (single-user install)"
    return 0
  fi
  local _sudo=""
  [ ! -O "$dir" ] && _sudo="$SUDO"

  # Detect & drop the known self-referential symlink (sharedConfig/sharedConfig
  # -> .../sharedConfig). Compare canonical paths so we only remove true
  # self-loops, regardless of relative-vs-absolute link target.
  local resolvedDir
  resolvedDir=$(private.this.path.canonical "$dir")
  local entry
  for entry in "$dir"/*; do
    if [ -L "$entry" ]; then
      local resolvedEntry
      resolvedEntry=$(private.this.path.canonical "$entry")
      if [ -n "$resolvedEntry" ] && [ "$resolvedEntry" = "$resolvedDir" ]; then
        important.log "private.ensure.sharedTree: removing self-referential symlink ${YELLOW}$entry${NORMAL}"
        $_sudo rm -f "$entry"
      fi
    fi
  done
  $_sudo chgrp -R dev "$dir" 2>/dev/null
  $_sudo chmod -R g+w "$dir" 2>/dev/null
}

this.functionExists() {

  local startFunc="$1"
  shift
  RETURN=$1

  if [ "$(type -t $startFunc)" = "function" ]; then
    info.log "$startFunc exists"
    return 0
  else
    info.log "$startFunc does not exist"
    return 1
  fi
} 2>/dev/null

this.function.partial() # <newName> <existingName> <firstArg> # define <newName>() as a wrapper that calls <existingName> with <firstArg> closured in front of any args. Replaces ad-hoc `source /dev/stdin <<HEREDOC` patterns for runtime delegate generation; sets RESULT to the new function's signature
{
  local newName="$1"
  local existingName="$2"
  local firstArg="$3"

  if [ -z "$newName" ] || [ -z "$existingName" ] || [ -z "$firstArg" ]; then
    create.result 1 "this.function.partial requires <newName> <existingName> <firstArg>"
    error.log "$RESULT"
    return $(result)
  fi

  source /dev/stdin <<HEREDOC
$newName() { $existingName "$firstArg" "\$@"; }
HEREDOC

  create.result 0 "defined $newName() => $existingName $firstArg \$@"
  return $(result)
}

this.function.partial.completion.newName()      { c2 get.functions $OOSH_DIR/$1 2>/dev/null; }
this.function.partial.completion.existingName() { c2 get.functions $OOSH_DIR/$1 2>/dev/null; }

this.methodNotFound() { # <method> <caller> # reports unknown method with suggestions
  local method=$1
  local caller=$2
  local scriptPath="$This"

  error.log "Method '$method' not found in $caller"

  # Extract available methods using c2 pattern (inlined, no c2 dependency)
  if [ -n "$scriptPath" ] && [ -f "$scriptPath" ]; then
    local suggestions=""
    local allMethods
    allMethods=$(grep -E "^${caller}\.[^ ]*\(\) " "$scriptPath" \
      | sed 's/().*$//' \
      | sed "s/^${caller}\.//" \
      | grep -v '\.completion' \
      | grep -v '^private' \
      | sort)

    # Find prefix/substring matches
    local match
    while IFS= read -r match; do
      if [ -n "$match" ] && [[ "$match" == *"$method"* || "$method" == *"$match"* ]]; then
        if [ -n "$suggestions" ]; then
          suggestions="$suggestions, $match"
        else
          suggestions="$match"
        fi
      fi
    done <<< "$allMethods"

    if [ -n "$suggestions" ]; then
      error.log "  Did you mean: $suggestions"
    else
      error.log "  Run '$caller usage' to see available methods"
    fi
  fi

  return 127
}

if (this.functionExists this.load); then
  info.log "this was already sourced"
  return 0
fi

this.load() { # <aFunction> <aShellScript> # loads <aFunction> from a <aShellScript>
  local aFunction=$1
  shift
  if [ -n "$1" ]; then
    local fullQualifiedScript="$(command -v $1)"
    local aShellScript=$(basename $1)
    shift
  else
    error.log "this.load: No script name provided!"
    return 1
  fi

  if (this.functionExists $aShellScript.$aFunction); then
    info.log "$aShellScript was already sourced"
  else
    if [ -z "$fullQualifiedScript" ]; then
      warn.log "Please check \$PATH: $PATH"
      fullQualifiedScript="$aShellScript"
    fi
    info.log "sourcing $fullQualifiedScript $aShellScript.$aFunction $@"
    source $fullQualifiedScript
    This=$fullQualifiedScript
  fi
  $aShellScript.$aFunction "$@"
  #stop.log "loaded and executed $aShellScript.$aFunction"
  RETURN=$1
  return "$(result save)"
}

check.debug.level() {
  if [ -n "$1" ]; then
    log.level $1
  fi

  if [ "$LOG_LEVEL" -gt "6" ]; then
    info.log "step Debug ON: LOG LEVEL=$LOG_LEVEL"
    export STEP_DEBUG=ON
  else
    export STEP_DEBUG=OFF
  fi

  if [ "$LOG_LEVEL" -gt "5" ]; then
    export PS4='\e[90m  ${BASH_SOURCE[0]##*/} -> ${BASH_SOURCE[1]##*/}: ${FUNCNAME[0]}:${LINENO}   - ${BASH_SOURCE[@]##*/} \e[0m'
    #set -x
  else
    {
      set +x
    } 2>/dev/null
  fi
  #set -x
} #2>/dev/null

if ! [ "$(type -t debug.v)" = "function" ]; then
  #LOG_LEVEL=6
  source $(dirname ${BASH_SOURCE[0]})/debug
fi

this.init() {
  # Ensure CONFIG_PATH is set — needed by state machine and other file-based operations
  : ${CONFIG_PATH:=$HOME/config}
  export CONFIG_PATH
  if [ -n "$CONFIG" ]; then
    info.log "inititlized"
    if [ -f "$CONFIG" ]; then
      if ! (this.isSourced); then
        # Preserve current PATH and LOG_LIVE — config may contain stale
        # values from a different user or install phase (e.g. root's PATH
        # saved during install; bash-user's LOG_LIVE persisted in shared
        # log.env after a 4-user platform-test). PATH is built dynamically
        # by bashrcTemplate/this.path.add; LOG_LIVE is unconditionally
        # re-anchored to the current user's home by log:22 at bashrc time
        # — same anchor must hold across mid-session $CONFIG re-sources or
        # console.log starts writing to another user's directory and hits
        # "Permission denied".
        # (Write-side complement: config:261 also filters LOG_LIVE= out of
        # saved log.env so the value never gets persisted in the first place.)
        local _savedPath="$PATH" _savedLogLive="$LOG_LIVE"
        source "$CONFIG"
        export PATH="$_savedPath"
        [ -n "$_savedLogLive" ] && export LOG_LIVE="$_savedLogLive"
      fi
    fi
    return 0
  fi
  #set -x
  #does not work on mac osx. readlink does not have option -f on mac
  #local initStartPath=$(dirname $(readlink -f "${BASH_SOURCE[0]}"))
  local initStartPath=$(dirname "${BASH_SOURCE[0]}")
  let shellLevel=$SHLVL-1
  let ooShellLevel=$SHLVL+2
  #echo initStartPath $initStartPath

  # if (loop list PATH find $initStartPath); then
  #   loop list PATH rm $initStartPath
  # fi
  #export PATH=$initStartPath:$PATH

  #export PS1="[oosh $ONCE_SSH_CONFIG_HOST] $PS1"
  if ! [ "${0##*/}" = "config" ]; then
    # if [ -z "$CONFIG" ]; then
    #   echo "no config found...initialising it: $OOSH_DIR/../config"
    #   #source $OOSH_DIR/../config/user.env
    #   #config.save


    #   this.path.add "$OOSH_DIR"
    #   this.path.add "$OOSH_DIR/ng"
    #   this.path.add "$OOSH_DIR/external"
    #   this.path.add "$OOSH_DIR/init"
    #   if [ "$USER" = "root" ]; then
    #     this.path.add "$OOSH_DIR/su"
    #   fi
    #   this.path.add "."

    #   if [ -n "$OOSH_CONFIG_NEEDS_SAVE" ]; then
    #     unset OOSH_CONFIG_NEEDS_SAVE
    #     config.save
    #   fi
    #   hash -r
    #   echo "initialising config done: $CONFIG"
    # fi
    if [ -f "$CONFIG" ]; then
      source "$CONFIG"
    fi
  fi
  if [ -z "$OOSH_PROMPT" ]; then
    export OOSH_STATUS="0: started in shell level: $shellLevel"
    export OOSH_DIR="$initStartPath"
    export OOSH_SHLVL=$ooShellLevel
    export OOSH_PROMPT="oosh "
    export ERROR_CODE_RECONFIG=117
    export OOSH_CONFIG_NEEDS_SAVE=~/config/user.env
  fi
}

create.result() # <processRETURN_VALUE:0> <RESULT:all went well> <option:$1> # creates a process return value and a function RESULT that been be returned in the calling function
# to make create result work, you have to call a SOURCED function
# e.g.  if os.check some.function; then ...
#   if you call 'os check' from th scrip 'os', it cannot return a RESULT since the porcess will end and no RESULT is left...
#   if you call 'os.check' you have to source the script oo before: 
#       source oo
# Then $RESULT will be in the same process and can be read from the calling function
#   otherwise if you call 'os check' you have to call:
#      create.result ERROR_CODE "some RSULT value" save
# <option> can be 'save' then you can retrieve the result with
#      result.load
# in the calling function.
# normaly <option> should always be "$1" to mark the start of the next command
{

  RETURN_VALUE=$1
  shift
  RESULT=$1
  shift
  RETURN=$1
  

  if ! (this.isNumber "$RETURN_VALUE"); then
    export RESULT=$RETURN_VALUE
    RETURN_VALUE=0
  fi
  
  info.log "create.result: $RETURN_VALUE $RESULT"
  if [ "$RETURN" = "save" ]; then    
    shift
    RETURN=$1
    result.save "$@"
    info.log "result saved"
  fi
  info.log "next argument: $RETURN"
  
  # if ! (this.isSourced); then
  #   important.log "show RESULT: $RESULT"
  # fi
}

result() {
  if [ "$1" = "save" ]; then    
    shift
    result.save "$@"
    RETURN=$1
  fi
  if [ -z "$RETURN_VALUE" ]; then
    RETURN_VALUE=0
  fi 
  echo $RETURN_VALUE
}

result.save()
{
  export RESULT_RETURN_VALUE=$RETURN_VALUE
  export RESULT=$RESULT

  export RESULT_DATE="$(date)"
  export RESULT_CALLER="${FUNCNAME[2]}"
  export RESULT_CALL_STACK="${FUNCNAME[@]}"
  export RESULT_SOURCE_STACK="${BASH_SOURCE[@]##*/}"
  export RESULT_NEXT_ARGS="$*"
  {
    declare -px | grep "RESULT"
  } >$CONFIG_PATH/result.env
}

result.cat() { # # logs the $CONFIG_PATH/result.env file
  cat $CONFIG_PATH/result.env
}

result.show() { # # alias to result.cat
  result.cat
}

result.view() { # # alias to result.cat
  result.cat
}

result.load()
{
  source $CONFIG_PATH/result.env
}

result.into() { # <shellVarname> <?method> #
  export $1="$( cat - )"
  echo "$1=${!1}" >$CONFIG_PATH/result.env
  # if [ -n "$2" ]; then
  #   "$@"
  # fi
}

this.scope() {
  declare -p
  declare -f | grep "^[^ ]* ()" | cut -d ' ' -f1
}

this.scope.full() {
  declare -p
  this.scope
}

this.absolutePathName()     # <?path:"."> <?option:"pipe"> echos the absolut path if started else it just puts it into $RESTULT
{
  local file=$1
  shift

  if [ -z "$file" ]; then
    file="$0"
  fi

  debug.log "file: $file"
  local path=""
  local dir=""
  if [ -d "$file" ]; then
    dir="$file"
  else
    dir="$(dirname "$file")"
  fi
  debug.log "local dir: $dir"
  path=$(cd $dir; pwd) 
  local name="$(basename $file)"
    

  create.result 0 "$path/$name" "$1"


  if ! (this.isSourced); then
    if [ -n "$1" ]; then
      shift
      RETURN="$1"
      echo "$RESULT"
    else
      console.log "absolutePathName: $RESULT"
    fi
  fi
}

this.absolutePath()     # <?path:"."> <?option:"pipe"> echos the absolut path if started else it just puts it into $RESTULT
{
  local file=$1
  shift

  if [ -z "$file" ]; then
    file="$0"
  fi

  # resoleved_link=$(readlink ${file})
  # if [ -z "$resoleved_link" ]; then
  #   resoleved_link="$file"
  # fi
  # resoleved_link=$(readlink -f ${file})
  # if [ -z "$resoleved_link" ]; then
  #   resoleved_link="$file"
  # fi

  #create.result "$(dirname $(pwd)/${file#./})" "$1"
  debug.log "file: $file"
  local path=""
  local dir=""
  if [ -d "$file" ]; then
    dir="$file"
  else
    dir=$(dirname "$file")
  fi
  info.log "local dir: $dir"
  path=$( cd "$dir" ; pwd ) 
    

  create.result "$path" "$1"


  if ! (this.isSourced); then
    if [ "$1" = "pipe" ]; then
      shift
      RETURN="$1"
      echo "$RESULT"
    else
      console.log "absolutePath: $RESULT"
    fi
  # else
  #   if [ -n "$1" ]; then
  #         console.log "absolutePath: $RESULT"
  #   fi
  fi
}

this.git.branch.short() # <?gitDir:$OOSH_DIR> # print the sanitised short branch name of <gitDir>'s current HEAD (strips refs/heads/, refs/remotes/origin/, heads/origin/, origin/ prefixes). Returns empty string if HEAD is detached or the dir is not a git repo.
{
  local dir="${1:-${OOSH_DIR:-.}}"
  local b
  b=$(git -C "$dir" rev-parse --abbrev-ref HEAD 2>/dev/null)
  # Degenerate branch names like `heads/origin/dev` — produced by
  # `git worktree add <path> heads/origin/dev` or `git checkout -b origin/dev`
  # followed by odd promotion sequences — would otherwise poison any caller
  # that concatenates `origin/` onto the returned value (see oo:1342,
  # init/oosh:247). Strip the known bad prefixes so downstream code can
  # assume a bare branch name like `dev`, `testing`, `prod`.
  b="${b#refs/heads/}"
  b="${b#refs/remotes/origin/}"
  b="${b#heads/origin/}"
  b="${b#origin/}"
  printf '%s' "$b"
}

this.git.commits.count() # <gitDir> <fromRef> <toRef> # count commits reachable from <toRef> but not <fromRef> in <gitDir> via `git rev-list --count refs/heads/<fromRef>..refs/heads/<toRef>`; sets RESULT to the count (numeric string), "0" when the range is empty or a ref is missing
{
  local gitDir="$1"
  local fromRef="$2"
  local toRef="$3"

  if [ -z "$gitDir" ] || [ -z "$fromRef" ] || [ -z "$toRef" ]; then
    create.result 1 "this.git.commits.count requires <gitDir> <fromRef> <toRef>"
    error.log "$RESULT"
    return $(result)
  fi

  local _n
  # Defensive 2>/dev/null on the git invocation itself: refs may legitimately
  # not exist on test rigs without remotes — caller treats empty as 0.
  _n=$(git -C "$gitDir" rev-list --count "refs/heads/$fromRef..refs/heads/$toRef" 2>/dev/null)
  create.result 0 "${_n:-0}"
  return $(result)
}

this.git.commits.count.completion.gitDir()  { c2 files.completion $1; }
this.git.commits.count.completion.fromRef() { echo dev; echo testing; echo prod; }
this.git.commits.count.completion.toRef()   { echo dev; echo testing; echo prod; }

this() {
  create.result "${0##*/}" "$1"
}

this.caller() {
  local len=${#BASH_LINENO[@]}
  local caller=${BASH_SOURCE[2]##*/}
  info.log "script: $0"
  info.log "caller: $caller"
  info.log "source stack: ${BASH_SOURCE[*]##*/}"
  create.result "$caller" "$1" 
}

this.caller.function() {
  local function=${FUNCNAME[1]}
  info.log "function stack: ${FUNCNAME[*]}"
  create.result "$function" "$1" 
}

this.call() # <aFunction> <?aShellScript> # loads <aFunction> from a <aShellScript>
{
  local aFunction=$1
  shift

  local len=${#BASH_LINENO[@]}
  local caller=${BASH_SOURCE[$len - 2]##*/}
  #info.log "stack : ${BASH_SOURCE[@]}"
  info.log "script: $0"
  info.log "caller: $caller"

  if (this.functionExists $aFunction); then
    debug.log "this.call: $aFunction $*"
    $aFunction "$@"
    return "$?"
  #else
    #info.log "$aFunction does not exist!"
  fi
  if (this.functionExists $caller.$aFunction); then
    # Prefer compound sub-method if it exists (e.g., oo.mode.stage over oo.mode)
    if [ -n "$1" ] && (this.functionExists $caller.$aFunction.$1); then
      local subMethod=$1
      shift
      debug.log "this.call: $caller.$aFunction.$subMethod $*"
      $caller.$aFunction.$subMethod "$@"
    else
      debug.log "this.call: $caller.$aFunction $*"
      $caller.$aFunction "$@"
    fi
  else
    info.log "$caller.$aFunction does not exist!"
    local aShellScript=$aFunction
    aFunction=$1
    shift

    info.log "aShellScript: $aShellScript"
    info.log "aFunction: $aFunction"
    info.log "next parameter \$1: $1"

    # if [ -z "$aFunction" ]; then
    #   aFunction="$aShellScript"
    #   aShellScript=$(which $caller)
    # fi

    if (this.functionExists $aFunction); then
      debug.log "this.call: $aFunction $* "
      stop.log "$aFunction $*"
      $aFunction "$@"
    else
      if [ -z "$aFunction" ]; then
        aFunction=usage
      fi
      # Guard: check if aShellScript is an actual script before trying this.load
      if [ -n "$(command -v $aShellScript 2>/dev/null)" ]; then
        important.log "this.load: $aFunction $aShellScript"
        if (this.load $aFunction $aShellScript "$@"); then
          debug.log "done this.call: $aShellScript.$aFunction $*"
        else
          problem.log "this.load failed to load $aShellScript from \"$aFunction\": $?"
          return 127
        fi
      else
        # aShellScript is not a real script — it was an unknown method name
        this.methodNotFound "$aShellScript" "$caller"
        return 127
      fi
    fi
  fi
} #2>/dev/null



this.path.add() {

  # if ! this.functionExists "line.add"; then
  #   source line
  # fi

  #   echo $PATH \
  # | line.split ":" \
  # | line.quote \
  # | line.remove "$1" \
  # | line.add "$1" \
  # | line.join ":" \
  # | line.into PATH

  if ! this.functionExists "line.add"; then
    export PATH="$OOSH_DIR:$PATH"
    # Debug: info.log "PATH: $PATH"
    source $OOSH_DIR/line '' ''
    #set -x
  fi

  local currentPath=$1
  if [ "$currentPath" = "." ]; then
    [ "$(type -t info.log)" = "function" ] && info.log "fixing .     $OOSH_DIR    $1"
    currentPath="\."
    #set -x
  fi

    echo $PATH \
  | line.split ":" \
  | line.quote \
  | line.remove "$currentPath" \
  | line.prepend "$1" \
  | line.join ":" \
  | line.into PATH

  
  # source $CONFIG_PATH/result.env
  # shift

  RESULT=$PATH
  # if (loop.list PATH find "$1" silent); then
  #   debug.log "found $1 at $RESULT"
  #   loop.list PATH rm $1 silent
  #   debug.log "PATH=$1:$RESULT"
  # fi

  #export PATH="$1:$RESULT"
}


this.help.table() {
  #echo $@
  local from="$1"
  if [ -n "$1" ]; then
    from="$1"
    shift
  else
    from="$This"
  fi
  shift
  cat "$from" \
  | line find "\(\) " "$" \
  | sed 's/() //'  \
  | sed 's/{//' \
  | sed "s/^$this.//" \
  | grep "$1" \
  | line table '#' 
}

this.help() {
  #echo $@
  source line
  #set -x
  local from="$1"
  if [ -n "$1" ]; then
    from="$1"
    shift
  else
    from="$This"
  fi
  shift

  cat "$from" \
  | line.find "\(\)" "\{" \
  | line.filter "^#" \
  | line.filter "^{" \
  | line.filter "\.completion" \
  | line.filter "^private" \
  | line.quote \
  | sort \
  | grep "$this\.$1" \
  | line.prepend "'=========== # =========== # ==========='" \
  | line.prepend "'METHOD # PARAMETER # DESCRIPTION'" \
  | line.unify '#' " no name" " ${GRAY}none" " ${GRAY}please add a description" \
  | line.trim.quoted \
  | line.replace "\([^ ]\)()" "\1" \
  | line.replace " {" \
  | line.replace "$this\." \
  | line.format FORMAT_HELP 
}



this.isSourced() {
  # test.isSourced this.isSourced \ this.isSourced main                                               => called by main            and started
  # init this.isSourced           \ this.isSourced main                                               => called by main            and started
  # this.call this.isSourced      \ this.isSourced this.call main                                     => called by this.call       and sourced
  # test.case source              \ this.isSourced this.start mycmd.start source test.case main       => called by this.start      and sourced from test.case
  # mycmd.feature3 hello world    \ this.isSourced mycmd.feature3 test.case main                      => called by mycmd.feature3

  caller=${BASH_SOURCE[1]##*/}
  callerFunction=${FUNCNAME[1]}

  case $callerFunction in
  "main") #started
    create.result 1 "started by $callerFunction in $caller"
    ;;
  "this.call") #called therfore sourced
    create.result 0 "sourced because called by $callerFunction in $caller"
    ;;
  "this.start") #started depending on command [3]
    if [ "${1:-${FUNCNAME[3]}}" = "source" ]; then
      create.result 0 "sourced because called by $callerFunction in $caller" >/dev/null
    else
      create.result 1 "started by ${FUNCNAME[4]} in ${BASH_SOURCE[4]##*/}" >/dev/null
    fi
    ;;
  *) #called therfore sourced
    if [ "${0##*/}" = "$caller" ]; then
      create.result 1 "started because $caller is $0" >/dev/null
    else
      create.result 0 "sourced because called by $callerFunction in $caller" >/dev/null
    fi
  esac
  info.log "return result $(result)"
  return $(result)
}

# shellcheck disable=SC2120
this.restart()
{
    important.log "exited back into this $STARTED: exit code: $RETURN_VALUE"
    unset STARTED
    export STARTED

    if [ -z "$RETURN_VALUE" ]; then
      important.log "no return value set....propably on MacOS...mitigating"
      source ~/config/result.env
      export RETURN_VALUE=$RESULT_RETURN_VALUE
      important.log "found RETURN_VALUE=$RETURN_VALUE"
    fi

    if [ "$1" = "again" ] || { [ -n "$ERROR_CODE_RECONFIG" ] && [ "$RETURN_VALUE" -eq "$ERROR_CODE_RECONFIG" ] 2>/dev/null; } ; then
      echo "
      restarting again $?
      "
      $OOSH_DIR/this restart
    fi
}


this.start() {
  local len=${#BASH_LINENO[@]}
  local caller=${BASH_SOURCE[$len - 2]##*/}
  local callerFunction=${FUNCNAME[1]}

  This=$(command -v $caller)
  if (this.isSourced "${FUNCNAME[2]}"); then
    info.log "is sourced"
    export RESULT
    return 0
  fi

  if [ -z "$1" ]; then
    if (this.functionExists $caller.usage); then
      $caller.usage
    else
      console.log "$0: no parameter: Bye"
    fi
  fi


  while [ -n "$1" ]; do
    info.log "start 1: -$1-"
    case $1 in
    # call)
    #   shift
    #   "$@"
    #   ;;
    # discover)
    #   once.discover
    #   if [ "$ONCE_STATE" = "disvocer" ]; then
    #     ONCE_STATE=check.installation
    #     once.stage
    #   fi
    #   ;;
    start)
      stop.log "once start"
      once.server.start "$@"
      ;;
    '')
      debug.log "$0: EXIT"
      #exit 0
      return $RETURN_VALUE
      ;;
    help*)
      # Check for script-specific help first (e.g., hiveMind.help)
      if (this.functionExists $caller.help); then
        $caller.help "$@"
      else
        this.$1 $This "$@"
      fi
      ;;
    localInstall)
      echo "local install mode"
      ;;
    restart)
      if [ -z "$BASH_FILE" ]; then
        export BASH_FILE="$(command -v bash)"
      fi
      echo "restarting $BASH_FILE: $RETURN_VALUE = $ERROR_CODE_RECONFIG"


      if [ -n "$ERROR_CODE_RECONFIG" ] && [ "$RETURN_VALUE" -eq "$ERROR_CODE_RECONFIG" ] 2>/dev/null; then
        export SHELL=$BASH_FILE
        $BASH_FILE #-x # force debug
        RETURN_VALUE=$?
        #      this.restart again
      else
        echo "finally exiting oosh"
      fi
      ;;
    *)
      # Reject method names with dashes — OOSH uses dots (e.g., peer.compact not peer-compact)
      if [[ "$1" == *-* ]]; then
        error.log "Invalid method name '$1': use dots instead of dashes (e.g., ${1//-/.})"
        RETURN_VALUE=1
      else
        debug.log "this.call to: $*"
        this.call "$@"
        RETURN_VALUE=$?
      fi
    #  ;;
    esac

    shift

    while [ ! "$RETURN" = "$1" ]; do
      shift
      debug.log "shift:  -Return:$RETURN-  -$1- -command=$COMMANDS-  =$*="
      if [ -z "$1" ]; then
        debug.log "force stop"
        RETURN=
        exit $RETURN_VALUE
      fi
    done
    debug.log "found RETURN=$1"
    RETURN=$2

  done
  debug.log "will stage"
  # Only call if there are remaining arguments (prevents spurious "usage" error)
  [ -n "$1" ] && this.call "$@"

  return $RETURN_VALUE
}


###################################
info.log "
still in ${BASH_SOURCE[0]##*/}
"
#set -x

this.init



case "${0##*/}" in
  "init"|"oosh"|"log"|"this")
    #source $OOSH_DIR/loop
    #LOG_LEVEL=6
    this.path.add "$OOSH_DIR/external"
    this.path.add "$OOSH_DIR/init"
    this.path.add "."
    this.path.add "$OOSH_DIR"
    this.path.add "$OOSH_DIR/ng"

    if [ "$USER" = "root" ]; then
      this.path.add "$OOSH_DIR/su"
    fi

    if [ -n "$OOSH_CONFIG_NEEDS_SAVE" ]; then
      unset OOSH_CONFIG_NEEDS_SAVE
      # Only save config if logging functions are available.
      # When log sources this, console.log isn't defined yet — skip to avoid errors.
      if [ "$(type -t console.log)" = "function" ]; then
        source $OOSH_DIR/config
        config.save
      fi
    fi
  ;;
  "config"|"loop")
    info.log "  running ${0##*/}"
  ;;
  *)
    info.log "  running unknown ${0##*/}"
  ;;
esac






if (this.isSourced); then
  info.log "this was sourced"
  #set -x

else
  if [ -z "$STARTED" ]; then
    echo "this was started as $0" 


    case "${0##*/}" in
      "init"|"oosh"|"log"|"this")
        #source $OOSH_DIR/loop
        #LOG_LEVEL=6
        info.log "  running ${0##*/}"
      ;;
      "config"|"loop")
        info.log "  running ${0##*/}"
      ;;
      *)
        info.log "  running unknown ${0##*/}"
      ;;
    esac

    if ! [ -f $OOSH_DIR/init/once ]; then
      rm -r $OOSH_DIR/init
      ln -s $OOSH_DIR/oosh/init
    fi
    config init
    if [ -z "$BASH_FILE" ]; then
      export BASH_FILE="$(command -v bash)"
      #   echo "BASH_FILE was not set"
      # else 
      #   echo "BASH_FILE is set to: $BASH_FILE"
    fi
    echo running bash with following settings
    echo -------------------------------------
    echo  OOSH_DIR=$OOSH_DIR
    echo      PATH=$PATH
    echo BASH_FILE=$BASH_FILE
    echo    CONFIG=$CONFIG
    echo ARGUMENTS=$*
    echo -------------------------------------


    if [ -n "$1" ]; then
      echo using arguments $*
      #LOG_LEVEL=6  # force debug
      #set -x
      this.start "$@"
      #exit 0
    fi

    export STARTED="true"
    export EXPECTED_RETURN_VALUE=117

    # TDOD move into this start?
    if [ "$1" = "localInstall" ]; then 

        oo state
        # HACK needed to get the package manager right for the first time
        user get home
        # crashed the state next otherwise





        important.log "
        
        still during oosh installation

        continue with:

          state
          state next

        "
    fi
    export SHELL=$BASH_FILES
    $BASH_FILE #-x # force debug
    this.restart


  else
    if [ -z "$1" ]; then
      console.log "
      ${GREEN}oosh is already started $GRAY(shell level: $SHLVL)$NORMAL
      
      Welcome to 4.0 again      
      "
    else
      important.log "starting this with: $@"
      this.start "$@"
    fi
  fi
fi