#!/bin/env bash
# purpose: setup personal neovim configuration
# author: flouda

# Color definitions for output formatting
RED='\033[0;31m'
YELLOW='\033[0;33m'
GREEN='\033[0;32m'
RESET='\033[0m'

# Global variables
use_sudo=false

# Function to print colored messages
print_message() {
    local color=$1
    local message=$2
    local options=${3:-""}  # Default to empty if no options provided
    echo -e ${options} "${color}${message}${RESET}"
}

# Function to check if sudo is available and set the use_sudo flag
check_sudo() {
    if command -v sudo &> /dev/null; then
        use_sudo=true
        print_message "$GREEN" "sudo is available"
    else
        use_sudo=false
        print_message "$YELLOW" "sudo is not available"
    fi
}

# Function to execute commands with or without sudo
execute_command() {
    local cmd="$1"
    if [[ $use_sudo == true ]]; then
        sudo $cmd
    else
        $cmd
    fi
}

# Function to install packages using pacman
install_pacman_packages() {
    print_message "$GREEN" "Using pacman package manager"

    local packages="neovim npm nodejs go ripgrep fzf git python gcc tree-sitter-cli luarocks diffutils unzip lazygit imagemagick"
    execute_command "pacman -Sy --noconfirm --needed $packages"

    if [[ $? -ne 0 ]]; then
        print_message "$RED" "Failed to install required packages. Please install them manually."
        exit 1
    else
        print_message "$GREEN" "Successfully installed required packages."
    fi
}

# Function to install packages using apt
install_apt_packages() {
    print_message "$GREEN" "Using apt package manager"
    export DEBIAN_FRONTEND=noninteractive

    execute_command "apt update"

    local base_packages="git python3 python3-venv gcc ninja-build gettext cmake curl build-essential golang ripgrep fzf imagemagick luarocks"

    print_message "$YELLOW" "Running in full mode, installing latest nodejs"

    if [[ $use_sudo == true ]]; then
        curl -sL https://deb.nodesource.com/setup_current.x | sudo bash -
    else
        curl -sL https://deb.nodesource.com/setup_current.x | bash -
    fi
    execute_command "apt install -y nodejs $base_packages"

    if [[ $? -ne 0 ]]; then
        print_message "$RED" "Failed to install required packages. Please install them manually."
        exit 1
    else
        print_message "$GREEN" "Successfully installed required packages."
    fi

    # install lazygit
    local lazygit_dir=$(mktemp -d --dry-run)
    current_dir=$(pwd)
    mkdir ${lazygit_dir}
    cd ${lazygit_dir}
    LAZYGIT_VERSION=$(curl -s "https://api.github.com/repos/jesseduffield/lazygit/releases/latest" | \grep -Po '"tag_name": *"v\K[^"]*')
    curl -Lo lazygit.tar.gz "https://github.com/jesseduffield/lazygit/releases/download/v${LAZYGIT_VERSION}/lazygit_${LAZYGIT_VERSION}_Linux_x86_64.tar.gz"
    tar xf lazygit.tar.gz lazygit
    if [[ $use_sudo == true ]]; then
        sudo install lazygit -D -t /usr/local/bin/
    else
        install lazygit -D -t /usr/local/bin/
    fi
    cd ${current_dir}

    # install tree-sitter-cli
    local tree_sitter_dir=$(mktemp -d --dry-run)
    current_dir=$(pwd)
    mkdir ${tree_sitter_dir}
    cd ${tree_sitter_dir}
    wget https://github.com/tree-sitter/tree-sitter/releases/download/v0.25.8/tree-sitter-linux-x64.gz
    gunzip tree-sitter-linux-x64.gz
    if [[ $use_sudo == true ]]; then
        sudo install tree-sitter-linux-x64 -D /usr/local/bin/tree-sitter
    else
        install tree-sitter-linux-x64 -D /usr/local/bin/tree-sitter
    fi
    cd ${current_dir}
}

# Function to build and install neovim from source (for apt systems)
build_install_neovim() {
    local build_flag=true
    local neovim_build_dir=$(mktemp -d --dry-run)

    print_message "$YELLOW" "Cloning neovim repository..."
    git clone https://github.com/neovim/neovim --branch=stable --depth=1 "${neovim_build_dir}"
    cd "${neovim_build_dir}"

    local latest_tag=$(git describe --tags `git rev-list --tags --max-count=1`)

    # Check if neovim is already installed and up to date
    if command -v nvim &> /dev/null; then
        print_message "$YELLOW" "Neovim is already installed. Checking version..."
        local installed_version=$(nvim --version | head -n 1 | awk '{print $2}')

        if [[ ${latest_tag} == ${installed_version} ]]; then
            print_message "$GREEN" "Neovim is already up to date."
            build_flag=false
        else
            print_message "$YELLOW" "Neovim is not up to date. Building from source..."
        fi
    fi

    # Build and install neovim if needed
    if [[ ${build_flag} == true ]]; then
        print_message "$YELLOW" "Building neovim..."
        make CMAKE_BUILD_TYPE=RelWithDebInfo

        if [[ $? -ne 0 ]]; then
            print_message "$RED" "Failed to build neovim. Please check the output for errors."
            exit 1
        else
            print_message "$GREEN" "Successfully built neovim."
        fi

        print_message "$YELLOW" "Installing neovim..."
        execute_command "make install"

        if [[ $? -ne 0 ]]; then
            print_message "$RED" "Failed to install neovim. Please check the output for errors."
            exit 1
        else
            print_message "$GREEN" "Successfully installed neovim."
        fi
    fi
}

# Function to backup existing neovim directories
backup_existing_config() {
    local directories=(
        "${HOME}/.config/nvim:${HOME}/.config/nvim.bak"
        "${HOME}/.cache/nvim:${HOME}/.cache/nvim.bak"
        "${HOME}/.local/share/nvim:${HOME}/.local/share/nvim.bak"
        "${HOME}/.local/state/nvim:${HOME}/.local/state/nvim.bak"
    )

    for dir_pair in "${directories[@]}"; do
        local source_dir="${dir_pair%%:*}"
        local backup_dir="${dir_pair##*:}"

        if [[ -d "$source_dir" ]]; then
            print_message "$YELLOW" "Backing up existing $(basename "$source_dir") to $(basename "$backup_dir")"
            mv "$source_dir" "$backup_dir"
        fi
    done
}

# Function to setup neovim configuration
setup_neovim_config() {
    # Create ~/.config directory if it doesn't exist
    if [[ ! -d ${HOME}/.config ]]; then
        print_message "$YELLOW" "Creating ~/.config directory..."
        mkdir ~/.config
    fi

    # Backup existing neovim directories
    backup_existing_config

    # Clone and install the configuration
    print_message "$YELLOW" "Downloading neovim configuration..."
    local tmpfile=$(mktemp -d --dry-run)
    git clone --depth 1 https://gitlab.com/flouda/dotfiles "${tmpfile}"

    mv "${tmpfile}/user-home/.config/nvim" ~/.config/
    rm -rf "${tmpfile}"
}

# Main function to orchestrate the entire setup process
main() {
    print_message "$GREEN" "Starting Neovim setup script..."

    # Check sudo availability
    check_sudo

    # Detect package manager and install packages
    if command -v pacman &> /dev/null; then
        install_pacman_packages
    elif command -v apt &> /dev/null; then
        install_apt_packages
        build_install_neovim
    else
        print_message "$RED" "Only pacman and apt package managers are supported."
        exit 1
    fi

    # Setup neovim configuration
    setup_neovim_config

    print_message "$GREEN" "Neovim setup completed successfully!"
}

# Execute main function with all command line arguments
main "$@"
