#!/bin/zsh

# =============================================================================
# NAVIGATION UTILITIES
# =============================================================================

eval "$(zoxide init zsh)"

# Zoxide aliases with better names
zcd() { z "$@" }
zadd() { z "$@" }
zremove() { zoxide remove "$@" }

# Legacy aliases for backward compatibility
alias zi=zcd
alias za=zadd
alias zrm=zremove

# Open files with xdg-open (non-blocking)
function open {
  if [[ $# -eq 0 ]]; then
    echo "Usage: open <file1> [file2] ..."
    echo "Opens files using the system default application"
    return 1
  fi
  
  for i in "$@"; do
    if [[ ! -e "$i" ]]; then
      echo "Warning: '$i' does not exist" >&2
      continue
    fi
    setsid nohup xdg-open "$i" > /dev/null 2> /dev/null &
  done
}

# Find and open files with fzf
function fopen() {
  if ! command -v fd >/dev/null 2>&1; then
    echo "Error: fd is not installed" >&2
    return 1
  fi
  
  if ! command -v fzf >/dev/null 2>&1; then
    echo "Error: fzf is not installed" >&2
    return 1
  fi
  
  local selected
  selected=$(fd "$@" | fzf --preview 'bat --color=always --style=numbers --line-range=:500 {}')
  [[ -n "$selected" ]] && setsid nohup xdg-open "$selected" >/dev/null 2>&1 &
}

# =============================================================================
# DEVELOPMENT TOOLS
# =============================================================================

# Smart package manager detection and execution
function _package_manager {
  local pkg_manager=""
  
  # Detect package manager based on lock files
  if [[ -f bun.lockb ]]; then
    pkg_manager="bun"
  elif [[ -f pnpm-lock.yaml ]]; then
    pkg_manager="pnpm"
  elif [[ -f yarn.lock ]]; then
    pkg_manager="yarn"
  elif [[ -f package-lock.json ]]; then
    pkg_manager="npm"
  else
    pkg_manager="pnpm"  # Default fallback
  fi

  # Auto-detect npm scripts if command exists in package.json
  if [[ -f package.json ]] && [[ $1 != "run" ]] && [[ $1 != "install" ]] && [[ $1 != "add" ]] && [[ $1 != "remove" ]] && [[ $1 != "i" ]] && [[ $1 != "rm" ]]; then
    if command -v jq >/dev/null 2>&1 && jq -e ".scripts[\"$1\"] != null" package.json >/dev/null 2>&1; then
      set -- "run" "$@"
    fi
  fi

  # Execute with corepack if available, otherwise direct command
  if command -v corepack >/dev/null 2>&1; then
    corepack ${pkg_manager} "$@"
  else
    command ${pkg_manager} "$@"
  fi
}

# Quick development commit with auto-push
function dc() {
  # Show help if requested
  if [[ "$1" == "-h" || "$1" == "--help" ]]; then
    echo "Usage: dc [commit_message]"
    echo "Quickly commit all changes and push to remote"
    echo "If no message provided, uses timestamp-based message"
    return 0
  fi
  
  if ! git rev-parse --is-inside-work-tree &>/dev/null; then
    echo "Error: Not in a git repository" >&2
    return 1
  fi

  if [[ -z $(git status --porcelain) ]]; then
    echo "No changes to commit"
    return 0
  fi

  git add .

  local commit_msg
  if [[ -n "$1" ]]; then
    commit_msg="$1"
  else
    local timestamp=$(date +"%Y-%m-%d %H:%M:%S")
    commit_msg="dev: automated commit - ${timestamp}"
  fi

  # Commit with message and push
  if git commit -m "$commit_msg" --no-gpg-sign; then
    if git push &>/dev/null; then
      echo "Committed and pushed successfully"
    else
      echo "Warning: Commit successful but push failed" >&2
      return 1
    fi
  else
    echo "Commit failed" >&2
    return 1
  fi
}

# Clean up merged git branches
function git-clean() {
  # Show help if requested
  if [[ "$1" == "-h" || "$1" == "--help" ]]; then
    echo "Usage: git-clean"
    echo "Safely delete merged branches (both local and optionally remote)"
    echo "Protects main, master, and develop branches"
    return 0
  fi
  
  if ! git rev-parse --is-inside-work-tree &>/dev/null; then
    echo "Error: Not in a git repository" >&2
    return 1
  fi

  local current_branch=$(git rev-parse --abbrev-ref HEAD)
  local branches_to_delete=$(git branch --merged | grep -v "^\*" | grep -v "master" | grep -v "main" | grep -v "develop")

  if [[ -z "$branches_to_delete" ]]; then
    echo "No merged branches to clean up"
    return 0
  fi

  echo "The following merged branches will be deleted:"
  echo "$branches_to_delete"
  echo -n "Continue? [y/N] "
  read confirm

  if [[ "$confirm" =~ ^[Yy]$ ]]; then
    echo "$branches_to_delete" | xargs git branch -d
    echo "Branches deleted locally"

    echo -n "Delete remote branches too? [y/N] "
    read confirm_remote

    if [[ "$confirm_remote" =~ ^[Yy]$ ]]; then
      echo "$branches_to_delete" | xargs -I{} git push origin --delete {}
      echo "Remote branches deleted"
    fi
  else
    echo "Operation cancelled"
  fi
}

# Open Sublime Merge
function sm {
  if [[ ! -f /opt/sublime_merge/sublime_merge ]]; then
    echo "Error: Sublime Merge not found at /opt/sublime_merge/sublime_merge" >&2
    return 1
  fi
  /opt/sublime_merge/sublime_merge "$@"
}

# Quick access to Neovim config
function vimrc {
  if [[ -z "$XDG_CONFIG_HOME" ]]; then
    echo "Error: XDG_CONFIG_HOME not set" >&2
    return 1
  fi
  
  local original_dir=$(pwd)
  cd "$XDG_CONFIG_HOME/nvim" || {
    echo "Error: Cannot access $XDG_CONFIG_HOME/nvim" >&2
    return 1
  }
  nvim
  cd "$original_dir"
}

# Quick access to Zsh config
function zshrc {
  if [[ -z "$XDG_CONFIG_HOME" ]]; then
    echo "Error: XDG_CONFIG_HOME not set" >&2
    return 1
  fi
  
  local original_dir=$(pwd)
  cd "$XDG_CONFIG_HOME/zsh" || {
    echo "Error: Cannot access $XDG_CONFIG_HOME/zsh" >&2
    return 1
  }
  nvim
  cd "$original_dir"
}

# Expose local port through SSH tunnel
function expose() {
  # Show help if requested
  if [[ "$1" == "-h" || "$1" == "--help" ]]; then
    echo "Usage: expose <port>"
    echo "Create SSH tunnel to expose local port through remote server"
    echo "Example: expose 3000  # Exposes localhost:3000"
    return 0
  fi
  
  if [[ -z "$1" ]]; then
    echo "Error: Port number required" >&2
    echo "Usage: expose <port>" >&2
    return 1
  fi
  
  # Validate port number
  if ! [[ "$1" =~ ^[0-9]+$ ]] || [[ "$1" -lt 1 ]] || [[ "$1" -gt 65535 ]]; then
    echo "Error: Invalid port number. Must be between 1-65535" >&2
    return 1
  fi
  
  # Check if port is already in use
  if lsof -i ":$1" >/dev/null 2>&1; then
    echo "Warning: Port $1 is already in use" >&2
    echo "Current processes using port $1:"
    lsof -i ":$1"
    echo -n "Continue anyway? [y/N] "
    read confirm
    if [[ ! "$confirm" =~ ^[Yy]$ ]]; then
      echo "Operation cancelled"
      return 1
    fi
  fi
  
  echo "Creating SSH tunnel for port $1..."
  ssh marianozunino@srv.us -R 1:localhost:"$1"
}

# Find process using a specific port
function ppid {
  # Show help if requested
  if [[ "$1" == "-h" || "$1" == "--help" ]]; then
    echo "Usage: ppid <port>"
    echo "Find processes using the specified port"
    echo "Alias: pport"
    return 0
  fi
  
  if [[ -z "$1" ]]; then
    echo "Error: Port number required" >&2
    echo "Usage: ppid <port>" >&2
    return 1
  fi
  
  # Validate port number
  if ! [[ "$1" =~ ^[0-9]+$ ]] || [[ "$1" -lt 1 ]] || [[ "$1" -gt 65535 ]]; then
    echo "Error: Invalid port number. Must be between 1-65535" >&2
    return 1
  fi
  
  lsof -i ":$1"
}

# Alias for ppid function
alias pport="ppid"

# =============================================================================
# KUBERNETES AND DEVOPS
# =============================================================================

# Kubernetes port forwarding with kubefwd
function kf {
  # Show help if requested
  if [[ "$1" == "-h" || "$1" == "--help" ]]; then
    echo "Usage: kf <cluster> [service-name]"
    echo "Forward Kubernetes services using kubefwd"
    echo "Example: kf prod my-service"
    return 0
  fi
  
  if [[ -z "$1" ]]; then
    echo "Error: Cluster name required" >&2
    echo "Usage: kf <cluster> [service-name]" >&2
    return 1
  fi

  local namespace="oc-app"
  local cluster="oc-$1-eks-cluster"
  local svc_filter=""

  if [[ -n "$2" ]]; then
    svc_filter="-l app.kubernetes.io/instance=$2"
  fi

  if ! command -v kubefwd >/dev/null 2>&1; then
    echo "Error: kubefwd is not installed" >&2
    return 1
  fi
  
  echo "Starting kubefwd for cluster: $cluster"
  sudo -E kubefwd svc -n "${namespace}" -x "${cluster}" ${svc_filter}
}

# =============================================================================
# SYSTEM AND UTILITY FUNCTIONS
# =============================================================================

# Lazy-load handler for heavy tools
function _lazy_load() {
  local cmd="$1"
  local loader="$2"

  eval "${cmd}() {
    unfunction $cmd
    eval \"\$($loader)\"
    $cmd \"\$@\"
  }"
}

# Example: lazy load kubectl completion
_lazy_load kubectl "kubectl completion zsh"

# Configure Wacom tablet for current session
function wacom {
  # Show help if requested
  if [[ "$1" == "-h" || "$1" == "--help" ]]; then
    echo "Usage: wacom"
    echo "Configure Wacom tablet for current display session"
    echo "Supports both Wayland and X11 sessions"
    return 0
  fi
  
  if [[ "$XDG_SESSION_TYPE" = "wayland" ]]; then
    if ! command -v otd >/dev/null 2>&1; then
      echo "Error: opentabletdriver (otd) not found" >&2
      return 1
    fi
    
    systemctl --user enable opentabletdriver --now
    
    local config_file="$HOME/Sync/System/Configs/wacom/wacom.json"
    if [[ -f "$config_file" ]]; then
      otd loadsettings "$config_file"
      echo "Wacom configured for Wayland"
    else
      echo "Warning: Config file not found at $config_file" >&2
    fi
  else
    if ! command -v xsetwacom >/dev/null 2>&1; then
      echo "Error: xsetwacom not found" >&2
      return 1
    fi
    
    xsetwacom --set "Wacom One by Wacom S Pen stylus" ResetArea
    xsetwacom --set "Wacom One by Wacom S Pen stylus" MapToOutput DisplayPort-0
    xsetwacom --set "Wacom One by Wacom S Pen stylus" Rotate half

    xsetwacom --set "Wacom One by Wacom S Pen eraser" ResetArea
    xsetwacom --set "Wacom One by Wacom S Pen eraser" MapToOutput DisplayPort-0
    
    echo "Wacom configured for X11"
  fi
}

# Enhanced cat with bat, context-aware display
function cat {
  # Show help if requested
  if [[ "$1" == "-h" || "$1" == "--help" ]]; then
    echo "Usage: cat [file1] [file2] ..."
    echo "Enhanced cat using bat with syntax highlighting"
    echo "Automatically adjusts output for SSH sessions"
    return 0
  fi
  
  if ! command -v bat >/dev/null 2>&1; then
    echo "Warning: bat not found, falling back to system cat" >&2
    command cat "$@"
    return $?
  fi
  
  if [[ -n "$SSH_TTY" ]] || [[ -n "$SSH_CLIENT" ]] || [[ -n "$SSH_CONNECTION" ]]; then
    bat --plain --paging=never "$@"
  else
    bat "$@"
  fi
}

# Toggle display resolution and configuration
function toggle_resolution() {
  # Show help if requested
  if [[ "$1" == "-h" || "$1" == "--help" ]]; then
    echo "Usage: toggle_resolution [-m|--mirror]"
    echo "Toggle between different display resolutions and modes"
    echo "Options:"
    echo "  -m, --mirror    Force mirror mode"
    return 0
  fi
  
  local mirror_mode=false

  # Parse flags
  while [[ $# -gt 0 ]]; do
    case $1 in
      -m|--mirror)
        mirror_mode=true
        shift
        ;;
      *)
        shift
        ;;
    esac
  done

  # Check if swaymsg is available
  if ! command -v swaymsg >/dev/null 2>&1; then
    echo "Error: swaymsg not found. This function requires Sway window manager" >&2
    return 1
  fi
  
  # Check if jq is available
  if ! command -v jq >/dev/null 2>&1; then
    echo "Error: jq not found. Required for JSON parsing" >&2
    return 1
  fi

  # Get current state of internal monitor
  local current_state
  current_state=$(swaymsg -t get_outputs | jq -r '.[] | select(.name == "eDP-1") | "\(.current_mode.width)x\(.current_mode.height):\(.scale)"')

  # Detect connected external monitors
  local external_monitor=""
  if swaymsg -t get_outputs | jq -r '.[].name' | grep -q "DP-2"; then
    external_monitor="DP-2"
  elif swaymsg -t get_outputs | jq -r '.[].name' | grep -q "HDMI-A-1"; then
    external_monitor="HDMI-A-1"
  fi

  if [[ "$mirror_mode" == true ]] || [[ -n "$external_monitor" ]]; then
    echo "Switching to mirror mode (1920x1080)..."

    # Configure internal monitor to 1920x1080
    swaymsg output eDP-1 resolution 1920x1080@120Hz scale 1.0 pos 0 0

    # Configure external monitor if connected
    if [[ -n "$external_monitor" ]]; then
      swaymsg output "$external_monitor" resolution 1920x1080@60Hz pos 0 0
      echo "Mirror mode enabled: eDP-1 + $external_monitor at 1920x1080"
    else
      echo "Internal monitor configured to 1920x1080 (no external monitor detected)"
    fi

  elif [[ "$current_state" == "2880x1920:2.0" ]]; then
    echo "Switching to 1920x1080 (16:9)..."
    swaymsg output eDP-1 resolution 1920x1080@120Hz scale 1.0

    # Disable mirroring if external monitor is present
    if [[ -n "$external_monitor" ]]; then
      swaymsg output "$external_monitor" pos 1920 0
      echo "Extended mode: $external_monitor positioned to the right"
    fi

  else
    echo "Switching to 2880x1920 (3:2) native..."
    swaymsg output eDP-1 resolution 2880x1920@120Hz scale 2.0

    # Disable mirroring if external monitor is present
    if [[ -n "$external_monitor" ]]; then
      swaymsg output "$external_monitor" pos 1440 0
      echo "Extended mode: $external_monitor positioned to the right"
    fi
  fi

  # Show final state
  echo "Current configuration:"
  swaymsg -t get_outputs | jq -r '.[] | select(.active == true) | "  \(.name): \(.current_mode.width)x\(.current_mode.height)@\(.current_mode.refresh/1000)Hz scale:\(.scale) pos:(\(.rect.x),\(.rect.y))"'
}

# Launch Code::Blocks with high contrast theme
function cb {
  # Show help if requested
  if [[ "$1" == "-h" || "$1" == "--help" ]]; then
    echo "Usage: cb [codeblocks-args]"
    echo "Launch Code::Blocks with high contrast theme"
    return 0
  fi
  
  if [[ ! -f /usr/bin/codeblocks ]]; then
    echo "Error: Code::Blocks not found at /usr/bin/codeblocks" >&2
    return 1
  fi
  
  # Store original values
  local original_gtk_theme="$GTK_THEME"
  local original_gdk_theme="$GDK_THEME"
  local original_qt_style="$QT_STYLE_OVERRIDE"
  local original_xdg_desktop="$XDG_CURRENT_DESKTOP"
  
  # Set high contrast theme temporarily
  GTK_THEME=HighContrast \
  GDK_THEME=HighContrast \
  QT_STYLE_OVERRIDE=HighContrast \
  XDG_CURRENT_DESKTOP=GNOME \
  GTK2_RC_FILES="" \
  GTK_RC_FILES="" \
  /usr/bin/codeblocks "$@"
  
  # Restore original values
  export GTK_THEME="$original_gtk_theme"
  export GDK_THEME="$original_gdk_theme"
  export QT_STYLE_OVERRIDE="$original_qt_style"
  export XDG_CURRENT_DESKTOP="$original_xdg_desktop"
}


# Create a new git repository on remote server
function zrepo() {
  # Show help if requested
  if [[ "$1" == "-h" || "$1" == "--help" ]]; then
    echo "Usage: zrepo <repo-name>"
    echo "Create a new bare git repository on remote server"
    echo "Example: zrepo my-project"
    return 0
  fi
  
  if [[ -z "$1" ]]; then
    echo "Error: Repository name required" >&2
    echo "Usage: zrepo <repo-name>" >&2
    return 1
  fi
  
  # Validate repository name (basic check)
  if [[ ! "$1" =~ ^[a-zA-Z0-9_-]+$ ]]; then
    echo "Error: Repository name contains invalid characters" >&2
    echo "Use only letters, numbers, hyphens, and underscores" >&2
    return 1
  fi

  local REPO="$1"
  local SERVER="git@zvps"
  local PATH_ON_SERVER="/var/git/$REPO.git"

  echo "Creating repository '$REPO' on $SERVER..."
  
  ssh "$SERVER" "
    if [ -d $PATH_ON_SERVER ]; then
      echo 'Error: Repository '$REPO' already exists'
      exit 1
    fi
    mkdir -p $PATH_ON_SERVER &&
    git init --bare $PATH_ON_SERVER &&
    chown -R git:git $PATH_ON_SERVER &&
    chmod -R 755 $PATH_ON_SERVER
  " || {
    echo "Failed to create repository" >&2
    return 1
  }

      echo "Repository created on $SERVER:$PATH_ON_SERVER"

  if git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
    git remote add origin "$SERVER:$PATH_ON_SERVER"
    echo "Remote 'origin' added to your local repository"
  else
    echo "To clone this repository, run:"
    echo "  git clone $SERVER:$PATH_ON_SERVER"
  fi
}



# Check if a command exists
function _has {
  if [[ $# -eq 0 ]]; then
    echo "Usage: _has <command>" >&2
    return 1
  fi
  
  whence "$1" >/dev/null 2>&1
}

# History-based directory navigation with fzf
function cdr {
  # Show help if requested
  if [[ "$1" == "-h" || "$1" == "--help" ]]; then
    echo "Usage: cdr"
    echo "Navigate to recently visited directories using fzf"
    return 0
  fi
  
  if ! command -v fzf >/dev/null 2>&1; then
    echo "Error: fzf is not installed" >&2
    return 1
  fi
  
  local dir
  dir=$(dirs -pl | awk '!x[$0]++' | fzf --height 40% --reverse)
  [[ -n "$dir" ]] && cd "$dir"
}

# Fix swaymsg when running inside tmux
if [[ -v TMUX ]]; then
  function swaymsg {
    export SWAYSOCK=$XDG_RUNTIME_DIR/sway-ipc.$UID.$(pgrep -x sway).sock
    command swaymsg "$@"
  }
fi


# =============================================================================
# ALIASES
# =============================================================================

# Development aliases
alias dev='~/Dev/marianozunino/dev/dev'
alias p='_package_manager'
alias fo='fopen'
alias pport='ppid'

# Node.js cleanup alias
alias unChonk="echo 'Starting the great node_modules purge...' && find . -name 'node_modules' -type d -prune -exec sh -c 'echo \"Deleting {}\" && rm -rf \"{}\"' \;"

# Font management
alias fm='font-manager'
alias fml='font-manager list'
alias fms='font-manager status'
alias fmc='font-manager clean'
alias fma='font-manager all'

# Advanced font management function
function font-switch() {
    # Show help if requested
    if [[ "$1" == "-h" || "$1" == "--help" ]]; then
        echo "Usage: font-switch [font-name]"
        echo "Quickly switch between font sets"
        echo "Example: font-switch jetbrains-mono"
        return 0
    fi
    
    if [[ -z "$1" ]]; then
        echo "Available fonts:"
        font-manager list
        return 0
    fi
    
    local font_name="$1"
    
    # Check if font exists
    if ! font-manager list | grep -q "$font_name"; then
        echo "Error: Font '$font_name' not found" >&2
        echo "Available fonts:" >&2
        font-manager list >&2
        return 1
    fi
    
    echo "Switching to $font_name fonts..."
    font-manager clean
    font-manager extract "$font_name"
    
    # Reload terminal if in kitty
    if [[ "$TERM" == "xterm-kitty" ]] && command -v kitty >/dev/null 2>&1; then
        echo "Reloading kitty configuration..."
        kitty @ set-colors --all ~/.config/kitty/kitty.conf
    fi
    
    echo "Font switch complete!"
}

# Font preview function
function font-preview() {
    # Show help if requested
    if [[ "$1" == "-h" || "$1" == "--help" ]]; then
        echo "Usage: font-preview [font-name]"
        echo "Preview fonts in terminal"
        echo "Example: font-preview jetbrains-mono"
        return 0
    fi
    
    if [[ -z "$1" ]]; then
        echo "Error: Font name required" >&2
        echo "Usage: font-preview [font-name]" >&2
        return 1
    fi
    
    local font_name="$1"
    local preview_text="The quick brown fox jumps over the lazy dog
ABCDEFGHIJKLMNOPQRSTUVWXYZ
abcdefghijklmnopqrstuvwxyz
0123456789
!@#$%^&*()_+-=[]{}|;':\",./<>?"
    
    echo "Previewing font: $font_name"
    echo "----------------------------------------"
    echo "$preview_text" | font-manager extract "$font_name" && echo "$preview_text"
}



