#!/usr/bin/env zsh

################################################################################
#                                                                              #
#   🔧 HELPER UTILITIES                                                        #
#   ----------------                                                           #
#   Core utility functions for package management and system operations.      #
#   UI/display functions have been moved to ui-kit.zsh for better separation. #
#                                                                              #
################################################################################

# Package management utilities

# Homebrew package caching system for performance optimization
_BREW_FORMULAE_CACHE=""
_BREW_CASKS_CACHE=""
_BREW_OUTDATED_CACHE=""

# Package queues for batch processing - properly reset after each batch
_NPM_PACKAGES_TO_INSTALL=()
_BREW_PACKAGES_TO_INSTALL=()
_CASK_PACKAGES_TO_INSTALL=()

function init_brew_cache() {
  if command -v brew >/dev/null 2>&1; then
    _BREW_FORMULAE_CACHE=$(brew list --formula 2>/dev/null || echo "")
    _BREW_CASKS_CACHE=$(brew list --cask 2>/dev/null || echo "")
    _BREW_OUTDATED_CACHE=$(brew outdated 2>/dev/null || echo "")
  fi
}

function refresh_brew_cache() {
  if command -v brew >/dev/null 2>&1; then
    _BREW_FORMULAE_CACHE=$(brew list --formula 2>/dev/null || echo "")
    _BREW_CASKS_CACHE=$(brew list --cask 2>/dev/null || echo "")
    _BREW_OUTDATED_CACHE=$(brew outdated 2>/dev/null || echo "")
  fi
}

function brew_tap() {
  if ! brew tap | grep "${@}" > /dev/null; then
    brew tap "${@}"
  fi
}

function brew_install() {
  local package="${@}"

  # Extract actual package name (remove tap prefix if present)
  local package_name
  if [[ "$package" == */* ]]; then
    package_name="${package##*/}"  # Get everything after the last slash
  else
    package_name="$package"
  fi

  # Check if already installed and up-to-date using cached lists
  if echo "$_BREW_FORMULAE_CACHE" | grep -q "^${package_name}$" && ! echo "$_BREW_OUTDATED_CACHE" | grep -q "^${package_name}"; then
    return 0
  fi

  # Add to batch installation array
  _BREW_PACKAGES_TO_INSTALL+=("${package}")
}

function brew_install_run() {
  # Use function-static array to avoid global state pollution
  local -a _LOCAL_BREW_PACKAGES=("${_BREW_PACKAGES_TO_INSTALL[@]}")
  # Clear global array immediately to prevent conflicts
  _BREW_PACKAGES_TO_INSTALL=()

  local start_time=$(date +%s.%N)
  ui_debug "brew_install_run: Starting with ${#_LOCAL_BREW_PACKAGES[@]} packages"

  if [[ ${#_LOCAL_BREW_PACKAGES[@]} -eq 0 ]]; then
    ui_debug "brew_install_run: No packages to install"
    return 0
  fi

  ui_info_simple "Installing ${#_LOCAL_BREW_PACKAGES[@]} formulae:"
  for package in "${_LOCAL_BREW_PACKAGES[@]}"; do
    echo "  • $package"
    ui_debug "brew_install_run: Will install $package"
  done
  ui_spacer

  ui_debug_command "brew install ${_LOCAL_BREW_PACKAGES[*]}"
  brew install "${_LOCAL_BREW_PACKAGES[@]}"

  ui_debug "brew_install_run: Refreshing cache"
  refresh_brew_cache
  ui_debug_timing "$start_time" "brew_install_run"
}

function brew_uninstall() {
  brew uninstall "${@}"
}

function cask_install() {
  local package="${@}"

  # Extract actual package name (remove tap prefix if present)
  local package_name
  if [[ "$package" == */* ]]; then
    package_name="${package##*/}"  # Get everything after the last slash
  else
    package_name="$package"
  fi

  # Check if already installed using cached list
  if echo "$_BREW_CASKS_CACHE" | grep -q "^${package_name}$"; then
    return 0
  fi

  # Add to batch installation array
  _CASK_PACKAGES_TO_INSTALL+=("${package}")
}

function cask_install_run() {
  # Use function-static array to avoid global state pollution
  local -a _LOCAL_CASK_PACKAGES=("${_CASK_PACKAGES_TO_INSTALL[@]}")
  # Clear global array immediately to prevent conflicts
  _CASK_PACKAGES_TO_INSTALL=()

  if [[ ${#_LOCAL_CASK_PACKAGES[@]} -eq 0 ]]; then
    return 0
  fi

  # Load UI functions if not already loaded
  if ! command -v ui_info_simple >/dev/null 2>&1; then
  fi

  ui_info_simple "Installing ${#_LOCAL_CASK_PACKAGES[@]} casks:"
  for package in "${_LOCAL_CASK_PACKAGES[@]}"; do
    echo "  • $package"
  done
  ui_spacer

  if ! brew install --cask "${_LOCAL_CASK_PACKAGES[@]}"; then
    ui_error_simple "Homebrew cask installation failed"
    ui_warning_simple "Please fix the conflict and run the script again"
    exit 1
  fi

  # Refresh cache
  refresh_brew_cache
}

function cask_uninstall() {
  brew uninstall --cask "${@}"
}

function gem_install() {
  if ! type "${@}" > /dev/null; then
    gem install "${@}"
  fi
}

function npm_install() {
  local package="${@}"

  # Add to batch installation array
  _NPM_PACKAGES_TO_INSTALL+=("${package}")
}

function npm_install_run() {
  # Use function-static array to avoid global state pollution
  local -a _LOCAL_NPM_PACKAGES=("${_NPM_PACKAGES_TO_INSTALL[@]}")
  # Clear global array immediately to prevent conflicts
  _NPM_PACKAGES_TO_INSTALL=()

  local start_time=$(date +%s.%N)
  ui_debug "npm_install_run: Starting with ${#_LOCAL_NPM_PACKAGES[@]} packages"

  if [[ ${#_LOCAL_NPM_PACKAGES[@]} -eq 0 ]]; then
    ui_debug "npm_install_run: No packages to install"
    return 0
  fi

  # Load UI functions if not already loaded
  if ! command -v ui_info_simple >/dev/null 2>&1; then
  fi

  # Get installed packages list once
  ui_debug "npm_install_run: Checking already installed packages"
  # Extract package names from the paths, preserving scoped packages
  local installed_packages=$(npm list -g --depth=0 --parseable 2>/dev/null | 
    sed 's|.*/node_modules/||' | 
    grep -v "^$" | 
    grep -v "^lib$" || echo "")
  ui_debug_vars installed_packages

  # Filter out already installed packages
  local packages_to_install=()
  ui_debug "npm_install_run: Filtering already installed packages"
  for package in "${_LOCAL_NPM_PACKAGES[@]}"; do
    # Extract package name without version (handle @scope/package@version format)
    local package_name="${package}"
    # Remove version if present (everything after the last @)
    if [[ "$package_name" == *"@"*"/"*"@"* ]]; then
      # Scoped package with version: @scope/package@version
      package_name="${package_name%@*}"
    elif [[ "$package_name" != *"/"* && "$package_name" == *"@"* ]]; then
      # Non-scoped package with version: package@version
      package_name="${package_name%@*}"
    fi
    
    if ! echo "$installed_packages" | grep -q "^${package_name}$"; then
      packages_to_install+=("$package")
      ui_debug "npm_install_run: Need to install $package"
    else
      ui_debug "npm_install_run: $package already installed, skipping"
    fi
  done

  # Skip if no packages need installation
  if [[ ${#packages_to_install[@]} -eq 0 ]]; then
    ui_info_simple "All npm packages already installed"
    ui_debug_timing "$start_time" "npm_install_run (no packages needed)"
    return 0
  fi

  ui_info_simple "Installing ${#packages_to_install[@]} npm packages:"
  for package in "${packages_to_install[@]}"; do
    echo "  • $package"
  done
  ui_spacer
  
  ui_debug_command "npm install -g ${packages_to_install[*]}"
  npm install -g "${packages_to_install[@]}"

  if [[ $? -ne 0 ]]; then
    ui_error_simple "npm installation failed"
    return 1
  fi

  ui_debug_timing "$start_time" "npm_install_run"
}

function pip_install() {
  local package="${@}"

  # Load UI functions if not already loaded
  if ! command -v ui_subtle >/dev/null 2>&1; then
  fi

  # Check if command exists
  if command -v "$package" >/dev/null 2>&1; then
    ui_subtle "✓ ${package} (already installed)"
    return 0
  fi

  # Use pip3 by default (most common nowadays)
  pip3 install --upgrade "$package"
}

function mas_install() {
  local package="${@}"


  # Install via Mac App Store
  mas install "$package"
}

# Path constants to reduce hard-coding
export CONFIG_DIR="$MY/config"
export PACKAGES_CONFIG_DIR="$CONFIG_DIR/packages"
export PROFILE_DIR="$MY/profiles/$OS_PROFILE"
export PROFILE_CONFIG_DIR="$PROFILE_DIR/config"
export PROFILE_PACKAGES_CONFIG_DIR="$PROFILE_CONFIG_DIR/packages"
export PROFILE_APPS_CONFIG_DIR="$PROFILE_CONFIG_DIR/apps"
export HOME_CONFIG_DIR="$HOME/.config"
export HOME_LIBRARY_APP_SUPPORT="$HOME/Library/Application Support"

# Generic command availability checker
ensure_command_available() {
  local command_name="$1"
  local install_hint="${2:-}"
  local exit_on_fail="${3:-true}"

  if ! command -v "$command_name" >/dev/null 2>&1; then
    # Load UI functions if not already loaded
    if ! command -v ui_error_simple >/dev/null 2>&1; then
    fi

    local error_msg="$command_name is not installed."
    if [[ -n "$install_hint" ]]; then
      error_msg="$error_msg $install_hint"
    fi

    if [[ "$exit_on_fail" == "true" ]]; then
      ui_error_simple "$error_msg"
      exit 1
    else
      ui_warning_simple "$error_msg"
      return 1
    fi
  fi
  return 0
}

# Help framework for consistent command help display
show_command_help() {
  local script_name="$1"
  local description="$2"
  local usage="$3"
  shift 3
  local commands=("$@")

  # Load UI functions if not already loaded
  if ! command -v ui_spacer >/dev/null 2>&1; then
  fi

  ui_spacer
  ui_highlight "$script_name - $description"
  ui_spacer
  ui_bold_text "USAGE:"
  echo "  $usage"
  ui_spacer 2

  if [[ ${#commands[@]} -gt 0 ]]; then
    ui_bold_text "COMMANDS:"
    for cmd_desc in "${commands[@]}"; do
      local cmd=$(echo "$cmd_desc" | cut -d: -f1)
      local desc=$(echo "$cmd_desc" | cut -d: -f2)
      printf "  %-12s %s\n" "$cmd" "$desc"
    done
    ui_spacer
  fi
}

# Automatic help flag handler
handle_help_flag() {
  if [[ "$1" == "--help" || "$1" == "-h" ]]; then
    ${2:-show_help}
    exit 0
  fi
}

# Merge app preferences from main and profile configs
merge_app_preferences() {
  local main_config="$1"
  local profile_config="$2"
  local yaml_key="${3:-preferences}"

  # Start with main config preferences
  local merged_prefs=$(yq eval ".${yaml_key}" "$main_config" -o json)

  # Merge with profile config if it exists
  if [[ -f "$profile_config" ]]; then
    local profile_prefs=$(yq eval ".${yaml_key}" "$profile_config" -o json 2>/dev/null || echo '{}')
    merged_prefs=$(echo "$merged_prefs $profile_prefs" | jq -s '.[0] * .[1]')
  fi

  echo "$merged_prefs"
}

