#!/bin/sh

# Exit immediately if a command exits with a non-zero status.
set -e

# Get OS type
os_type=$(uname -s)

# --- Check for Required Commands ---
# Base commands required for all platforms
required_cmds="curl tar uname mkdir rm grep sed printf"

# Add platform-specific commands
case "$os_type" in
  MSYS*|MINGW*|CYGWIN*)
    required_cmds="$required_cmds unzip powershell.exe"
    ;;
  *)
    required_cmds="$required_cmds gzip"
    ;;
esac

# Perform the check
for cmd in $required_cmds; do
  if ! command -v "$cmd" >/dev/null 2>&1; then
    echo "Error: Required command '$cmd' not found in PATH." >&2
    exit 1
  fi
done

# --- Determine OS, Architecture, and Target Details ---

# Get architecture
arch=$(uname -m)
# Normalize arm64 to aarch64 for consistency with release naming
if [ "$arch" = "arm64" ]; then
  arch="aarch64"
fi

# Determine OS string, default home directory, and archive extension
case "$os_type" in
  Linux*)
    os_kernel="linux"
    os_libc="gnu"
    archive_ext="tar.gz"

    # --- Libc Detection ---
    # Method 1: Try using ldd on /bin/sh (if ldd exists)
    if command -v ldd >/dev/null 2>&1; then
      if ldd /bin/sh 2>/dev/null | grep -q 'musl'; then
        os_libc="musl"
      fi
    fi

    # Method 2: If still 'gnu', try checking for common musl linker file existence
    # This serves as a fallback or primary method if ldd isn't present/conclusive.
    if [ "$os_libc" = "gnu" ]; then
      # Use shell's path expansion to check common locations
      # Loop through potential matches. If a file exists, the loop runs.
      for potential_musl_linker in /lib/ld-musl-*.so.? /usr/lib/ld-musl-*.so.?; do
        # Check if the glob pattern actually expanded to an existing file
        if [ -e "$potential_musl_linker" ]; then
          os_libc="musl"
          break 
        fi
      done
    fi

    # Construct the os_slug based on detected kernel and libc
    os_slug="unknown-$os_kernel-$os_libc"
    if [ -z "$INTELLI_HOME" ]; then
      # Use XDG_DATA_HOME if set, otherwise default to ~/.local/share
      INTELLI_HOME="${XDG_DATA_HOME:-$HOME/.local/share}/intelli-shell"
    fi
    ;;

  Darwin*)
    os_slug="apple-darwin"
    archive_ext="tar.gz"
    if [ -z "$INTELLI_HOME" ]; then
      INTELLI_HOME="$HOME/Library/Application Support/org.IntelliShell.Intelli-Shell"
    fi
    ;;

  MSYS*|MINGW*|CYGWIN*)
    os_slug="pc-windows-msvc"
    archive_ext="zip"
    if [ -z "$INTELLI_HOME" ]; then
      if [ -n "$APPDATA" ]; then
        # Convert Windows %APPDATA% path to a POSIX-like path for use in sh
        POSIX_APPDATA=$(echo "/$APPDATA" | sed 's/\\/\//g' | sed 's/://')
        INTELLI_HOME="$POSIX_APPDATA/IntelliShell/Intelli-Shell/data"
      else
        echo "Error: Cannot determine default install location on Windows." >&2
        echo "Reason: Neither INTELLI_HOME nor APPDATA environment variables are set." >&2
        echo "Please set the INTELLI_HOME variable to your desired installation path before running the script." >&2
        exit 1
      fi
    fi
    # Convert the POSIX-style path in INTELLI_HOME to a native Windows path (e.g., C:\Users\...)
    # This is needed for shells like PowerShell and Nushell that run natively on Windows
    drive_letter=$(echo "$INTELLI_HOME" | sed -n 's,^/\(.\)/.*,\1,p')
    drive_letter_upper=$(echo "$drive_letter" | tr 'a-z' 'A-Z')
    path_without_drive=$(echo "$INTELLI_HOME" | sed 's,^/./,,')
    path_win_slashes=$(echo "$path_without_drive" | sed 's|/|\\|g')
    INTELLI_HOME_WIN="$drive_letter_upper:\\$path_win_slashes"
    ;;

  *)
    echo "Error: OS type not supported: $os_type" >&2
    exit 1
    ;;
esac

# Construct the final target string and artifact filename
target="$arch-$os_slug"
artifact_filename="intelli-shell-$target.$archive_ext"

# --- Download and Extract Latest Release ---

# Ensure the target directory exists
mkdir -p "$INTELLI_HOME/bin"

# Determine the version to install
target_version=""
if [ -n "$1" ]; then
  target_version="$1"
elif [ -n "$INTELLI_VERSION" ]; then
  target_version="$INTELLI_VERSION"
fi

# Determine the release path part of the URL based on the version
if [ -n "$target_version" ]; then
  # If a version is provided, use it
  VERSION_TAG=$(echo "$target_version" | sed 's/^v//')
  RELEASE_PATH="releases/download/v$VERSION_TAG"
  echo "Downloading IntelliShell v$VERSION_TAG ($artifact_filename) ..."
else
  # Otherwise, download the latest release
  RELEASE_PATH="releases/latest/download"
  echo "No version specified, installing the latest release."
fi

# Define the download URL and a temporary file path
DOWNLOAD_URL="https://github.com/lasantosr/intelli-shell/$RELEASE_PATH/$artifact_filename"
TMP_ARCHIVE="$INTELLI_HOME/$artifact_filename.tmp"

if ! curl -Lsf "$DOWNLOAD_URL" -o "$TMP_ARCHIVE"; then
  echo "Error: Download failed from $DOWNLOAD_URL" >&2
  rm -f "$TMP_ARCHIVE"
  exit 1
fi

echo "Extracting ..."
if [ "$archive_ext" = "zip" ]; then
  # Use unzip for Windows zip files
  if ! unzip -oq "$TMP_ARCHIVE" -d "$INTELLI_HOME/bin"; then
    echo "Error: Extraction failed for $TMP_ARCHIVE using unzip" >&2
    rm -f "$TMP_ARCHIVE"
    exit 1
  fi
else
  # Use tar for tar.gz files
  if ! tar zxf "$TMP_ARCHIVE" -C "$INTELLI_HOME/bin"; then
    echo "Error: Extraction failed for $TMP_ARCHIVE using tar" >&2
    rm -f "$TMP_ARCHIVE"
    exit 1
  fi
fi

# Clean up the temporary archive
rm -f "$TMP_ARCHIVE"

# Ensure the main binary is executable
if [ -f "$INTELLI_HOME/bin/intelli-shell" ]; then
  chmod +x "$INTELLI_HOME/bin/intelli-shell"
fi

echo "Successfully installed IntelliShell at: $INTELLI_HOME"

# --- Update Shell Profiles (Optional) ---

if [ "${INTELLI_SKIP_PROFILE:-0}" = "0" ]; then

  # Use strings to keep track of modified and skipped files
  updated_files=""
  skipped_files=""

  # Function to add IntelliShell config to a given profile file if not already present
  update_rc() {
    profile_file="$1"
    shell_type="$2" # 'bash', 'zsh', 'fish', 'nushell' or 'powershell'

    # Check if the file's parent directory exists, and create it if not
    profile_dir=$(dirname "$profile_file")
    if [ ! -d "$profile_dir" ]; then
      mkdir -p "$profile_dir"
    fi
    # Create the file if it doesn't exist
    if [ ! -f "$profile_file" ]; then
      touch "$profile_file"
    fi

    # Check if IntelliShell is already mentioned
    is_sourced=""
    if [ -f "$profile_file" ] && grep -q 'intelli-shell' "$profile_file"; then
      is_sourced="yes"
    fi

    # If not already sourced, add the necessary lines
    if [ -z "$is_sourced" ]; then
      updated_files=$(printf '%s\n%s' "$updated_files" "$profile_file")

      if [ "$shell_type" = "fish" ]; then
        printf '\n# IntelliShell\n' >> "$profile_file"
        printf 'set -gx INTELLI_HOME "%s"\n' "$INTELLI_HOME" >> "$profile_file"
        printf '# set -gx INTELLI_SEARCH_HOTKEY ctrl-space\n' >> "$profile_file"
        printf '# set -gx INTELLI_VARIABLE_HOTKEY ctrl-l\n' >> "$profile_file"
        printf '# set -gx INTELLI_BOOKMARK_HOTKEY ctrl-b\n' >> "$profile_file"
        printf '# set -gx INTELLI_FIX_HOTKEY ctrl-x\n' >> "$profile_file"
        printf '# set -gx INTELLI_SKIP_ESC_BIND 0\n' >> "$profile_file"
        printf '# alias is="intelli-shell"\n' >> "$profile_file"
        printf 'fish_add_path "$INTELLI_HOME/bin"\n' >> "$profile_file"
        printf 'intelli-shell init fish | source\n' >> "$profile_file"
      elif [ "$shell_type" = "nushell" ]; then
        printf '\n# IntelliShell\n' >> "$profile_file"
        case "$os_type" in
          MSYS*|MINGW*|CYGWIN*)
            printf "\$env.INTELLI_HOME = '%s'\n" "$INTELLI_HOME_WIN" >> "$profile_file"
            ;;
          *)
            printf '$env.INTELLI_HOME = "%s"\n' "$INTELLI_HOME" >> "$profile_file"
            printf '$env.PATH = ($env.PATH | prepend "%s/bin")\n' "$INTELLI_HOME" >> "$profile_file"
            ;;
        esac
        printf '# $env.INTELLI_SEARCH_HOTKEY = "control space"\n' >> "$profile_file"
        printf '# $env.INTELLI_VARIABLE_HOTKEY = "control char_l"\n' >> "$profile_file"
        printf '# $env.INTELLI_BOOKMARK_HOTKEY = "control char_b"\n' >> "$profile_file"
        printf '# $env.INTELLI_FIX_HOTKEY = "control char_x"\n' >> "$profile_file"
        printf '# alias is = intelli-shell\n' >> "$profile_file"
        printf 'mkdir ($nu.data-dir | path join "vendor/autoload")\n' >> "$profile_file"
        printf 'intelli-shell init nushell | save -f ($nu.data-dir | path join "vendor/autoload/intelli-shell.nu")\n' >> "$profile_file"
      elif [ "$shell_type" = "powershell" ]; then
        case "$os_type" in
          MSYS*|MINGW*|CYGWIN*)
            printf '\r\n# IntelliShell\r\n' >> "$profile_file"
            printf '$env:INTELLI_HOME = "%s"\r\n' "$INTELLI_HOME_WIN" >> "$profile_file"
            printf '# $env:INTELLI_SEARCH_HOTKEY = "Ctrl+Spacebar"\r\n' >> "$profile_file"
            printf '# $env:INTELLI_VARIABLE_HOTKEY = "Ctrl+l"\r\n' >> "$profile_file"
            printf '# $env:INTELLI_BOOKMARK_HOTKEY = "Ctrl+b"\r\n' >> "$profile_file"
            printf '# $env:INTELLI_FIX_HOTKEY = "Ctrl+x"\r\n' >> "$profile_file"
            printf '# Set-Alias -Name "is" -Value "intelli-shell"\r\n' >> "$profile_file"
            printf 'intelli-shell.exe init powershell | Out-String | Invoke-Expression\r\n' >> "$profile_file"
            ;;
          *)
            printf '\n# IntelliShell\n' >> "$profile_file"
            printf '$env:INTELLI_HOME = "%s"\n' "$INTELLI_HOME" >> "$profile_file"
            printf '$env:PATH = "%s/bin:" + $env:PATH\n' "$INTELLI_HOME" >> "$profile_file"
            printf '# $env:INTELLI_SEARCH_HOTKEY = "Ctrl+Spacebar"\n' >> "$profile_file"
            printf '# $env:INTELLI_VARIABLE_HOTKEY = "Ctrl+l"\n' >> "$profile_file"
            printf '# $env:INTELLI_BOOKMARK_HOTKEY = "Ctrl+b"\n' >> "$profile_file"
            printf '# $env:INTELLI_FIX_HOTKEY = "Ctrl+x"\n' >> "$profile_file"
            printf '# Set-Alias -Name "is" -Value "intelli-shell"\n' >> "$profile_file"
            printf 'intelli-shell init powershell | Out-String | Invoke-Expression\n' >> "$profile_file"
            ;;
        esac
      elif [ "$shell_type" = "zsh" ]; then
        printf '\n# IntelliShell\n' >> "$profile_file"
        printf 'export INTELLI_HOME="%s"\n' "$INTELLI_HOME" >> "$profile_file"
        printf "# export INTELLI_SEARCH_HOTKEY='^@'\n" >> "$profile_file"
        printf "# export INTELLI_VARIABLE_HOTKEY='^l'\n" >> "$profile_file"
        printf "# export INTELLI_BOOKMARK_HOTKEY='^b'\n" >> "$profile_file"
        printf "# export INTELLI_FIX_HOTKEY='^x'\n" >> "$profile_file"
        printf '# export INTELLI_SKIP_ESC_BIND=0\n' >> "$profile_file"
        printf '# alias is="intelli-shell"\n' >> "$profile_file"
        printf 'export PATH="$INTELLI_HOME/bin:$PATH"\n' >> "$profile_file"
        printf 'eval "$(intelli-shell init zsh)"\n' >> "$profile_file"
      else # bash
        printf '\n# IntelliShell\n' >> "$profile_file"
        printf 'export INTELLI_HOME="%s"\n' "$INTELLI_HOME" >> "$profile_file"
        printf '# export INTELLI_SEARCH_HOTKEY=\\\\C-@\n' >> "$profile_file"
        printf '# export INTELLI_VARIABLE_HOTKEY=\\\\C-l\n' >> "$profile_file"
        printf '# export INTELLI_BOOKMARK_HOTKEY=\\\\C-b\n' >> "$profile_file"
        printf '# export INTELLI_FIX_HOTKEY=\\\\C-x\n' >> "$profile_file"
        printf '# export INTELLI_SKIP_ESC_BIND=0\n' >> "$profile_file"
        printf '# alias is="intelli-shell"\n' >> "$profile_file"
        printf 'export PATH="$INTELLI_HOME/bin:$PATH"\n' >> "$profile_file"
        printf 'eval "$(intelli-shell init %s)"\n' "$shell_type" >> "$profile_file"
      fi
    else
      # If the file is already configured, add it to the skipped list
      skipped_files=$(printf '%s\n%s' "$skipped_files" "$profile_file")
    fi
  }

  # Check for PowerShell Profile (Windows-only)
  case "$os_type" in
    MSYS*|MINGW*|CYGWIN*)
      # Convert the POSIX path in INTELLI_HOME to a native Windows path (e.g., C:\Users\...)
      drive_letter=$(echo "$INTELLI_HOME" | sed -n 's,^/\(.\)/.*,\1,p')
      drive_letter_upper=$(echo "$drive_letter" | tr 'a-z' 'A-Z')
      path_without_drive=$(echo "$INTELLI_HOME" | sed 's,^/./,,')
      path_win_slashes=$(echo "$path_without_drive" | sed 's|/|\\|g')
      INTELLI_HOME_WIN="$drive_letter_upper:\\$path_win_slashes"
      pwsh_command=$(printf '
        $binPath = "%s\\bin";
        $currentUserPath = [System.Environment]::GetEnvironmentVariable("PATH", [System.EnvironmentVariableTarget]::User)
        $pathItems = $currentUserPath -split [System.IO.Path]::PathSeparator
        if ($binPath -notin $pathItems) {
          $newPath = ($pathItems + $binPath) -join [System.IO.Path]::PathSeparator
          [System.Environment]::SetEnvironmentVariable("PATH", $newPath, [System.EnvironmentVariableTarget]::User)
        }
      ' "$INTELLI_HOME_WIN")
      if ! powershell.exe -NoProfile -ExecutionPolicy Bypass -Command "$pwsh_command"; then
        echo "Warning: You may need to add $INTELLI_HOME_WIN\bin to your Windows PATH manually" >&2
      fi
      pwsh_profile_win_path=$(powershell.exe -NoProfile -Command '$PROFILE.CurrentUserCurrentHost')
      if [ -n "$pwsh_profile_win_path" ]; then
        # Convert Windows path (C:\Users\...) to a POSIX path (/c/Users/...) that sh can use
        pwsh_profile_posix_path=$(echo "$pwsh_profile_win_path" | sed -e 's|\\|/|g' -e 's|^ *\([A-Za-z]\):|/\L\1|' | tr -d '\r')
        update_rc "$pwsh_profile_posix_path" "powershell"
      else
        echo "Warning: Could not determine PowerShell profile path"
      fi
      ;;
  esac
  # Check for .bash_profile or default to .bashrc
  if [ -f "$HOME/.bash_profile" ]; then
    update_rc "$HOME/.bash_profile" "bash"
  else
    update_rc "$HOME/.bashrc" "bash"
  fi
  # Check if zsh likely exists before updating .zshrc
  if command -v zsh >/dev/null 2>&1; then
    update_rc "$HOME/.zshrc" "zsh"
  fi
  # Check if fish likely exists before updating fish config
  if command -v fish >/dev/null 2>&1; then
    update_rc "$HOME/.config/fish/config.fish" "fish"
  fi
  # Check if nu likely exists before updating nu config
  if command -v nu >/dev/null 2>&1; then
    # Query nushell for its config file path to be robust across versions and platforms
    nu_config_path_native=$(nu -c '$nu.config-path' 2>/dev/null | tr -d '\r')
    if [ -n "$nu_config_path_native" ]; then
      nu_config_path_posix="$nu_config_path_native"
      # If on Windows, convert the native path (C:\...) to a POSIX path (/c/...) for the sh script to use
      case "$os_type" in
        MSYS*|MINGW*|CYGWIN*)
          nu_config_path_posix=$(echo "$nu_config_path_native" | sed -e 's|\\|/|g' -e 's|^ *\([A-Za-z]\):|/\L\1|')
          ;;
      esac
      update_rc "$nu_config_path_posix" "nushell"
    fi
    # Check for PowerShell (pwsh) on Linux and macOS
    if [ "$os_type" != "MSYS*" ] && [ "$os_type" != "MINGW*" ] && [ "$os_type" != "CYGWIN*" ]; then
      if command -v pwsh >/dev/null 2>&1; then
        # Query pwsh for its profile path
        pwsh_profile_path=$(pwsh -NoProfile -Command '$PROFILE.CurrentUserCurrentHost' 2>/dev/null | tr -d '\r')
        if [ -n "$pwsh_profile_path" ]; then
          update_rc "$pwsh_profile_path" "powershell"
        fi
      fi
    fi
  fi

  # Trim leading newlines that might exist from the printf construction
  updated_files=$(echo "$updated_files" | sed '/^$/d')
  skipped_files=$(echo "$skipped_files" | sed '/^$/d')

  # Check if any action was taken (either update or skip)
  if [ -n "$updated_files" ] || [ -n "$skipped_files" ]; then
    echo ""

    # Report skipped files, if any
    if [ -n "$skipped_files" ]; then
      echo "The following files already contain IntelliShell configuration and were skipped:"
      old_ifs="$IFS"
      IFS='
'
      for file in $skipped_files; do
        if [ -n "$file" ]; then
          echo "  - $file"
        fi
      done
      IFS="$old_ifs"
      
      echo ""
    fi

    # Report successfully updated files, if any
    if [ -n "$updated_files" ]; then
      echo "Configuration successfully added to the following files:"
      old_ifs="$IFS"
      IFS='
'
      for file in $updated_files; do
        if [ -n "$file" ]; then
          echo "  - $file"
        fi
      done
      IFS="$old_ifs"

      echo ""
      echo "Please restart your terminal for the changes to take effect."
    fi

    echo "If you use a shell that wasn't listed above, you will need to configure it manually."
  else
    # This block now only runs if no config files were found at all
    echo ""
    echo "Could not find a shell profile to update automatically."
    echo "To complete the setup, please add the following lines to your shell's configuration file:"
    
    echo ""
    echo "--- For bash or zsh (in ~/.bashrc or ~/.zshrc) ---"
    printf 'export INTELLI_HOME="%s"\n' "$INTELLI_HOME"
    printf 'export PATH="$INTELLI_HOME/bin:$PATH"\n'
    printf 'eval "$(intelli-shell init bash)" # Or "zsh"\n'
    
    echo ""
    echo "--- For Fish shell (in ~/.config/fish/config.fish) ---"
    printf 'set -gx INTELLI_HOME="%s"\n' "$INTELLI_HOME"
    printf 'fish_add_path "$INTELLI_HOME/bin"\n'
    printf 'intelli-shell init fish | source\n'
    
    echo ""
    echo "--- For Nushell (in ~/.config/nushell/config.nu) ---"
    printf '$env.INTELLI_HOME = "%s"\n' "$INTELLI_HOME"
    printf '$env.PATH = ($env.PATH | prepend "%s/bin")\n' "$INTELLI_HOME"
    printf 'mkdir ($nu.data-dir | path join "vendor/autoload")\n'
    printf 'intelli-shell init nushell | save -f ($nu.data-dir | path join "vendor/autoload/intelli-shell.nu")\n'
    
    echo ""
    echo "After saving the file, please restart your terminal."
  fi

else

  # If profile update was skipped, show manual instructions
  echo "Skipped automatic profile update as requested."
  echo "To complete the setup, please add the following lines to your shell's configuration file:"

  echo ""
  echo "--- For bash or zsh (in ~/.bashrc or ~/.zshrc) ---"
  printf 'export INTELLI_HOME="%s"\n' "$INTELLI_HOME"
  printf 'export PATH="$INTELLI_HOME/bin:$PATH"\n'
  printf 'eval "$(intelli-shell init bash)" # Or "zsh"\n'
  
  echo ""
  echo "--- For Fish shell (in ~/.config/fish/config.fish) ---"
  printf 'set -gx INTELLI_HOME="%s"\n' "$INTELLI_HOME"
  printf 'fish_add_path "$INTELLI_HOME/bin"\n'
  printf 'intelli-shell init fish | source\n'
  
  echo ""
  echo "--- For Nushell (in ~/.config/nushell/config.nu) ---"
  printf '$env.INTELLI_HOME = "%s"\n' "$INTELLI_HOME"
  printf '$env.PATH = ($env.PATH | prepend "%s/bin")\n' "$INTELLI_HOME"
  printf 'mkdir ($nu.data-dir | path join "vendor/autoload")\n'
  printf 'intelli-shell init nushell | save -f ($nu.data-dir | path join "vendor/autoload/intelli-shell.nu")\n'
  
  echo ""
  echo "After saving the file, please restart your terminal."

fi

exit 0
