#!/usr/bin/env bash
#clear
#export PS4='\e[90m+${LINENO} in ${#BASH_SOURCE[@]}>${FUNCNAME[0]}:${BASH_SOURCE[@]##*/} \e[0m'
#set -x

#echo "starting: $0 <LOG_LEVEL=$1>"

### new.method

# ============================================================================
# otmux - tmux wrapper for oosh
# Makes tmux commands easy to use with intuitive method names
# ============================================================================

# Always use UTF-8 mode - essential for Claude Code and modern terminal apps
# The -u flag forces tmux to assume UTF-8 is supported, regardless of locale
TMUX_CMD="tmux -u"

# Configuration file location (symlinked to ~/.tmux.conf)
# Features: mouse support, macOS clipboard (pbcopy/pbpaste), vi keys
OTMUX_CONFIG="${OOSH_DIR:-$(dirname "$0")}/tmux.conf"

# Ensure color support for Claude Code and other modern CLI apps
# FORCE_COLOR=1 is needed because NO_COLOR might be set elsewhere
export FORCE_COLOR=1
export COLORTERM=truecolor

# ─────────────────────────────────────────────────────────────────────────────
# TARGET COMPLETION HELPERS
# ─────────────────────────────────────────────────────────────────────────────
# Targets in tmux follow these patterns:
#   Session:  session_name or $session_id (e.g., "dev" or "$1")
#   Window:   [session:]window (e.g., "dev:0", "dev:main", or just "2")
#   Pane:     [session:][window.]pane (e.g., "dev:0.1", "0.2", or just "1")

private.resolve.target() {
  # Resolve direction targets (U/D/L/R) to pane IDs
  local target="$1"
  case "$target" in
    U|u|up)    $TMUX_CMD display-message -p -t "{up-of}" "#{pane_id}" 2>/dev/null || echo "$target" ;;
    D|d|down)  $TMUX_CMD display-message -p -t "{down-of}" "#{pane_id}" 2>/dev/null || echo "$target" ;;
    L|l|left)  $TMUX_CMD display-message -p -t "{left-of}" "#{pane_id}" 2>/dev/null || echo "$target" ;;
    R|r|right) $TMUX_CMD display-message -p -t "{right-of}" "#{pane_id}" 2>/dev/null || echo "$target" ;;
    *)         echo "$target" ;;
  esac
}

private.complete.sessions() {
  $TMUX_CMD list-sessions -F "#{session_name}" 2>/dev/null
}

private.complete.windows() {
  $TMUX_CMD list-windows -a -F "#{session_name}:#{window_index}:#{window_name}" 2>/dev/null | \
    while IFS=: read -r sess idx name; do
      echo "$sess:$idx"
      echo "$sess:$name"
    done
}

private.complete.panes() {
  $TMUX_CMD list-panes -a -F "#{session_name}:#{window_index}.#{pane_index}" 2>/dev/null
}

private.complete.buffers() {
  $TMUX_CMD list-buffers -F "#{buffer_name}" 2>/dev/null
}

private.complete.clients() {
  $TMUX_CMD list-clients -F "#{client_name}" 2>/dev/null
}

# ─────────────────────────────────────────────────────────────────────────────
# SESSION COMMANDS
# ─────────────────────────────────────────────────────────────────────────────

otmux.new() # <?name> <?command> # create a new session
{
  if [ -n "$1" ]; then
    local name="$1"
    shift
    $TMUX_CMD new-session -s "$name" "$@"
  else
    $TMUX_CMD new-session "$@"
  fi
}

otmux.attach() # <?target> # attach to session; target=session name or $id
{
  if [ -n "$1" ]; then
    $TMUX_CMD attach-session -t "$1"
  else
    $TMUX_CMD attach-session
  fi
}
otmux.attach.completion.target() { private.complete.sessions; }

otmux.a() # <?session> # shorthand for attach
{
  otmux.attach "$@"
}

otmux.detach() # # detach from current session
{
  $TMUX_CMD detach-client "$@"
}

otmux.d() # # shorthand for detach
{
  otmux.detach "$@"
}

otmux.sessions() # # list all sessions
{
  $TMUX_CMD list-sessions "$@"
}

otmux.ls() # # shorthand for sessions
{
  otmux.sessions "$@"
}

otmux.has() # <target> # check if session exists; target=session name
{
  $TMUX_CMD has-session -t "$1" 2>/dev/null
}
otmux.has.completion.target() { private.complete.sessions; }

otmux.kill() # <target> # kill session; target=session name to destroy
{
  if [ -n "$1" ]; then
    $TMUX_CMD kill-session -t "$1"
  else
    error.log "usage: otmux kill <session-name>"
    return 1
  fi
}
otmux.kill.completion.target() { private.complete.sessions; }

private.otmux.killAll() # # kill all sessions except current
{
  $TMUX_CMD kill-session -a "$@"
}

otmux.rename() # <new-name> # rename current session
{
  if [ -n "$1" ]; then
    $TMUX_CMD rename-session "$1"
  else
    error.log "usage: otmux rename <new-name>"
    return 1
  fi
}

otmux.switch() # <target> # switch to session; target=session name or $id
{
  if [ -n "$1" ]; then
    $TMUX_CMD switch-client -t "$1"
  else
    $TMUX_CMD switch-client "$@"
  fi
}
otmux.switch.completion.target() { private.complete.sessions; }

otmux.last() # # switch to last session
{
  $TMUX_CMD switch-client -l
}

otmux.next() # # switch to next session
{
  $TMUX_CMD switch-client -n
}

otmux.prev() # # switch to previous session
{
  $TMUX_CMD switch-client -p
}

otmux.lock() # # lock the current session
{
  $TMUX_CMD lock-session "$@"
}

# ─────────────────────────────────────────────────────────────────────────────
# WINDOW COMMANDS
# ─────────────────────────────────────────────────────────────────────────────

private.otmux.newWindow() # <?name> <?command> # create a new window
{
  if [ -n "$1" ]; then
    $TMUX_CMD new-window -n "$1" "${@:2}"
  else
    $TMUX_CMD new-window "$@"
  fi
}

otmux.nw() # <?name> <?command> # shorthand for newWindow
{
  private.otmux.newWindow "$@"
}

otmux.windows() # # list windows in current session
{
  $TMUX_CMD list-windows "$@"
}

otmux.lsw() # # shorthand for windows
{
  otmux.windows "$@"
}

private.otmux.selectWindow() # <target> # select window; target=index (0,1,2) or name
{
  if [ -n "$1" ]; then
    $TMUX_CMD select-window -t "$1"
  else
    error.log "usage: otmux selectWindow <window>"
    return 1
  fi
}
private.otmux.selectWindow.completion.target() { private.complete.windows; }

otmux.sw() # <window> # shorthand for selectWindow
{
  private.otmux.selectWindow "$@"
}

private.otmux.nextWindow() # # go to next window
{
  $TMUX_CMD next-window
}

private.otmux.prevWindow() # # go to previous window
{
  $TMUX_CMD previous-window
}

private.otmux.lastWindow() # # go to last window
{
  $TMUX_CMD last-window
}

private.otmux.killWindow() # <?target> # kill window; target=[session:]window index/name
{
  if [ -n "$1" ]; then
    $TMUX_CMD kill-window -t "$1"
  else
    $TMUX_CMD kill-window
  fi
}
private.otmux.killWindow.completion.target() { private.complete.windows; }

otmux.kw() # <?window> # shorthand for killWindow
{
  private.otmux.killWindow "$@"
}

private.otmux.renameWindow() # <new-name> # rename current window
{
  if [ -n "$1" ]; then
    $TMUX_CMD rename-window "$1"
  else
    error.log "usage: otmux renameWindow <new-name>"
    return 1
  fi
}

otmux.rw() # <new-name> # shorthand for renameWindow
{
  private.otmux.renameWindow "$@"
}

private.otmux.moveWindow() # <target> # move window; target=destination [session:]index
{
  $TMUX_CMD move-window "$@"
}
private.otmux.moveWindow.completion.target() { private.complete.windows; }

private.otmux.swapWindow() # <target> # swap with window; target=[session:]window to swap with
{
  $TMUX_CMD swap-window "$@"
}
private.otmux.swapWindow.completion.target() { private.complete.windows; }

private.otmux.linkWindow() # <src> <dst> # link window; src=source window, dst=target session
{
  $TMUX_CMD link-window "$@"
}
private.otmux.linkWindow.completion.src() { private.complete.windows; }
private.otmux.linkWindow.completion.dst() { private.complete.sessions; }

private.otmux.unlinkWindow() # <?target> # unlink window; target=window to unlink
{
  $TMUX_CMD unlink-window "$@"
}
private.otmux.unlinkWindow.completion.target() { private.complete.windows; }

private.otmux.findWindow() # <pattern> # find window by pattern
{
  if [ -n "$1" ]; then
    $TMUX_CMD find-window "$1"
  else
    error.log "usage: otmux findWindow <pattern>"
    return 1
  fi
}

private.otmux.rotateWindow() # # rotate panes in window
{
  $TMUX_CMD rotate-window "$@"
}

private.otmux.respawnWindow() # <?command> # respawn window with command
{
  $TMUX_CMD respawn-window "$@"
}

# ─────────────────────────────────────────────────────────────────────────────
# PANE COMMANDS
# ─────────────────────────────────────────────────────────────────────────────

otmux.split() # <?command> # split pane horizontally
{
  $TMUX_CMD split-window "$@"
}

private.otmux.splitH() # <?command> # split pane horizontally (alias)
{
  $TMUX_CMD split-window -h "$@"
}

otmux.split.h() # <?command> # split pane horizontally (side-by-side)
{
  private.otmux.splitH "$@"
}

private.otmux.splitV() # <?command> # split pane vertically
{
  $TMUX_CMD split-window -v "$@"
}

otmux.split.v() # <?command> # split pane vertically (top-bottom)
{
  private.otmux.splitV "$@"
}

otmux.panes() # # list panes in current window
{
  $TMUX_CMD list-panes "$@"
}

otmux.lsp() # # shorthand for panes
{
  otmux.panes "$@"
}

private.otmux.selectPane() # <target> # select pane; target=U/D/L/R direction or index (0,1,2)
{
  case "$1" in
    U|u|up)    $TMUX_CMD select-pane -U ;;
    D|d|down)  $TMUX_CMD select-pane -D ;;
    L|l|left)  $TMUX_CMD select-pane -L ;;
    R|r|right) $TMUX_CMD select-pane -R ;;
    *)         $TMUX_CMD select-pane -t "$1" ;;
  esac
}
private.otmux.selectPane.completion.target() {
  echo "U"
  echo "D"
  echo "L"
  echo "R"
  private.complete.panes
}

otmux.sp() # <direction> # shorthand for selectPane
{
  private.otmux.selectPane "$@"
}

otmux.up() # # select pane above
{
  $TMUX_CMD select-pane -U
}

otmux.down() # # select pane below
{
  $TMUX_CMD select-pane -D
}

otmux.left() # # select pane to the left
{
  $TMUX_CMD select-pane -L
}

otmux.right() # # select pane to the right
{
  $TMUX_CMD select-pane -R
}

private.otmux.lastPane() # # select last pane
{
  $TMUX_CMD last-pane
}

private.otmux.killPane() # <?target> # kill pane; target=[session:][window.]pane index
{
  if [ -n "$1" ]; then
    $TMUX_CMD kill-pane -t "$1"
  else
    $TMUX_CMD kill-pane
  fi
}
private.otmux.killPane.completion.target() { private.complete.panes; }

otmux.kp() # <?pane> # shorthand for killPane
{
  private.otmux.killPane "$@"
}

private.otmux.breakPane() # # break pane into a new window
{
  $TMUX_CMD break-pane "$@"
}

private.otmux.joinPane() # <target> # join pane to window; target=destination [session:]window
{
  $TMUX_CMD join-pane "$@"
}
private.otmux.joinPane.completion.target() { private.complete.windows; }

private.otmux.swapPane() # <target> # swap with pane; target=pane to swap with
{
  $TMUX_CMD swap-pane "$@"
}
private.otmux.swapPane.completion.target() { private.complete.panes; }

private.otmux.movePane() # <target> # move pane; target=destination window
{
  $TMUX_CMD move-pane "$@"
}
private.otmux.movePane.completion.target() { private.complete.windows; }

private.otmux.resizePane() # <direction> <?amount> # resize pane; direction=U/D/L/R, amount=cells (default 5)
{
  local amount="${2:-5}"
  case "$1" in
    U|u|up)    $TMUX_CMD resize-pane -U "$amount" ;;
    D|d|down)  $TMUX_CMD resize-pane -D "$amount" ;;
    L|l|left)  $TMUX_CMD resize-pane -L "$amount" ;;
    R|r|right) $TMUX_CMD resize-pane -R "$amount" ;;
    *)         $TMUX_CMD resize-pane "$@" ;;
  esac
}
private.otmux.resizePane.completion.direction() {
  echo "U"
  echo "D"
  echo "L"
  echo "R"
}

otmux.rp() # <direction> <?amount> # shorthand for resizePane
{
  private.otmux.resizePane "$@"
}

otmux.zoom() # # toggle pane zoom
{
  $TMUX_CMD resize-pane -Z
}

otmux.z() # # shorthand for zoom
{
  otmux.zoom
}

private.otmux.respawnPane() # <?command> # respawn pane with command
{
  $TMUX_CMD respawn-pane "$@"
}

private.otmux.pipePane() # <?command> # pipe pane output to command
{
  $TMUX_CMD pipe-pane "$@"
}

private.otmux.displayPanes() # # display pane numbers
{
  $TMUX_CMD display-panes "$@"
}

otmux.dp() # # shorthand for displayPanes
{
  private.otmux.displayPanes "$@"
}

private.otmux.capturePane() # <?options> # capture pane contents
{
  $TMUX_CMD capture-pane "$@"
}

private.otmux.clearHistory() # # clear pane history
{
  $TMUX_CMD clear-history "$@"
}

# ─────────────────────────────────────────────────────────────────────────────
# LAYOUT COMMANDS
# ─────────────────────────────────────────────────────────────────────────────

otmux.layout() # <layout> # set window layout
{
  if [ -n "$1" ]; then
    $TMUX_CMD select-layout "$1"
  else
    $TMUX_CMD select-layout
  fi
}
otmux.layout.completion.layout() {
  echo "even-horizontal"
  echo "even-vertical"
  echo "main-horizontal"
  echo "main-vertical"
  echo "tiled"
}

private.otmux.evenH() # # set even-horizontal layout
{
  $TMUX_CMD select-layout even-horizontal
}

private.otmux.evenV() # # set even-vertical layout
{
  $TMUX_CMD select-layout even-vertical
}

private.otmux.mainH() # # set main-horizontal layout
{
  $TMUX_CMD select-layout main-horizontal
}

private.otmux.mainV() # # set main-vertical layout
{
  $TMUX_CMD select-layout main-vertical
}

otmux.tiled() # # set tiled layout
{
  $TMUX_CMD select-layout tiled
}

private.otmux.nextLayout() # # cycle to next layout
{
  $TMUX_CMD next-layout
}

private.otmux.prevLayout() # # cycle to previous layout
{
  $TMUX_CMD previous-layout
}

# ─────────────────────────────────────────────────────────────────────────────
# BUFFER COMMANDS
# ─────────────────────────────────────────────────────────────────────────────

otmux.buffers() # # list buffers
{
  $TMUX_CMD list-buffers "$@"
}

otmux.lsb() # # shorthand for buffers
{
  otmux.buffers "$@"
}

private.otmux.showBuffer() # <?buffer> # show buffer contents; buffer=buffer name
{
  $TMUX_CMD show-buffer "$@"
}
private.otmux.showBuffer.completion.buffer() { private.complete.buffers; }

private.otmux.setBuffer() # <data> # set buffer data
{
  if [ -n "$1" ]; then
    $TMUX_CMD set-buffer "$1"
  else
    error.log "usage: otmux setBuffer <data>"
    return 1
  fi
}

private.otmux.loadBuffer() # <file> # load buffer from file
{
  if [ -n "$1" ]; then
    $TMUX_CMD load-buffer "$1"
  else
    error.log "usage: otmux loadBuffer <file>"
    return 1
  fi
}

private.otmux.saveBuffer() # <file> # save buffer to file
{
  if [ -n "$1" ]; then
    $TMUX_CMD save-buffer "$1"
  else
    error.log "usage: otmux saveBuffer <file>"
    return 1
  fi
}

private.otmux.deleteBuffer() # <?buffer> # delete buffer; buffer=buffer name
{
  $TMUX_CMD delete-buffer "$@"
}
private.otmux.deleteBuffer.completion.buffer() { private.complete.buffers; }

private.otmux.pasteBuffer() # # paste buffer contents
{
  $TMUX_CMD paste-buffer "$@"
}

otmux.paste() # # shorthand for pasteBuffer
{
  private.otmux.pasteBuffer "$@"
}

private.otmux.chooseBuffer() # # interactively choose a buffer
{
  $TMUX_CMD choose-buffer "$@"
}

# ─────────────────────────────────────────────────────────────────────────────
# CLIENT COMMANDS
# ─────────────────────────────────────────────────────────────────────────────

otmux.clients() # # list clients
{
  $TMUX_CMD list-clients "$@"
}

otmux.lsc() # # shorthand for clients
{
  otmux.clients "$@"
}

private.otmux.detachClient() # <?client> # detach client; client=client tty (e.g., /dev/pts/0)
{
  $TMUX_CMD detach-client "$@"
}
private.otmux.detachClient.completion.client() { private.complete.clients; }

private.otmux.suspendClient() # # suspend current client
{
  $TMUX_CMD suspend-client "$@"
}

private.otmux.refreshClient() # # refresh client display
{
  $TMUX_CMD refresh-client "$@"
}

private.otmux.chooseClient() # # interactively choose a client
{
  $TMUX_CMD choose-client "$@"
}

private.otmux.chooseTree() # # interactively choose session/window
{
  $TMUX_CMD choose-tree "$@"
}

private.otmux.lockClient() # # lock the client
{
  $TMUX_CMD lock-client "$@"
}

# ─────────────────────────────────────────────────────────────────────────────
# SERVER COMMANDS
# ─────────────────────────────────────────────────────────────────────────────

private.otmux.startServer() # # start the tmux server
{
  $TMUX_CMD start-server
}

private.otmux.killServer() # # kill the tmux server
{
  $TMUX_CMD kill-server
}

private.otmux.lockServer() # # lock all clients
{
  $TMUX_CMD lock-server
}

otmux.info() # # show server information
{
  $TMUX_CMD info
}

# ─────────────────────────────────────────────────────────────────────────────
# CONFIGURATION COMMANDS
# ─────────────────────────────────────────────────────────────────────────────

otmux.source() # <?file> # source a config file (defaults to otmux config)
{
  if [ -n "$1" ]; then
    $TMUX_CMD source-file "$1"
  elif [ -f "$OTMUX_CONFIG" ]; then
    $TMUX_CMD source-file "$OTMUX_CONFIG"
    echo "Loaded: $OTMUX_CONFIG"
  else
    $TMUX_CMD source-file ~/.tmux.conf
  fi
}

otmux.reload() # # reload the otmux config (mouse, clipboard, etc.)
{
  if [ -f "$OTMUX_CONFIG" ]; then
    $TMUX_CMD source-file "$OTMUX_CONFIG"
    echo "Reloaded: $OTMUX_CONFIG"
    echo "Features: mouse support, macOS clipboard, vi keys, 256 colors"
  elif [ -f ~/.tmux.conf ]; then
    $TMUX_CMD source-file ~/.tmux.conf
    echo "Reloaded: ~/.tmux.conf"
  else
    error.log "No config file found"
    return 1
  fi
}

private.otmux.configPath() # # show the otmux config file location
{
  if [ -f "$OTMUX_CONFIG" ]; then
    echo "$OTMUX_CONFIG"
  else
    echo "~/.tmux.conf"
  fi
}

# Default tmux configuration template location
OTMUX_DEFAULT_CONFIG_TEMPLATE="${OOSH_DIR:-$(dirname "$0")}/templates/user/tmux_default_config"

# Output the default tmux configuration from external template
private.default.config() {
  if [ -f "$OTMUX_DEFAULT_CONFIG_TEMPLATE" ]; then
    cat "$OTMUX_DEFAULT_CONFIG_TEMPLATE"
  else
    error.log "Template not found: $OTMUX_DEFAULT_CONFIG_TEMPLATE"
    return 1
  fi
}

otmux.config.init() # # create default tmux config if not exists (with color support)
{
  local config_file="$HOME/.tmux.conf"
  local oosh_link="$OTMUX_CONFIG"
  
  # Check if config already exists
  if [ -f "$config_file" ]; then
    echo "Config already exists: $config_file"
    echo "Use 'otmux config.reset' to overwrite with defaults"
    return 0
  fi
  
  # Create the config file
  echo "Creating default tmux config: $config_file"
  private.default.config > "$config_file"
  
  # Create symlink in oosh directory if it doesn't exist
  if [ ! -e "$oosh_link" ] && [ -n "$oosh_link" ]; then
    ln -sf "$config_file" "$oosh_link" 2>/dev/null && \
      echo "Created symlink: $oosh_link -> $config_file"
  fi
  
  # Source the config if tmux server is running
  if $TMUX_CMD list-sessions &>/dev/null; then
    $TMUX_CMD source-file "$config_file"
    echo "Config loaded into running tmux server"
  fi
  
  echo ""
  echo "Features enabled:"
  echo "  - Mouse support (click, scroll, select)"
  echo "  - macOS clipboard (pbcopy/pbpaste)"
  echo "  - Color support (FORCE_COLOR=1, COLORTERM=truecolor)"
  echo "  - Vi-style copy mode"
  echo "  - 50,000 line scrollback"
  echo "  - Intuitive splits: prefix + | (horizontal), prefix + - (vertical)"
}

otmux.config.reset() # # reset tmux config to default (overwrites existing)
{
  local config_file="$HOME/.tmux.conf"
  local oosh_link="$OTMUX_CONFIG"
  local backup_file="$config_file.backup.$(date +%Y%m%d_%H%M%S)"
  
  # Backup existing config if present
  if [ -f "$config_file" ] && [ ! -L "$config_file" ]; then
    cp "$config_file" "$backup_file"
    echo "Backed up existing config to: $backup_file"
  fi
  
  # Create/overwrite the config file
  echo "Resetting tmux config to defaults: $config_file"
  private.default.config > "$config_file"
  
  # Ensure symlink in oosh directory
  if [ -n "$oosh_link" ]; then
    rm -f "$oosh_link" 2>/dev/null
    ln -sf "$config_file" "$oosh_link" 2>/dev/null && \
      echo "Updated symlink: $oosh_link -> $config_file"
  fi
  
  # Source the config if tmux server is running
  if $TMUX_CMD list-sessions &>/dev/null; then
    $TMUX_CMD source-file "$config_file"
    echo "Config reloaded into running tmux server"
  fi
  
  echo ""
  echo "Config reset to defaults with color support for Claude Code"
}

otmux.install() # # install tmux via oo cmd and initialize config
{
  echo "Checking tmux installation..."
  
  # Use oo cmd to check and install tmux
  # oo cmd handles package manager detection via oo.pm.discover and $OOSH_PM
  oo cmd tmux
  
  # Verify installation
  if ! command -v tmux &>/dev/null; then
    error.log "tmux installation failed"
    return 1
  fi
  
  echo ""
  echo "tmux installed successfully: $(tmux -V)"
  echo ""
  
  # Initialize config
  otmux.config.init
}

otmux.set() # <option> <value> # set a tmux option
{
  $TMUX_CMD set-option "$@"
}

private.otmux.setGlobal() # <option> <value> # set a global option
{
  $TMUX_CMD set-option -g "$@"
}

private.otmux.setWindow() # <option> <value> # set a window option
{
  $TMUX_CMD set-window-option "$@"
}

otmux.show() # <?option> # show options
{
  $TMUX_CMD show-options "$@"
}

private.otmux.showGlobal() # <?option> # show global options
{
  $TMUX_CMD show-options -g "$@"
}

private.otmux.showWindow() # <?option> # show window options
{
  $TMUX_CMD show-window-options "$@"
}

private.otmux.showHooks() # # show hooks
{
  $TMUX_CMD show-hooks "$@"
}

private.otmux.setHook() # <hook> <command> # set a hook
{
  $TMUX_CMD set-hook "$@"
}

# ─────────────────────────────────────────────────────────────────────────────
# KEY BINDING COMMANDS
# ─────────────────────────────────────────────────────────────────────────────

otmux.bind() # <key> <command> # bind a key
{
  $TMUX_CMD bind-key "$@"
}

otmux.unbind() # <key> # unbind a key
{
  $TMUX_CMD unbind-key "$@"
}

otmux.keys() # # list key bindings
{
  $TMUX_CMD list-keys "$@"
}

otmux.lsk() # # shorthand for keys
{
  otmux.keys "$@"
}

# ─────────────────────────────────────────────────────────────────────────────
# ENVIRONMENT COMMANDS
# ─────────────────────────────────────────────────────────────────────────────

private.otmux.setEnv() # <name> <value> # set environment variable
{
  $TMUX_CMD set-environment "$@"
}

private.otmux.showEnv() # <?name> # show environment variables
{
  $TMUX_CMD show-environment "$@"
}

# ─────────────────────────────────────────────────────────────────────────────
# SEND/RUN COMMANDS
# ─────────────────────────────────────────────────────────────────────────────

otmux.send() # <target> <keys> # send keys to pane; target=pane id, index, or direction (U/D/L/R)
{
  local target=$(private.resolve.target "$1")
  shift
  # Detect trailing Enter — add delay for TUI apps like Claude Code.
  # Without delay, the TUI receives Enter before processing the text.
  local last=""
  for last in "$@"; do :; done
  if [ "$last" = "Enter" ] && [ $# -gt 1 ]; then
    local text_count=$(($# - 1))
    $TMUX_CMD send-keys -t "$target" "${@:1:text_count}"
    sleep 0.05
    $TMUX_CMD send-keys -t "$target" Enter
  else
    $TMUX_CMD send-keys -t "$target" "$@"
  fi
}
otmux.parameter.completion.target() {
  echo "U"
  echo "D"
  echo "L"
  echo "R"
  private.complete.panes
}

otmux.send.verified() # <target> <text> <?timeout:3> # send text to pane and verify delivery via capture
{
    local target=$(private.resolve.target "$1")
    local text="$2"
    local timeout="${3:-3}"

    if [ -z "$target" ] || [ -z "$text" ]; then
        error.log "usage: otmux send.verified <target> <text> <?timeout>"
        return 1
    fi

    # Capture state BEFORE send
    local before
    before=$($TMUX_CMD capture-pane -t "$target" -p -S -5 2>/dev/null | tail -5)

    # Send text + Enter (using sendEnter for literal text handling)
    private.otmux.sendEnter "$target" "$text"

    # Wait for TUI to process
    sleep "$timeout"

    # Capture state AFTER send
    local after
    after=$($TMUX_CMD capture-pane -t "$target" -p -S -10 2>/dev/null | tail -10)

    # Verify: text should appear in pane OR pane state should have changed
    if [ "$before" = "$after" ]; then
        # Pane didn't change — likely blocked (permission dialog, overlay, etc.)
        error.log "send.verified FAILED: pane $target unchanged after send"
        RESULT="FAILED"
        return 1
    fi

    # Check if our text appears in the after capture
    if echo "$after" | grep -qF "$text"; then
        console.log "send.verified OK: text delivered to $target"
        RESULT="DELIVERED"
        return 0
    fi

    # Pane changed but text not visible — likely processed (agent consumed it)
    console.log "send.verified OK: pane $target changed (text likely processed)"
    RESULT="CHANGED"
    return 0
}
otmux.send.verified.completion.target() { private.complete.panes; }

private.otmux.sendEnter() # <target> <text> # send text followed by Enter; target=pane or direction (U/D/L/R)
{
  local target=$(private.resolve.target "$1")
  shift
  # Send text literally (-l) to avoid interpreting tmux key names in the message,
  # then send Enter separately with a brief delay. This prevents words like
  # "Escape" or "Up" from being treated as key sequences, and improves reliability
  # with TUI prompts (Claude Code accept-edits, permission dialogs).
  if [ -n "$*" ]; then
    $TMUX_CMD send-keys -t "$target" -l "$*"
    sleep 0.05
  fi
  $TMUX_CMD send-keys -t "$target" Enter
}

private.otmux.sendKeys() # <target> <key1> [<key2>...] # send keys with inter-key delays for TUI apps
{
  # Sends each argument as a separate key with a brief delay between them.
  # Use this for TUI interactions where keys must be processed sequentially
  # (e.g. Claude Code permission prompts: sendKeys <pane> Down Enter).
  local target=$(private.resolve.target "$1")
  shift
  for key in "$@"; do
    $TMUX_CMD send-keys -t "$target" "$key"
    sleep 0.05
  done
}
private.otmux.sendKeys.completion.target() {
  echo "U"
  echo "D"
  echo "L"
  echo "R"
  private.complete.panes
}

otmux.run() # <command> # run shell command
{
  $TMUX_CMD run-shell "$@"
}

otmux.display() # <message> # display a message
{
  $TMUX_CMD display-message "$@"
}

otmux.msg() # <message> # shorthand for display
{
  otmux.display "$@"
}

otmux.confirm() # <command> # confirm before running command
{
  $TMUX_CMD confirm-before "$@"
}

otmux.prompt() # <?template> # command prompt
{
  $TMUX_CMD command-prompt "$@"
}

otmux.menu() # # display menu
{
  $TMUX_CMD display-menu "$@"
}

# ─────────────────────────────────────────────────────────────────────────────
# COPY MODE COMMANDS
# ─────────────────────────────────────────────────────────────────────────────

otmux.copy() # # enter copy mode
{
  $TMUX_CMD copy-mode "$@"
}

otmux.clock() # # show clock
{
  $TMUX_CMD clock-mode "$@"
}

# ─────────────────────────────────────────────────────────────────────────────
# UTILITY COMMANDS
# ─────────────────────────────────────────────────────────────────────────────

otmux.wait() # <channel> # wait for a channel
{
  $TMUX_CMD wait-for "$@"
}

otmux.if() # <condition> <cmd1> <?cmd2> # conditional execution
{
  $TMUX_CMD if-shell "$@"
}

private.otmux.showMessages() # # show server messages
{
  $TMUX_CMD show-messages "$@"
}

otmux.commands() # # list all tmux commands
{
  $TMUX_CMD list-commands "$@"
}

otmux.lscm() # # shorthand for commands
{
  otmux.commands "$@"
}

# ─────────────────────────────────────────────────────────────────────────────
# GLOBAL FLAGS
# Note: UTF-8 mode (-u) is always enabled by default via TMUX_CMD
# ─────────────────────────────────────────────────────────────────────────────

otmux.256color() # <command> # force 256 color mode (stacks with UTF-8)
{
  tmux -u -2 "$@"
}

otmux.control() # <?command> # start in control mode (stacks with UTF-8)
{
  tmux -u -C "$@"
}

otmux.utf8() # <command> # force UTF-8 mode (already default, provided for compatibility)
{
  $TMUX_CMD "$@"
}

otmux.verbose() # <command> # enable verbose logging (stacks with UTF-8)
{
  tmux -u -v "$@"
}

otmux.socket() # <name> <command> # use specific socket name (stacks with UTF-8)
{
  local name="$1"
  shift
  tmux -u -L "$name" "$@"
}

private.otmux.socketPath() # <path> <command> # use specific socket path (stacks with UTF-8)
{
  local path="$1"
  shift
  tmux -u -S "$path" "$@"
}

otmux.config() # <file> <command> # use specific config file (stacks with UTF-8)
{
  local file="$1"
  shift
  tmux -u -f "$file" "$@"
}

# ─────────────────────────────────────────────────────────────────────────────
# STATUS & HELP
# ─────────────────────────────────────────────────────────────────────────────

otmux.version() # # show tmux version
{
  $TMUX_CMD -V
}

otmux.v() # # shorthand for version
{
  otmux.version
}

otmux.help() # # show tmux help
{
  $TMUX_CMD --help 2>&1 | head -50
  echo ""
  echo "For full documentation: man tmux"
}

otmux.tree() # # show formatted tree of all sessions, panes, titles and commands
{
  if ! $TMUX_CMD list-sessions >/dev/null 2>&1; then
    echo "No tmux server running. Use 'otmux new' to start."
    return 1
  fi

  # Collect session info: name, attached status, creation date
  local session_data
  session_data=$($TMUX_CMD list-sessions \
    -F "#{session_name}|#{session_attached}|#{session_created}" 2>/dev/null)

  if [ -z "$session_data" ]; then
    echo "No tmux sessions."
    return 0
  fi

  local session_count
  session_count=$(echo "$session_data" | wc -l | tr -d ' ')

  echo "tmux sessions"
  echo "│"

  local session_i=0

  echo "$session_data" | while IFS='|' read -r sess_name sess_attached sess_created; do
    session_i=$((session_i + 1))
    local is_last=0
    [ "$session_i" -eq "$session_count" ] && is_last=1

    # Format creation date (Mon DD or Mon D)
    local sess_date
    if date -r "$sess_created" "+%b %-d" >/dev/null 2>&1; then
      sess_date=$(date -r "$sess_created" "+%b %-d")
    else
      sess_date=$(date -d "@$sess_created" "+%b %-d" 2>/dev/null || echo "unknown")
    fi

    # Session connector
    local sess_connector="├──"
    local pane_prefix="│   "
    if [ "$is_last" -eq 1 ]; then
      sess_connector="└──"
      pane_prefix="    "
    fi

    # Session label: name (attached, date) or name (date)
    local sess_label="$sess_name"
    if [ "$sess_attached" -gt 0 ] 2>/dev/null; then
      sess_label="$sess_name (attached, $sess_date)"
    else
      sess_label="$sess_name ($sess_date)"
    fi

    echo "$sess_connector $sess_label"

    # Collect panes for this session (include PID for agent detection)
    local pane_data
    pane_data=$($TMUX_CMD list-panes -t "$sess_name" -s \
      -F "#{window_index}|#{pane_index}|#{pane_title}|#{pane_current_command}|#{pane_pid}" 2>/dev/null)

    local pane_count
    pane_count=$(echo "$pane_data" | wc -l | tr -d ' ')
    local pane_i=0

    echo "$pane_data" | while IFS='|' read -r win_idx pane_idx pane_title pane_cmd pane_pid; do
      pane_i=$((pane_i + 1))

      local address="${win_idx}.${pane_idx}"
      local title="${pane_title:--}"

      # Pane connector
      local pane_connector="├──"
      [ "$pane_i" -eq "$pane_count" ] && pane_connector="└──"

      # Print the pane line
      printf "%s%s %-5s %-24s [%s]\n" "$pane_prefix" "$pane_connector" "$address" "$title" "$pane_cmd"

      # Detect AI agent and show session info as sub-line
      local oosh_dir="${OOSH_DIR:-$(dirname "$0")}"
      local pane_target="${sess_name}:${win_idx}.${pane_idx}"
      local is_agent=0
      local agent_name="" agent_sid=""

      if [[ "$pane_cmd" =~ ^[0-9]+\.[0-9]+\.[0-9]+ ]] || [[ "$pane_cmd" == "claude" ]]; then
        is_agent=1
        agent_sid=$("$oosh_dir/claudeCode" session.id "$pane_target" 2>/dev/null)
        # Look up session name from sessions-index.json (customTitle or firstPrompt)
        [ -n "$agent_sid" ] && agent_name=$("$oosh_dir/claudeCode" session.name "$agent_sid" 2>/dev/null)
      elif [ "$pane_cmd" = "node" ] && echo "$pane_title" | grep -qi "cursor"; then
        is_agent=1
        agent_name="Cursor Agent"
      fi

      if [ "$is_agent" -eq 1 ]; then
        # Sub-line connector: continue vertical line or indent under last pane
        local sub_prefix="│     "
        [ "$pane_i" -eq "$pane_count" ] && sub_prefix="      "
        local sub_name="${agent_name:-(unnamed)}"
        if [ -n "$agent_sid" ]; then
          printf "%s%s└ %-26s [%s]\n" "$pane_prefix" "$sub_prefix" "$sub_name" "${agent_sid:0:8}"
        else
          printf "%s%s└ %s\n" "$pane_prefix" "$sub_prefix" "$sub_name"
        fi
      fi
    done

    echo "${pane_prefix}"
  done
}

otmux.status() # # show current tmux status (tree overview)
{
  otmux.tree
}

# ─────────────────────────────────────────────────────────────────────────────
# OBJECT.VERB ALIASES (tmux.object.verb style)
# ─────────────────────────────────────────────────────────────────────────────
# These provide an alternative naming convention: otmux.object.verb
# instead of otmux.verbObject, for those who prefer noun-first naming.

# --- SESSION ALIASES ---

otmux.session.new() # <?name> <?command> # create new session; name=session identifier
{
  otmux.new "$@"
}

otmux.session.attach() # <?target> # attach to session; target=session name or $id
{
  otmux.attach "$@"
}
otmux.session.attach.completion.target() { private.complete.sessions; }

otmux.session.detach() # # detach from current session
{
  otmux.detach "$@"
}

otmux.session.list() # # list all sessions
{
  otmux.sessions "$@"
}

otmux.session.has() # <target> # check if session exists; target=session name
{
  otmux.has "$@"
}
otmux.session.has.completion.target() { private.complete.sessions; }

otmux.session.kill() # <target> # kill session; target=session name to destroy
{
  otmux.kill "$@"
}
otmux.session.kill.completion.target() { private.complete.sessions; }

otmux.session.kill.all() # # kill all sessions except current
{
  private.otmux.killAll "$@"
}

otmux.session.rename() # <name> # rename current session; name=new session name
{
  otmux.rename "$@"
}

otmux.session.switch() # <target> # switch to session; target=session name or $id
{
  otmux.switch "$@"
}
otmux.session.switch.completion.target() { private.complete.sessions; }

otmux.session.last() # # switch to last active session
{
  otmux.last "$@"
}

otmux.session.next() # # switch to next session
{
  otmux.next "$@"
}

otmux.session.prev() # # switch to previous session
{
  otmux.prev "$@"
}

otmux.session.lock() # # lock current session
{
  otmux.lock "$@"
}

otmux.session.details() # <session> # show all windows and panes with titles, commands, and dimensions
{
  local session="$1"

  if [ -z "$session" ]; then
    error.log "usage: otmux session.details <session-name>"
    return 1
  fi

  if ! $TMUX_CMD has-session -t "$session" 2>/dev/null; then
    error.log "session not found: $session"
    return 1
  fi

  echo "Session: $session"
  echo "═══════════════════════════════════════════════════════════════════"

  local current_window=""

  $TMUX_CMD list-panes -t "$session" -s \
    -F "#{window_index}|#{window_name}|#{pane_index}|#{pane_title}|#{pane_current_command}|#{pane_width}|#{pane_height}|#{pane_active}" 2>/dev/null | \
    while IFS='|' read -r win_idx win_name pane_idx pane_title pane_cmd pane_w pane_h pane_active; do
      if [ "$win_idx" != "$current_window" ]; then
        [ -n "$current_window" ] && echo ""
        echo "  Window $win_idx: $win_name"
        echo "  ───────────────────────────────────────────────────────────────"
        printf "  %-30s %-16s %-12s %-10s %s\n" "Address" "Title" "Command" "Size" ""
        current_window="$win_idx"
      fi

      local address="${session}:${win_idx}.${pane_idx}"
      local size="${pane_w}x${pane_h}"
      local active_mark=""
      [ "$pane_active" = "1" ] && active_mark="(active)"

      printf "  %-30s %-16s %-12s %-10s %s\n" "$address" "${pane_title:--}" "$pane_cmd" "$size" "$active_mark"
    done

  echo ""
}
otmux.session.details.completion.session() { private.complete.sessions; }

# --- WINDOW ALIASES ---

otmux.window.new() # <?name> <?command> # create window; name=window title
{
  private.otmux.newWindow "$@"
}

otmux.window.list() # # list windows in current session
{
  otmux.windows "$@"
}

otmux.window.get() # <?format:#> # get current window target; format=# for index, @ for id, name for name
{
  local format="${1:-#}"
  case "$format" in
    \#)   $TMUX_CMD display-message -p "#{window_index}" ;;
    @)    $TMUX_CMD display-message -p "#{window_id}" ;;
    name) $TMUX_CMD display-message -p "#{window_name}" ;;
    *)    $TMUX_CMD display-message -p "$format" ;;
  esac
}

otmux.window.get.target() # # get current window in target format (session:window)
{
  $TMUX_CMD display-message -p "#{session_name}:#{window_index}"
}

otmux.window.select() # <target> # select window; target=index (0,1,2) or name
{
  private.otmux.selectWindow "$@"
}
otmux.window.select.completion.target() { private.complete.windows; }

otmux.window.next() # # go to next window
{
  private.otmux.nextWindow "$@"
}

otmux.window.prev() # # go to previous window
{
  private.otmux.prevWindow "$@"
}

otmux.window.last() # # go to last active window
{
  private.otmux.lastWindow "$@"
}

otmux.window.kill() # <?target> # kill window; target=[session:]window index/name
{
  private.otmux.killWindow "$@"
}
otmux.window.kill.completion.target() { private.complete.windows; }

otmux.window.rename() # <name> # rename current window; name=new window title
{
  private.otmux.renameWindow "$@"
}

otmux.window.move() # <target> # move window; target=destination [session:]index
{
  private.otmux.moveWindow "$@"
}
otmux.window.move.completion.target() { private.complete.windows; }

otmux.window.swap() # <target> # swap with window; target=[session:]window to swap with
{
  private.otmux.swapWindow "$@"
}
otmux.window.swap.completion.target() { private.complete.windows; }

otmux.window.link() # <src> <dst> # link window; src=source window, dst=target session
{
  private.otmux.linkWindow "$@"
}
otmux.window.link.completion.src() { private.complete.windows; }
otmux.window.link.completion.dst() { private.complete.sessions; }

otmux.window.unlink() # <?target> # unlink window; target=window to unlink
{
  private.otmux.unlinkWindow "$@"
}
otmux.window.unlink.completion.target() { private.complete.windows; }

otmux.window.find() # <pattern> # find window by pattern; pattern=search string
{
  private.otmux.findWindow "$@"
}

otmux.window.rotate() # # rotate panes within window
{
  private.otmux.rotateWindow "$@"
}

otmux.window.respawn() # <?command> # respawn window; command=shell command to run
{
  private.otmux.respawnWindow "$@"
}

# --- PANE ALIASES ---

otmux.pane.split() # <?command> # split pane horizontally; command=run in new pane
{
  otmux.split "$@"
}

otmux.pane.split.h() # <?command> # split horizontally (side-by-side)
{
  private.otmux.splitH "$@"
}

otmux.pane.split.v() # <?command> # split vertically (top-bottom)
{
  private.otmux.splitV "$@"
}

otmux.pane.list() # <?session> # list panes with addresses and titles; session=filter to session
{
  if [ -n "$1" ]; then
    $TMUX_CMD list-panes -t "$1" -s \
      -F "#{session_name}:#{window_index}.#{pane_index}  #{pane_title}  #{pane_current_command}" 2>/dev/null
  else
    otmux.panes "$@"
  fi
}
otmux.pane.list.completion.session() { private.complete.sessions; }

otmux.pane.get() # <?format:%> # get current pane target; format=% for pane_id, # for index
{
  local format="${1:-%}"
  case "$format" in
    %)  $TMUX_CMD display-message -p "#{pane_id}" ;;
    \#) $TMUX_CMD display-message -p "#{pane_index}" ;;
    *)  $TMUX_CMD display-message -p "$format" ;;
  esac
}

otmux.pane.get.target() # # get current pane in target format (session:window.pane)
{
  $TMUX_CMD display-message -p "#{session_name}:#{window_index}.#{pane_index}"
}

otmux.pane.select() # <target> # select pane; target=U/D/L/R direction or index (0,1,2)
{
  private.otmux.selectPane "$@"
}
otmux.pane.select.completion.target() {
  echo "U"
  echo "D"
  echo "L"
  echo "R"
  private.complete.panes
}

otmux.pane.up() # # select pane above
{
  otmux.up "$@"
}

otmux.pane.down() # # select pane below
{
  otmux.down "$@"
}

otmux.pane.left() # # select pane to the left
{
  otmux.left "$@"
}

otmux.pane.right() # # select pane to the right
{
  otmux.right "$@"
}

otmux.pane.last() # # select last active pane
{
  private.otmux.lastPane "$@"
}

otmux.pane.kill() # <?target> # kill pane; target=[session:][window.]pane index
{
  private.otmux.killPane "$@"
}
otmux.pane.kill.completion.target() { private.complete.panes; }

otmux.pane.break() # # break pane into new window
{
  private.otmux.breakPane "$@"
}

otmux.pane.join() # <target> # join pane to window; target=destination [session:]window
{
  private.otmux.joinPane "$@"
}
otmux.pane.join.completion.target() { private.complete.windows; }

otmux.pane.swap() # <target> # swap with pane; target=pane to swap with
{
  private.otmux.swapPane "$@"
}
otmux.pane.swap.completion.target() { private.complete.panes; }

otmux.pane.move() # <target> # move pane; target=destination window
{
  private.otmux.movePane "$@"
}
otmux.pane.move.completion.target() { private.complete.windows; }

otmux.pane.resize() # <direction> <?amount> # resize pane; direction=U/D/L/R, amount=cells (default 5)
{
  private.otmux.resizePane "$@"
}
otmux.pane.resize.completion.direction() {
  echo "U"
  echo "D"
  echo "L"
  echo "R"
}

otmux.pane.zoom() # # toggle pane zoom (fullscreen)
{
  otmux.zoom "$@"
}

otmux.pane.respawn() # <?command> # respawn pane; command=shell command to run
{
  private.otmux.respawnPane "$@"
}

otmux.pane.pipe() # <?command> # pipe pane output; command=receive piped output
{
  private.otmux.pipePane "$@"
}

otmux.pane.display() # # display pane numbers temporarily
{
  private.otmux.displayPanes "$@"
}

otmux.pane.capture() # <target> <?lines:20> # capture last N lines of visible pane output; target=session:window.pane
{
  local target=$(private.resolve.target "$1")
  local lines="${2:-20}"
  if [ -z "$target" ]; then
    error.log "usage: otmux pane.capture <target> <?lines>"
    return 1
  fi
  $TMUX_CMD capture-pane -t "$target" -p -S "-${lines}" 2>/dev/null | tail -"$lines"
}
otmux.pane.capture.completion.target() { private.complete.panes; }

otmux.pane.history.clear() # # clear pane scrollback history
{
  private.otmux.clearHistory "$@"
}

otmux.pane.title() # <target> <title> # set pane title; target=session:window.pane
{
  local target=$(private.resolve.target "$1")
  local title="$2"
  if [ -z "$title" ]; then
    error.log "usage: otmux pane.title <target> <title>"
    return 1
  fi
  $TMUX_CMD select-pane -t "$target" -T "$title"
}
otmux.pane.title.completion.target() { private.complete.panes; }

otmux.pane.send() # <target> <text> # send text + Enter to pane; target=session:window.pane
{
  private.otmux.sendEnter "$@"
}
otmux.pane.send.completion.target() { private.complete.panes; }

otmux.pane.lock() # <target> <title> # lock pane title; prevents Claude Code from overwriting
{
  local target=$(private.resolve.target "$1")
  local title="$2"
  if [ -z "$target" ] || [ -z "$title" ]; then
    error.log "usage: otmux pane.lock <target> <title>"
    return 1
  fi
  # Set the title
  $TMUX_CMD select-pane -t "$target" -T "$title"
  # Block escape-sequence-based renaming
  $TMUX_CMD set-option -p -t "$target" allow-rename off
  # Hook to re-enforce title on any change (catches tmux command-based renaming too)
  $TMUX_CMD set-hook -p -t "$target" pane-title-changed "select-pane -T \"$title\""
  info.log "Locked pane $target title to: $title"
}
otmux.pane.lock.completion.target() { private.complete.panes; }

otmux.pane.unlock() # <target> # unlock pane title; allows normal title changes
{
  local target=$(private.resolve.target "$1")
  if [ -z "$target" ]; then
    error.log "usage: otmux pane.unlock <target>"
    return 1
  fi
  # Remove the title enforcement hook
  $TMUX_CMD set-hook -up -t "$target" pane-title-changed
  # Re-enable escape-sequence renaming
  $TMUX_CMD set-option -up -t "$target" allow-rename
  info.log "Unlocked pane $target title"
}
otmux.pane.unlock.completion.target() { private.complete.panes; }

# --- LAYOUT ALIASES ---

otmux.layout.set() # <layout> # set layout; layout=even-horizontal/vertical/main-horizontal/vertical/tiled
{
  otmux.layout "$@"
}
otmux.layout.set.completion.layout() {
  echo "even-horizontal"
  echo "even-vertical"
  echo "main-horizontal"
  echo "main-vertical"
  echo "tiled"
}

otmux.layout.even.h() # # set even-horizontal layout (equal width columns)
{
  private.otmux.evenH "$@"
}

otmux.layout.even.v() # # set even-vertical layout (equal height rows)
{
  private.otmux.evenV "$@"
}

otmux.layout.main.h() # # set main-horizontal layout (large pane on top)
{
  private.otmux.mainH "$@"
}

otmux.layout.main.v() # # set main-vertical layout (large pane on left)
{
  private.otmux.mainV "$@"
}

otmux.layout.tiled() # # set tiled layout (grid arrangement)
{
  otmux.tiled "$@"
}

otmux.layout.next() # # cycle to next layout
{
  private.otmux.nextLayout "$@"
}

otmux.layout.prev() # # cycle to previous layout
{
  private.otmux.prevLayout "$@"
}

# --- BUFFER ALIASES ---

otmux.buffer.list() # # list all buffers
{
  otmux.buffers "$@"
}

otmux.buffer.show() # <?buffer> # show buffer contents; buffer=buffer name
{
  private.otmux.showBuffer "$@"
}
otmux.buffer.show.completion.buffer() { private.complete.buffers; }

otmux.buffer.set() # <data> # set buffer data; data=text to store
{
  private.otmux.setBuffer "$@"
}

otmux.buffer.load() # <file> # load buffer from file; file=path to read
{
  private.otmux.loadBuffer "$@"
}

otmux.buffer.save() # <file> # save buffer to file; file=path to write
{
  private.otmux.saveBuffer "$@"
}

otmux.buffer.delete() # <?buffer> # delete buffer; buffer=buffer name
{
  private.otmux.deleteBuffer "$@"
}
otmux.buffer.delete.completion.buffer() { private.complete.buffers; }

otmux.buffer.paste() # # paste buffer contents into pane
{
  private.otmux.pasteBuffer "$@"
}

otmux.buffer.choose() # # interactively choose buffer
{
  private.otmux.chooseBuffer "$@"
}

# --- CLIENT ALIASES ---

otmux.client.list() # # list connected clients
{
  otmux.clients "$@"
}

otmux.client.detach() # <?client> # detach client; client=client tty (e.g., /dev/pts/0)
{
  private.otmux.detachClient "$@"
}
otmux.client.detach.completion.client() { private.complete.clients; }

otmux.client.suspend() # # suspend current client (Ctrl+Z)
{
  private.otmux.suspendClient "$@"
}

otmux.client.refresh() # # refresh client display
{
  private.otmux.refreshClient "$@"
}

otmux.client.choose() # # interactively choose client
{
  private.otmux.chooseClient "$@"
}

otmux.client.choose.tree() # # interactively choose session/window tree
{
  private.otmux.chooseTree "$@"
}

otmux.client.lock() # # lock current client
{
  private.otmux.lockClient "$@"
}

# --- SERVER ALIASES ---

otmux.server.start() # # start tmux server
{
  private.otmux.startServer "$@"
}

otmux.server.kill() # # kill tmux server and all sessions
{
  private.otmux.killServer "$@"
}

otmux.server.lock() # # lock all clients
{
  private.otmux.lockServer "$@"
}

otmux.server.info() # # show server information
{
  otmux.info "$@"
}

# --- CONFIG ALIASES ---

otmux.config.source() # <?file> # source config file; file=path (default ~/.tmux.conf)
{
  otmux.source "$@"
}

otmux.config.set() # <option> <value> # set option; option=tmux option name
{
  otmux.set "$@"
}

otmux.config.set.global() # <option> <value> # set global option
{
  private.otmux.setGlobal "$@"
}

otmux.config.set.window() # <option> <value> # set window option
{
  private.otmux.setWindow "$@"
}

otmux.config.show() # <?option> # show options; option=specific option or all
{
  otmux.show "$@"
}

otmux.config.show.global() # <?option> # show global options
{
  private.otmux.showGlobal "$@"
}

otmux.config.show.window() # <?option> # show window options
{
  private.otmux.showWindow "$@"
}

otmux.config.show.hooks() # # show configured hooks
{
  private.otmux.showHooks "$@"
}

otmux.config.set.hook() # <hook> <command> # set hook; hook=event name, command=action
{
  private.otmux.setHook "$@"
}

# --- KEY ALIASES ---

otmux.key.bind() # <key> <command> # bind key; key=key sequence, command=tmux command
{
  otmux.bind "$@"
}

otmux.key.unbind() # <key> # unbind key; key=key sequence to remove
{
  otmux.unbind "$@"
}

otmux.key.list() # # list all key bindings
{
  otmux.keys "$@"
}

# --- ENV ALIASES ---

otmux.env.set() # <name> <value> # set environment variable; name=var name
{
  private.otmux.setEnv "$@"
}

otmux.env.show() # <?name> # show environment; name=specific var or all
{
  private.otmux.showEnv "$@"
}

# --- SEND ALIASES ---

otmux.send.keys() # <target> <keys> # send keys to pane; target=pane, keys=sequence (e.g., "ls -la" Enter)
{
  otmux.send "$@"
}

otmux.send.enter() # <target> <text> # send text + Enter; target=pane, text=command to execute
{
  private.otmux.sendEnter "$@"
}

otmux.send.tui() # <target> <key1> [<key2>...] # send keys with inter-key delays for TUI apps (Claude Code)
{
  private.otmux.sendKeys "$@"
}
otmux.send.tui.completion.target() {
  echo "U"
  echo "D"
  echo "L"
  echo "R"
  private.complete.panes
}

otmux.send.run() # <command> # run shell command in background
{
  otmux.run "$@"
}

otmux.send.display() # <message> # display message in status line
{
  otmux.display "$@"
}

otmux.send.confirm() # <command> # confirm before running; command=requires y/n
{
  otmux.confirm "$@"
}

otmux.send.prompt() # <?template> # show command prompt; template=prompt format
{
  otmux.prompt "$@"
}

otmux.send.menu() # # display interactive menu
{
  otmux.menu "$@"
}

# --- COPY ALIASES ---

otmux.copy.mode() # # enter copy mode for scrollback/selection
{
  otmux.copy "$@"
}

otmux.copy.clock() # # show clock in current pane
{
  otmux.clock "$@"
}

# ─────────────────────────────────────────────────────────────────────────────
# USAGE
# ─────────────────────────────────────────────────────────────────────────────

otmux.usage()
{
  local this=${0##*/}
  echo "You started"
  echo "$0

  otmux - tmux wrapper for oosh
  Makes tmux commands easy to remember!

  Two naming styles available:
    verbObject:    otmux killWindow dev:0
    object.verb:   otmux window.kill dev:0

  Usage:
  $this command     Description
  ─────────────────────────────────────────────────────
  SESSIONS:
      new <name>      create new session
      attach <sess>   attach to session (a)
      detach          detach from session (d)
      sessions        list sessions (ls)
      kill <sess>     kill a session
      rename <name>   rename session
      switch <sess>   switch to session
      last/next/prev  navigate sessions

  WINDOWS:
      newWindow <n>   create window (nw)
      windows         list windows (lsw)
      selectWindow    select window (sw)
      killWindow      kill window (kw)
      renameWindow    rename window (rw)
      nextWindow      next window
      prevWindow      previous window
      findWindow      find by pattern

  PANES:
      split           split horizontally
      splitH/splitV   split h/v explicitly
      panes           list panes (lsp)
      selectPane      select pane (sp)
      up/down/l/r     navigate panes
      killPane        kill pane (kp)
      zoom            toggle zoom (z)
      resizePane      resize pane (rp)
      breakPane       break to window
      joinPane        join to window
      displayPanes    show pane numbers (dp)

  LAYOUTS:
      layout <type>   set layout
      evenH/evenV     even layouts
      mainH/mainV     main layouts
      tiled           tiled layout
      nextLayout      cycle layouts

  BUFFERS:
      buffers         list buffers (lsb)
      paste           paste buffer
      chooseBuffer    choose buffer
      saveBuffer      save to file
      loadBuffer      load from file

  CONFIG:
      source <file>   source config
      set/setGlobal   set options
      show/showGlobal show options
      bind/unbind     key bindings
      keys            list bindings (lsk)

  UTILITY:
      send <keys>     send keys to pane
      run <cmd>       run shell command
      display <msg>   show message
      copy            enter copy mode
      clock           show clock
      status          show status
      v               show version
  ─────────────────────────────────────────────────────

  OBJECT.VERB STYLE (alternative):
      session.new/list/details/kill/switch/attach
      window.new/list/kill/select/move/swap
      pane.split/list/kill/select/resize/zoom/lock/unlock
      layout.set/evenH/evenV/mainH/mainV/tiled
      buffer.list/show/set/paste/delete
      client.list/detach/suspend/lock
      server.start/kill/info
      config.source/set/show
      key.bind/unbind/list
      send.keys/enter/run/display
  ─────────────────────────────────────────────────────

  Target formats:
    Session:  name or \$id (e.g., 'dev', '\$1')
    Window:   [session:]index/name (e.g., 'dev:0', '2')
    Pane:     [session:][window.]index (e.g., 'dev:0.1')

  Examples:
    $this new dev                 # new session 'dev'
    $this splitH                  # split horizontally
    $this send 'ls -la' Enter     # send command
    $this zoom                    # toggle pane zoom
    $this layout tiled            # tiled layout
    $this attach dev              # attach to 'dev'

    # object.verb style:
    $this session.new dev         # same as above
    $this pane.splitH             # split horizontally
    $this pane.zoom               # toggle zoom
    $this window.kill dev:0       # kill window 0 in dev
  "
}

otmux.start()
{
  #echo "sourcing init"
  source this

  if [ -z "$1" ]; then
    otmux.status
    return 0
  fi

  this.start "$@"
}

otmux.start "$@"
