#!/usr/bin/env bash

# Orchestra command history hook
#
# Source this file from your shell profile to log each executed command to a
# per-tmux-pane history file. The auto-rename pipeline can then use the
# captured history as the primary context for generating session names.
#
#   source /path/to/orchestrator/shell/orchestra-command-hook.sh
#
# On Bash we install a DEBUG pre-exec hook; on Zsh we install a preexec hook.
# This captures the last user command reliably before execution.

orchestra_rename_session() {
  local new_name="$*"
  if [[ -z "$new_name" ]]; then
    printf 'Usage: orchestra_rename_session <new name>\n' >&2
    return 1
  fi

  if [[ -z "${TMUX-}" ]] || ! command -v tmux >/dev/null 2>&1; then
    printf 'orchestra_rename_session must be run inside a tmux session\n' >&2
    return 1
  fi

  if [[ -z "${ORCHESTRA_BRIDGE_PATH-}" || ! -x "$ORCHESTRA_BRIDGE_PATH" ]]; then
    printf 'ORCHESTRA_BRIDGE_PATH is not set or executable\n' >&2
    return 1
  fi

  local session_name=""
  session_name="$(tmux display-message -p '#{session_name}' 2>/dev/null || echo "")"
  if [[ -z "$session_name" ]]; then
    printf 'Unable to determine current tmux session\n' >&2
    return 1
  fi

  local result=""
  result="$("$ORCHESTRA_BRIDGE_PATH" manual-rename-session "$session_name" "$new_name" 2>/dev/null || true)"
  case "$result" in
    '"success"')
      printf 'Renamed session to: %s\n' "$new_name"
      ;;
    '"invalid_name"')
      printf 'Invalid session name: %s\n' "$new_name" >&2
      return 1
      ;;
    '"session_not_found"')
      printf 'Current tmux session was not found\n' >&2
      return 1
      ;;
    '"tmux_not_available"')
      printf 'tmux is not available\n' >&2
      return 1
      ;;
    *)
      printf 'Failed to rename session\n' >&2
      return 1
      ;;
  esac
}

if [[ -n "${ORCHESTRA_PROMPT_HOOK_INSTALLED-}" ]]; then
  return 0 2>/dev/null || exit 0
fi

ORCHESTRA_HISTORY_DIR="${ORCHESTRA_HISTORY_DIR:-$HOME/.orchestra/history}"
ORCHESTRA_PROMPT_HOOK_INSTALLED=1

_ORCHESTRA_HOOK_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)"

_orchestra_history_key() {
  local key="$1"
  key="${key//\//_}"
  key=$(echo "$key" | tr '[:space:]' '_')
  key=$(echo "$key" | tr -c '[:alnum:]_-' '_')
  while [[ "$key" == *"__"* ]]; do
    key="${key//__/_}"
  done
  key="${key##_}"
  key="${key%%_}"
  echo "$key"
}

_orchestra_bridge_path() {
  local bridge=""

  if [[ -n "${GW_ORCHESTRATOR_ROOT-}" ]]; then
    bridge="$GW_ORCHESTRATOR_ROOT/gw-bridge.sh"
    if [[ -f "$bridge" ]]; then
      echo "$bridge"
      return
    fi
  fi

  bridge="$(cd "$_ORCHESTRA_HOOK_DIR/.." && pwd -P)/gw-bridge.sh"
  if [[ -f "$bridge" ]]; then
    echo "$bridge"
    return
  fi

  echo ""
}

_orchestra_should_auto_rename_session() {
  local session_name="$1"
  [[ -n "$session_name" && "$session_name" == *"__auto_"* ]]
}

_orchestra_should_trigger_auto_rename_command() {
  local command="$1"
  local app="$2"

  [[ -n "$command" ]] || return 1

  case "$app" in
    ""|cd|ls|pwd|clear|reset)
      return 1
      ;;
  esac

  return 0
}

_orchestra_auto_rename_flag_path() {
  local session_name="$1"
  local session_key
  session_key=$(_orchestra_history_key "$session_name")
  if [[ -z "$session_key" ]]; then
    return
  fi
  printf '%s/%s.rename_requested\n' "$ORCHESTRA_HISTORY_DIR" "$session_key"
}

_orchestra_auto_rename_delay_secs() {
  local delay="${ORCHESTRA_AUTO_RENAME_DELAY_SECS:-10}"
  if [[ ! "$delay" =~ ^[0-9]+([.][0-9]+)?$ ]]; then
    delay="10"
  fi
  printf '%s\n' "$delay"
}

_orchestra_trigger_auto_rename_async() {
  local session_name="$1"
  local command="$2"
  local app="$3"

  [[ -n "$session_name" ]] || return
  _orchestra_should_auto_rename_session "$session_name" || return
  _orchestra_should_trigger_auto_rename_command "$command" "$app" || return

  local bridge
  bridge="$(_orchestra_bridge_path)"
  [[ -n "$bridge" && -f "$bridge" ]] || return

  local flag_path
  flag_path="$(_orchestra_auto_rename_flag_path "$session_name")"
  [[ -n "$flag_path" ]] || return
  if [[ -f "$flag_path" ]]; then
    return
  fi

  local timestamp
  timestamp=$(date '+%Y-%m-%dT%H:%M:%S%z')
  printf '%s\n' "$timestamp" > "$flag_path"

  if command -v tmux >/dev/null 2>&1; then
    tmux set-option -q -t "$session_name" @orchestra_auto_rename_requested 1 >/dev/null 2>&1 || true
  fi

  local delay
  delay="$(_orchestra_auto_rename_delay_secs)"

  (
    sleep "$delay"
    command bash "$bridge" rename-session "$session_name" >/dev/null 2>&1 || true
  ) >/dev/null 2>&1 &
}

_orchestra_capture_command() {
  local cmd=""
  if [[ -n "${ZSH_VERSION-}" ]]; then
    # fc -ln -1 returns the most recent command without line numbers
    cmd="$(fc -ln -1 2>/dev/null)"
  else
    cmd="$(history 1 2>/dev/null)"
    cmd="${cmd#*[0-9] }"
  fi
  printf '%s' "$cmd"
}

_orchestra_normalize_app() {
  local cmd="$1"
  if [[ -n "${ZSH_VERSION-}" ]]; then
    setopt local_options ksharrays 2>/dev/null || true
  fi
  cmd="${cmd#"${cmd%%[![:space:]]*}"}"
  cmd="${cmd%"${cmd##*[![:space:]]}"}"
  if [[ -z "$cmd" ]]; then
    return
  fi

  local tokens=()
  if [[ -n "${ZSH_VERSION-}" ]]; then
    tokens=(${=cmd})
  else
    read -r -a tokens <<< "$cmd"
  fi
  if [[ ${#tokens[@]} -eq 0 ]]; then
    return
  fi

  local i=0
  while [[ $i -lt ${#tokens[@]} ]]; do
    local t="${tokens[$i]}"
    if [[ "$t" =~ ^[A-Za-z_][A-Za-z0-9_]*= ]]; then
      ((i++))
      continue
    fi
    case "$t" in
      sudo|env|command|nohup|time)
        ((i++))
        continue
        ;;
    esac
    break
  done

  if [[ $i -ge ${#tokens[@]} ]]; then
    return
  fi

  local base="${tokens[$i]}"
  base="${base##*/}"
  base="$(printf '%s' "$base" | tr '[:upper:]' '[:lower:]' | tr -c 'a-z0-9._:-' '_')"
  base="${base//__/_}"
  base="${base##_}"
  base="${base%%_}"

  case "$base" in
    python3|python3.*)
      base="python"
      ;;
    pip3|pip3.*)
      base="pip"
      ;;
    docker-compose|docker_compose)
      base="docker_compose"
      ;;
    nvim|nvim.app)
      base="nvim"
      ;;
  esac

  case "$base" in
    ""|bash|zsh|sh|fish|tmux|login|sudo|man|less|more|cat|tail|watch|source|export|set|alias|unalias|history|bindkey)
      return
      ;;
  esac

  printf '%s' "$base"
}

orchestra_log_command() {
  local command="${1-}"
  if [[ -z "$command" ]]; then
    command=$(_orchestra_capture_command)
  fi
  command="${command#"${command%%[![:space:]]*}"}"
  command="${command%"${command##*[![:space:]]}"}"
  if [[ -z "$command" ]]; then
    return
  fi

  case "$command" in
    orchestra_*|_orchestra_*)
      return
      ;;
  esac

  # Avoid logging duplicate consecutive commands within the same shell
  if [[ "$command" == "${ORCHESTRA_LAST_COMMAND-}" ]]; then
    return
  fi
  ORCHESTRA_LAST_COMMAND="$command"

  local pane_id=""
  local session_name=""
  if command -v tmux >/dev/null 2>&1 && [[ -n "${TMUX-}" ]]; then
    pane_id="${TMUX_PANE-}"
    if [[ -z "$pane_id" ]]; then
      pane_id="$(tmux display-message -p '#{pane_id}' 2>/dev/null || echo "")"
    fi
    session_name="$(tmux display-message -p '#{session_name}' 2>/dev/null || echo "")"
  fi
  session_name="${session_name:-shell}"

  local key
  if [[ -n "$pane_id" ]]; then
    key=$(_orchestra_history_key "$pane_id")
  else
    key=$(_orchestra_history_key "$session_name")
  fi
  if [[ -z "$key" ]]; then
    key="shell"
  fi

  mkdir -p "$ORCHESTRA_HISTORY_DIR"

  local timestamp
  timestamp=$(date '+%Y-%m-%dT%H:%M:%S%z')
  printf '%s\t%s\n' "$timestamp" "$command" >> "$ORCHESTRA_HISTORY_DIR/$key.log"

  local app
  app="$(_orchestra_normalize_app "$command")"
  if [[ -n "$app" ]]; then
    printf '%s\n' "$app" > "$ORCHESTRA_HISTORY_DIR/$key.last_app"
  fi
  printf '%s\n' "$command" > "$ORCHESTRA_HISTORY_DIR/$key.last_cmd"

  if [[ -n "$session_name" && "$session_name" != "shell" ]]; then
    _orchestra_trigger_auto_rename_async "$session_name" "$command" "$app" || true
  fi
}

_orchestra_install_hook_bash() {
  _orchestra_bash_preexec_hook() {
    if [[ "${ORCHESTRA_DEBUG_TRAP_ACTIVE-}" == "1" ]]; then
      return
    fi
    ORCHESTRA_DEBUG_TRAP_ACTIVE=1
    local cmd="${BASH_COMMAND-}"
    ORCHESTRA_DEBUG_TRAP_ACTIVE=0
    orchestra_log_command "$cmd"
  }

  local existing_debug
  existing_debug="$(trap -p DEBUG 2>/dev/null | sed -n "s/^trap -- '\(.*\)' DEBUG$/\1/p")"
  if [[ "$existing_debug" == *"_orchestra_bash_preexec_hook"* ]]; then
    return
  fi

  if [[ -n "$existing_debug" ]]; then
    trap "_orchestra_bash_preexec_hook; $existing_debug" DEBUG
  else
    trap '_orchestra_bash_preexec_hook' DEBUG
  fi
}

_orchestra_install_hook_zsh() {
  _orchestra_zsh_preexec_hook() {
    orchestra_log_command "$1"
  }

  if ! command -v add-zsh-hook >/dev/null 2>&1; then
    autoload -Uz add-zsh-hook 2>/dev/null || true
  fi
  if command -v add-zsh-hook >/dev/null 2>&1; then
    add-zsh-hook preexec _orchestra_zsh_preexec_hook
  else
    # Fallback: append to preexec_functions manually
    if [[ -z "${preexec_functions[(r)_orchestra_zsh_preexec_hook]}" ]]; then
      preexec_functions+=(_orchestra_zsh_preexec_hook)
    fi
  fi
}

_orchestra_install_hook() {
  case "$-" in
    *i*) ;;
    *)
      return
      ;;
  esac

  if [[ -n "${ZSH_VERSION-}" ]]; then
    _orchestra_install_hook_zsh
  else
    _orchestra_install_hook_bash
  fi
}

_orchestra_install_hook
