#!/usr/bin/env bash
# Shared helpers for brt

# shellcheck source=progress.sh
source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/progress.sh"

brt_info()  { echo -e "\033[36m●\033[0m $*"; }
brt_ok()    { echo -e "\033[32m✓\033[0m $*"; }
brt_warn()  { echo -e "\033[33m!\033[0m $*" >&2; }
brt_error() { echo -e "\033[31m✗\033[0m $*" >&2; }

# bash 3.2 + set -u treats empty ${arr[@]} as unbound — use these helpers
brt_arr_append() {
  local dest_name="$1"
  local src_name="$2"
  eval "local _src=(\"\${${src_name}[@]+${src_name}[@]}\")"
  ((${#_src[@]})) || return 0
  eval "${dest_name}+=(\"\${_src[@]}\")"
}

brt_arr_nonempty() {
  local name="$1"
  eval "local _n=\${#${name}[@]}"
  (( _n > 0 ))
}

brt_require() {
  local cmd="$1"
  if ! command -v "$cmd" &>/dev/null; then
    brt_error "'${cmd}' is required but not installed."
    exit 1
  fi
}

brt_random_token() {
  if command -v openssl &>/dev/null; then
    openssl rand -hex 24
  else
    head -c 32 /dev/urandom | xxd -p -c 64
  fi
}

brt_local_ips() {
  ifconfig 2>/dev/null | awk '/inet / && $2 != "127.0.0.1" { print $2 }' || \
  ip -4 addr show 2>/dev/null | awk '/inet / { split($2,a,"/"); print a[1] }' | grep -v '^127\.' || true
}

brt_get_public_ip() {
  local ip=""
  for url in "https://api.ipify.org" "https://ifconfig.me/ip" "https://icanhazip.com"; do
    ip=$(curl -fsSL --max-time 5 "$url" 2>/dev/null | tr -d '[:space:]') && [[ -n "$ip" ]] && break
  done
  echo "$ip"
}

brt_read_version() {
  local dir="${1:-}"
  local version=""

  if [[ -n "$dir" && -f "${dir}/version" ]]; then
    version=$(tr -d '[:space:]' < "${dir}/version")
  fi

  if [[ -z "$version" && -n "$dir" && -f "${dir}/brt" ]]; then
    version=$(grep '^BRT_VERSION=' "${dir}/brt" 2>/dev/null | head -1 | cut -d'"' -f2)
  fi

  echo "$version"
}

brt_os_is_windows() {
  [[ "${OS:-}" == "Windows_NT" ]] && return 0
  case "$(uname -s 2>/dev/null)" in
    MINGW*|MSYS*|CYGWIN*) return 0 ;;
  esac
  return 1
}

brt_install_hint_primary() {
  local base="${BRT_BASE_URL:-https://brt.sushii.dev}"
  if brt_os_is_windows; then
    echo "irm ${base}/win/install.ps1 | iex"
  else
    echo "curl -fsSL ${base}/install.sh | sh"
  fi
}

brt_install_hint_secondary() {
  local base="${BRT_BASE_URL:-https://brt.sushii.dev}"
  if brt_os_is_windows; then
    echo "macOS / Linux: curl -fsSL ${base}/install.sh | sh"
  else
    echo "Windows: irm ${base}/win/install.ps1 | iex"
  fi
}

brt_print_install_hints() {
  echo "Install: $(brt_install_hint_primary)"
  echo "$(brt_install_hint_secondary)"
  echo "  Remote access works across brt and brtwin."
}

brt_show_pending_update_notice() {
  local f="${HOME}/.brt/update-available"
  [[ -f "$f" ]] || return 0
  local msg
  msg=$(tr -d '\n' < "$f" 2>/dev/null || true)
  rm -f "$f"
  [[ -n "$msg" ]] || return 0
  brt_warn "brt update available: ${msg} (run: brt -update)"
}

brt_maybe_check_updates_async() {
  [[ "${BRT_AUTO_UPDATE:-1}" == "0" ]] && return 0
  local lib_dir
  lib_dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
  (
    # shellcheck source=/dev/null
    . "${lib_dir}/update.sh"
    brt_remove_startup_check_hook
    brt_update_check_startup
  ) >/dev/null 2>&1 &
  disown 2>/dev/null || true
}

brt_realpath() {
  local path="$1"
  local dir base

  while [[ -L "$path" ]]; do
    dir=$(cd "$(dirname "$path")" && pwd)
    base=$(readlink "$path")
    [[ "$base" != /* ]] && base="${dir}/${base}"
    path="$base"
  done

  dir=$(cd "$(dirname "$path")" && pwd)
  base=$(basename "$path")
  echo "${dir}/${base}"
}

brt_version_cmd() {
  local ver active active_real self_real
  ver=$(brt_read_version "$BRT_DIR")
  ver="${ver:-unknown}"
  echo "brt ${ver}"

  active=$(command -v brt 2>/dev/null || true)
  self_real=$(brt_realpath "${BRT_DIR}/brt" 2>/dev/null || echo "${BRT_DIR}/brt")
  if [[ -n "$active" ]]; then
    active_real=$(brt_realpath "$active" 2>/dev/null || echo "$active")
    if [[ "$active_real" != "$self_real" ]]; then
      brt_warn "PATH points to a different brt: ${active}"
      brt_info "This binary: ${self_real}"
    fi
  fi
}

brt_parse_ports() {
  # Outputs one port per line. Accepts: "80", "1-1024", "22,80,443", or empty for defaults.
  local spec="${1:-}"
  if [[ -z "$spec" ]]; then
    echo "21 22 23 25 53 80 110 111 135 139 143 443 445 993 995 1723 3306 3389 5900 8080 8443 8888 9000 9090" | tr ' ' '\n'
    return
  fi
  if [[ "$spec" == *-* ]]; then
    local start="${spec%-*}" end="${spec#*-}"
    seq "$start" "$end" 2>/dev/null
    return
  fi
  if [[ "$spec" == *,* ]]; then
    echo "$spec" | tr ',' '\n'
    return
  fi
  echo "$spec"
}

# Terminal media size in character cells (columns rows).
# Pass explicit width/height as $1/$2; 0 means auto-detect from terminal.
brt_term_media_size() {
  local req_width="${1:-0}"
  local req_height="${2:-0}"
  local cols rows width height

  cols=$(tput cols 2>/dev/null || true)
  rows=$(tput lines 2>/dev/null || true)
  cols=${cols:-${COLUMNS:-80}}
  rows=${rows:-${LINES:-24}}

  if (( req_width > 0 )); then
    width=$req_width
  else
    width=$cols
  fi

  if (( req_height > 0 )); then
    height=$req_height
  else
    height=$rows
  fi

  if (( width < 1 )); then width=1; fi
  if (( height < 1 )); then height=1; fi
  if (( width > cols )); then width=$cols; fi
  if (( height > rows )); then height=$rows; fi

  printf '%s %s\n' "$width" "$height"
}

# Largest cols x rows that fit video aspect within terminal cells.
# $1/$2 = video pixels, $3/$4 = max cols/rows, $5/$6 = cell pixel size.
brt_term_media_size_fit() {
  local vid_w="${1:-0}"
  local vid_h="${2:-0}"
  local max_cols="${3:-80}"
  local max_rows="${4:-24}"
  local cell_w="${5:-9}"
  local cell_h="${6:-18}"
  local cols rows

  if (( vid_w < 1 || vid_h < 1 || max_cols < 1 || max_rows < 1 )); then
    printf '%s %s\n' "$max_cols" "$max_rows"
    return 0
  fi

  cols=$max_cols
  rows=$(( cols * cell_w * vid_h / ( vid_w * cell_h ) ))
  (( rows < 1 )) && rows=1

  if (( rows > max_rows )); then
    rows=$max_rows
    cols=$(( rows * vid_w * cell_h / ( vid_h * cell_w ) ))
  fi

  (( cols > max_cols )) && cols=$max_cols
  (( cols < 1 )) && cols=1
  (( rows < 1 )) && rows=1

  printf '%s %s\n' "$cols" "$rows"
}

BRT_STATE_DIR="${HOME}/.brt"
BRT_CONFIG_FILE="${BRT_STATE_DIR}/.env"
BRT_LEGACY_CONFIG_FILE="${BRT_STATE_DIR}/config"

brt_config_write_template() {
  mkdir -p "$BRT_STATE_DIR"
  cat >"$BRT_CONFIG_FILE" <<'EOF'
# brt configuration — edit with: brt -config

# Browse search (https://serper.dev)
# BRT_SERPER_API_KEY=your-key-here

# Google Custom Search (optional)
# BRT_GOOGLE_API_KEY=
# BRT_GOOGLE_CX=

# Auto-update on terminal startup (1 = on, 0 = off)
# BRT_AUTO_UPDATE=1
EOF
}

brt_config_migrate_legacy() {
  local line key val
  [[ -f "$BRT_LEGACY_CONFIG_FILE" && ! -f "$BRT_CONFIG_FILE" ]] || return 0
  brt_config_write_template
  while IFS= read -r line || [[ -n "$line" ]]; do
    [[ "$line" =~ ^[[:space:]]*# ]] && continue
    if [[ "$line" =~ ^[[:space:]]*export[[:space:]]+([A-Za-z_][A-Za-z0-9_]*)=(.*)$ ]]; then
      key="${BASH_REMATCH[1]}"
      val="${BASH_REMATCH[2]}"
      val="${val%\"}"
      val="${val#\"}"
      val="${val%\'}"
      val="${val#\'}"
      [[ -n "$val" ]] || continue
      if grep -q "^[[:space:]]*#*[[:space:]]*${key}=" "$BRT_CONFIG_FILE" 2>/dev/null; then
        sed -i.bak "s|^[[:space:]]*#*[[:space:]]*${key}=.*|${key}=${val}|" "$BRT_CONFIG_FILE" 2>/dev/null || true
        rm -f "${BRT_CONFIG_FILE}.bak"
      else
        printf '%s=%s\n' "$key" "$val" >>"$BRT_CONFIG_FILE"
      fi
    fi
  done <"$BRT_LEGACY_CONFIG_FILE"
  mv "$BRT_LEGACY_CONFIG_FILE" "${BRT_LEGACY_CONFIG_FILE}.bak" 2>/dev/null || true
}

brt_ensure_config_file() {
  mkdir -p "$BRT_STATE_DIR"
  brt_config_migrate_legacy
  [[ -f "$BRT_CONFIG_FILE" ]] || brt_config_write_template
}

brt_env_unquote() {
  local val="$1"
  if [[ "$val" =~ ^\"(.*)\"$ ]]; then
    printf '%s' "${BASH_REMATCH[1]}"
  elif [[ "$val" =~ ^\'(.*)\'$ ]]; then
    printf '%s' "${BASH_REMATCH[1]}"
  else
    printf '%s' "$val"
  fi
}

brt_load_config() {
  brt_ensure_config_file
  local line key val
  while IFS= read -r line || [[ -n "$line" ]]; do
    line="${line#"${line%%[![:space:]]*}"}"
    [[ -z "$line" || "$line" == \#* ]] && continue
    if [[ "$line" =~ ^([A-Za-z_][A-Za-z0-9_]*)=(.*)$ ]]; then
      key="${BASH_REMATCH[1]}"
      val="$(brt_env_unquote "${BASH_REMATCH[2]}")"
      export "${key}=${val}"
    fi
  done <"$BRT_CONFIG_FILE"
}

brt_config_mask() {
  local value="$1"
  local len=${#value}
  if (( len == 0 )); then
    printf 'not set'
  elif (( len <= 4 )); then
    printf 'set (****)'
  else
    printf 'set (****%s)' "${value: -4}"
  fi
}

brt_config_show() {
  local serper google_key google_cx auto_update

  serper="${BRT_SERPER_API_KEY:-}"
  google_key="${BRT_GOOGLE_API_KEY:-}"
  google_cx="${BRT_GOOGLE_CX:-}"
  auto_update="${BRT_AUTO_UPDATE:-1}"

  brt_info "Config: ${BRT_CONFIG_FILE}"
  echo
  printf '  %-22s %s\n' "BRT_SERPER_API_KEY" "$(brt_config_mask "$serper")"
  printf '  %-22s %s\n' "BRT_GOOGLE_API_KEY" "$(brt_config_mask "$google_key")"
  printf '  %-22s %s\n' "BRT_GOOGLE_CX" "$(brt_config_mask "$google_cx")"
  if [[ -n "$auto_update" ]]; then
    printf '  %-22s %s\n' "BRT_AUTO_UPDATE" "$auto_update"
  else
    printf '  %-22s %s\n' "BRT_AUTO_UPDATE" "1 (default)"
  fi
}

brt_config() {
  local action="${1:-edit}"

  case "$action" in
    show|status)
      brt_load_config
      brt_config_show
      ;;
    path)
      brt_ensure_config_file
      echo "$BRT_CONFIG_FILE"
      ;;
    edit|"")
      brt_ensure_config_file
      if [[ ! -t 0 || ! -t 1 ]]; then
        brt_error "Config editor requires an interactive terminal"
        brt_info "Edit manually: ${BRT_CONFIG_FILE}"
        exit 1
      fi
      # shellcheck source=edit.sh
      source "${BRT_LIB}/edit.sh"
      BRT_EDITOR_FORCE=1 brt_edit "$BRT_CONFIG_FILE"
      brt_load_config
      brt_ok "Saved ${BRT_CONFIG_FILE}"
      brt_config_show
      ;;
    *)
      brt_error "Usage: brt -config [edit|show|path]"
      exit 1
      ;;
  esac
}
