#!/bin/bash

# Downloaded from https://sh.sabooboo.me/

# This script is used to bootstrap the environment I use on my machines.
# Requirements: curl, git, bash, gcc, make, pkg-config and a package manager (apt or brew)

# Packages to install via cargo
cargo_packages=(
    # note that sscache is are installed separately in this script.
    "bat" # better cat
    "exa" # better ls
    "fd-find" # better find
    "ripgrep" # better grep
    "zoxide" # rusty z
    "cargo-info" # cargo info
    "cargo-tree" # cargo tree
    "du-dust" # better du
    "zellij" # terminal multiplexer
    "mprocs" # run finite processes in parallel
    "bacon" # super useful cargo watcher
    "speedtest-rs" # speedtest
    "wiki-tui" # wikipedia tuiaa
    "bob-nvim" # neovim version manager
    "rtx-cli" # rust toolchain manager
)

# Else packages (available via apt or brew)
packages=(
    "ffmpeg"
    "fzf"
)

# Language tools
lang_tools=(
    "yarn@1.22"
    "nodejs@18"
    "golang@latest"
)

# Change installer based on OS
function set_installer() {
    # Check for $INSTALLER variable first
    if [[ -n "$INSTALLER" ]]; then
        echo "Installer set to $INSTALLER"
        return
    fi
    # If no $INSTALLER variable, check for OS
    if [[ "$OSTYPE" == "darwin"* ]]; then
        echo "Installer set to brew"
        INSTALLER="brew"
    elif [[ "$OSTYPE" == "linux-gnu"* ]]; then
        echo "Installer set to apt"
        INSTALLER="apt"
    fi

    if [[ -z "$INSTALLER" ]]; then
        echo "No installer found. Try setting the \$INSTALLER variable."
        exit 1
    fi
}

function install() {
    if [[ "$INSTALLER" == "apt" ]]; then
        sudo apt install -y "$@"
    elif [[ "$INSTALLER" == "brew" ]]; then
        brew install "$@"
    else
        # Install with custom $INSTALLER
        $INSTALLER install "$@"
    fi
}

# Mac specific bootstrap function
function bootstrap_mac() {
    # xcode tools
    xcode-select --install

    # brew
    bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"
    if [[ "$?" -ne 0 ]]; then
        echo "Failed to install brew"
        installed_brew=2
    fi
    installed_brew=1

    # Alacritty config
    mkdir -p "$HOME/.config/alacritty"
    local url="https://sh.sabooboo.me/alacritty.yml"
    curl "$url" -o "$HOME/.config/alacritty/alacritty.yml"
    
    # Add mac specific packages to packages array
    packages+=(
        "alacritty"
        "keycastr"
        "obsidian"
        "gitui" # Don't know an alternative for apt
    )
}

function bootstrap_linux() {
    install libssl libssl-dev # required for rust sccache
    packages+=(
        "zsh"
    )
}

function download_nerdfont() {
    local nerd_url="https://github.com/ryanoasis/nerd-fonts/releases/download/v2.3.3/JetBrainsMono.zip"
    local nerd_dir="$HOME/.local/share/fonts"
    echo "Downloading nerd font from $nerd_url"
    mkdir -p "$nerd_dir"
    curl "$nerd_url" -o "$nerd_dir/JetBrainsMono.zip"
    if [[ "$?" -ne 0 ]]; then
        return 1
    fi
    unzip "$nerd_dir/JetBrainsMono.zip" -d "$nerd_dir/JetBrainsMono"
    rm "$nerd_dir/JetBrainsMono.zip"
    return 0
}

function download_dotfiles() {
    local url="https://sh.sabooboo.me/zshrc"
    echo "Downloading dotfiles from $URL"
    curl "$url" -o "$HOME/.zshrc"
    if [[ "$?" -ne 0 ]]; then
        failure_dotfiles=1
        return
    fi
}

function download_nvim() {
    # Download neovim
    # If bob is not installed, alert & return
    if [[ -z "$(command -v bob)" ]]; then
        echo "bob not installed. Skipping neovim config."
        failure_nvim=1
        return
    fi
    bob install stable
    if [[ "$?" -ne 0 ]]; then
        failure_nvim=2
        return
    fi
    download_nerdfont
    if [[ "$?" -ne 0 ]]; then
        failure_nvim=3
    fi

    # Download neovim config
    local astro_url="https://github.com/AstroNvim/AstroNvim"
    echo "Downloading neovim config from $astro_url"
    mkdir -p "$HOME/.config/nvim"
    git clone "$astro_url" "$HOME/.config/nvim"
    if [[ "$?" -ne 0 ]]; then
        failure_nvim=4
        return
    fi
    bob use stable
    if [[ "$?" -ne 0 ]]; then
        failure_nvim=5
        return
    fi
    failure_nvim=0
}

### -- Execution begins -- ###

# Set installer
set_installer

# If on a mac, run mac specific bootstrap
if [[ "$OSTYPE" == "darwin"* ]]; then
    bootstrap_mac
fi

if [[ "$OSTYPE" == "linux-gnu"* ]]; then
    bootstrap_linux
fi

# -- Adding dotfiles
download_dotfiles

# -- Installing packages

# Cargo
curl https://sh.rustup.rs -sSf | sh -s -- -y

source "$HOME/.cargo/env" # Add cargo to path for this session. This is needed for cargo packages to install

failure_packages=""
for package in "${packages[@]}"; do
    install "$package"
    if [[ $? -ne 0 ]]; then
        failure_packages="$failure_packages $package"
    fi
done

# Cargo packages
failure_cargo=""
# cargo install sccache
# if sccache is now in path, set it as rustc wrapper
if [[ -n "$(command -v sccache)" ]]; then
    export RUSTC_WRAPPER=sccache
else
    failure_cargo="$failure_cargo sccache"
fi

for package in "${cargo_packages[@]}"; do
    cargo install "$package"
    if [[ $? -ne 0 ]]; then
        failure_cargo="$failure_cargo $package"
    fi
done

# Language tools
failure_rtx=""
for package in "${lang_tools[@]}"; do
    rtx install "$package"
    if [[ $? -ne 0 ]]; then
        failure_rtx="$failure_rtx $package"
    fi
done

# -- zoxide setup
# If zoxide is installed, set it up
if [[ -n "$(command -v zoxide)" ]]; then
    # If ~/.zcompdump exists, delete it
    if [[ -f $HOME/.zcompdump ]]; then
        rm ~/.zcompdump*
    fi
    compinit
fi

for package in "${lang_tools[@]}"; do
    # If package in failure_rtx, skip
    if [[ "$failure_rtx" == *"$package"* ]]; then
        continue
    fi
    rtx global "$package"
done

# -- Neovim config
download_nvim

# -- Finish
echo
echo "Finished bootstrapping!"
echo "What happened:"
if [[ -n "$installed_brew" ]]; then
    echo " - Installed brew"
elif [[ "$installed_brew" -eq 2 ]]; then
    echo " - Failed to install brew"
fi
echo " - Attempted to install packages:" "${packages[@]}" "${cargo_packages[@]}"
if [[ "${#failure_packages[@]}" -ne 0 || "${#failure_cargo[@]}" -ne 0 ]]; then
    echo "   - Failed to install packages:" "${failure_packages[@]}" "${failure_cargo[@]}"
else 
    echo "   - All packages installed successfully"
fi
echo " - Attempted to install language tools:" "${lang_tools[@]}"
if [[ "${#failure_rtx[@]}" -ne 0 ]]; then
    echo "   - Failed to install language tools:" "${failure_rtx[@]}"
else
    echo "   - All language tools installed successfully"
fi
# Check if dotfiles were downloaded
if [[ -n "$failure_dotfiles" ]]; then
    echo " - Failed to download dotfiles"
else
    echo " - Downloaded dotfiles"
fi
# 1: bob is not installed.
# 2: bob malfunctioned.
# 3: nerd font failed to download.
# 4: git clone neovim config failed.
echo " - Attempted to configure neovim as astrovim"
if [[ -n "$failure_nvim" ]]; then
    if [[ "$failure_nvim" -eq 1 ]]; then
        echo "   - bob not installed; skipped neovim config."
    elif [[ "$failure_nvim" -eq 2 ]]; then
        echo "   - something went wrong with bob"
    elif [[ "$failure_nvim" -eq 3 ]]; then
        echo "   - nerd font failed to download"
    elif [[ "$failure_nvim" -eq 4 ]]; then
        echo "   - git clone neovim config failed"
    fi
else
    echo "   - Successfully configured neovim as astrovim"
fi
echo "What's next:"
echo " - Open a zsh session to see changes"
echo " - Change your terminal font to a nerd font" # If on alacritty then alacritty.yml will be installed so conditionally print this
echo " - Change your default shell to zsh:"
echo "     - chsh -s $(which zsh)"
echo "     - sudo usermod -s $(which zsh) $USER"
echo "     - you may need to change your terminal settings instead"
echo " - Install the following packages:" "${failure_packages[@]}" "${failure_cargo[@]}"
if [[ "$failure_nvim" -eq 0 ]]; then
    echo " - Check out nvim for yourself"
    echo "   - Run :Mason to check lsp plugins"
    echo "   - Check out ~/.recommended-MasonInstall for my recommended lsp plugins"
    echo "bash-language-server clangd cmake-language-server css-lsp debugpy emmet-ls eslint-lsp gopls html-lsp jdtls json-lsp kotlin-language-server lemminx lua-language-server marksman omnisharp prisma-language-server pyright tailwindcss-language-server taplo typescript-language-server vue-language-server yaml-language-server" > "$HOME/.recommended-MasonInstall"
fi

