#!/usr/bin/env bash

set -o errexit
set -o pipefail
set -o nounset

__dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
backup_dir="$HOME/.local/backups/dotfiles"

# Colors for output. So fancy.

COLOR_SUCCESS='\033[0;32m'
COLOR_ERROR='\033[0;31m'
COLOR_NOTIFY='\033[1;33m'
NC='\033[0m' # No Color

# Default settings for this script:
#  - Do not create backups automatically.
#  - Install everything.

auto_backup=false
config_selection="all"

# Dotfile locations. Note that these locations should be identical between the 
# home directory and the dotfile directory.

zshrc=".zshrc"
zshrc_name="zshrc"
zshrc_source="${__dir}/${zshrc}"
zshrc_target="${HOME}/${zshrc}"
zshrc_backup="${backup_dir}/${zshrc_name}"

profile=".profile"
profile_name="profile"
profile_source="${__dir}/${profile}"
profile_target="${HOME}/${profile}"
profile_backup="${backup_dir}/${profile_name}"

i3=".config/i3/config"
i3_name="i3"
i3_source="${__dir}/${i3}"
i3_target="${HOME}/${i3}"
i3_backup="${backup_dir}/${i3_name}"

i3status=".config/i3status/config"
i3status_name="i3status"
i3status_source="${__dir}/${i3status}"
i3status_target="${HOME}/${i3status}"
i3status_backup="${backup_dir}/${i3status_name}"

xresources=".Xresources"
xresources_name="xresources"
xresources_source="${__dir}/${xresources}"
xresources_target="${HOME}/${xresources}"
xresources_backup="${backup_dir}/${xresources_name}"

gitconfig=".gitconfig"
gitconfig_name="gitconfig"
gitconfig_source="${__dir}/${gitconfig}"
gitconfig_target="${HOME}/${gitconfig}"
gitconfig_backup="${backup_dir}/${gitconfig_name}"

gitignore=".gitignore"
gitignore_name="gitignore"
gitignore_source="${__dir}/${gitignore}"
gitignore_target="${HOME}/${gitignore}"
gitignore_backup="${backup_dir}/${gitignore_name}"

alacritty=".config/alacritty/alacritty.toml"
alacritty_name="alacritty"
alacritty_source="${__dir}/${alacritty}"
alacritty_target="${HOME}/${alacritty}"
alacritty_backup="${backup_dir}/${alacritty_name}"

fontconfig=".config/fontconfig/fonts.conf"
fontconfig_name="fontconfig"
fontconfig_source="${__dir}/${fontconfig}"
fontconfig_target="${HOME}/${fontconfig}"
fontconfig_backup="${backup_dir}/${fontconfig_name}"

function display_configs {
    echo 'Supported config targets: all, zshrc, profile, i3, i3status, xresources, gitconfig, gitignore, alacritty, fontconfig, nvim'
}

function display_usage {
    echo 'Usage: install.sh [-c|--config <target>] [-a|--auto-backup]'
    echo '       [-h|--help]'
    echo ''
    echo 'Install configurations.'
    echo ''
    echo '  -c|--config       Describes what to install: Default=all'
    echo '  -l|--list         List available configs.'
    echo '  -a|--auto-backup  Automatically backup existing configs.'
    echo '  -h|--help         Display this usage text.'
    echo ''
    echo 'Examples:'
    echo ''
    echo "./install.sh --config=all --auto-backup"
}

# Install some singular configuration file by creating a symbolic link. Handles
# automatic backups if the file already exists.
function install_config {

    # Used for diagnostic purposes only - describes the configuration.
    local config_name="$1"

    # The location of the configuration to install.
    local config_source="$2"

    # The destination where the symbolic link should be created.
    local config_target="$3"

    # The backup file for this piece of configuration.
    local config_backup="$4"

    if [ "$config_selection" = "all" ] || [ "${config_selection}" = "${config_name}" ]; then
        echo -n -e "${COLOR_SUCCESS}[+]${NC} Installing '${config_name}' to '${config_target}'... "
        if [ -f "${config_target}" ]; then
            if $auto_backup; then
                # The file exists, so create a backup and remove the file.
                echo -e "\n\t${COLOR_NOTIFY}[Note]${NC} creating a backup of '${config_target}'"
                cp "${config_target}" "${config_backup}"
                rm "${config_target}"
                ln -s "${config_source}" "${config_target}"
                echo -e "\t${COLOR_SUCCESS}[Success]${NC}"
            else
                # The caller does not want backups/deletions, so we must abort.
                echo -e "\n\t${COLOR_ERROR}[Error]${NC} Could not install configuration '${config_name}'. File '${config_target}' already exists. Please manually remove it or set --auto-backup"
            fi
        else
            # The file doesn't exist, we can safely create a symlink.
            ln -s "${config_source}" "${config_target}"
            echo -e "${COLOR_SUCCESS}[Success]${NC}"
        fi
    fi
}

function install_neovim {

    # Used for diagnostic purposes only - describes the configuration.
    local config_name="nvim"

    # The location of the configuration to install.
    local config_source=".config/nvim/init.lua"

    local lua_source=".config/nvim/lua"

    # The destination where the symbolic link should be created.
    local config_target="${HOME}/.config/nvim/init.lua"

    local lua_target="${HOME}/.config/nvim/lua"

    # The backup file for this piece of configuration.
    local config_backup="${backup_dir}/${config_name}"
    local lua_backup="${backup_dir}/nvim-lua"

    if [ "$config_selection" = "all" ] || [ "${config_selection}" = "${config_name}" ]; then
        echo -n -e "${COLOR_SUCCESS}[+]${NC} Installing '${config_name}' to '${config_target}'... "
        if [ -f "${config_target}" ]; then
            if $auto_backup; then
                # The file exists, so create a backup and remove the file.
                echo -e "\n\t${COLOR_NOTIFY}[Note]${NC} creating a backup of '${config_target}' and '${lua_target}'"
                cp "${config_target}" "${config_backup}"
                cp -r "${lua_target}" "${lua_backup}"
                rm "${config_target}"
                rm -r "${lua_target}"
                ln -s "${__dir}/${config_source}" "${config_target}"
                ln -s "${__dir}/${lua_source}" "${lua_target}"
                echo -e "\t${COLOR_SUCCESS}[Success]${NC}"
            else
                # The caller does not want backups/deletions, so we must abort.
                echo -e "\n\t${COLOR_ERROR}[Error]${NC} Could not install configuration '${config_name}'. This configuration already exists. Please manually remove it or set --auto-backup"
            fi
        else
            # The file doesn't exist, we can safely create a symlink.
            ln -s "${__dir}/${config_source}" "${config_target}"
            ln -s "${__dir}/${lua_source}" "${lua_target}"
            echo -e "${COLOR_SUCCESS}[Success]${NC}"
        fi
    fi
}

while [[ $# -gt 0 ]]
do
key="$1"

case $key in
    -c|--config)
        config_selection="$2"
        shift
        shift
        ;;
    -a|--auto-backup)
        auto_backup=true
        shift
        ;;
    -l|--list)
        display_configs
        exit 0
        ;;
    -h|--help)
        display_usage
        exit 0
        ;;
    *)
        echo "Unrecognized option: $1"
        display_usage
        exit 1
        ;;
esac
done

# Ensure the backup directory exists (if backups are requested).
if $auto_backup; then
    if [ ! -d "$backup_dir" ]; then
        if eval mkdir "$backup_dir"; then
            echo -e "${COLOR_NOTIFY}[Note]${NC} created '$backup_dir' to store dotfile backups."
        else
            echo -e "${COLOR_ERROR}[Error]${NC} Failed to create backup directory '$backup_dir'."
        fi
    fi
fi

# Install all requested configurations.
install_config "${zshrc_name}" "${zshrc_source}" "${zshrc_target}" "${zshrc_backup}"
install_config "${profile_name}" "${profile_source}" "${profile_target}" "${profile_backup}"
install_config "${i3_name}" "${i3_source}" "${i3_target}" "${i3_backup}"
install_config "${i3status_name}" "${i3status_source}" "${i3status_target}" "${i3status_backup}"
install_config "${gitconfig_name}" "${gitconfig_source}" "${gitconfig_target}" "${gitconfig_backup}"
install_config "${gitignore_name}" "${gitignore_source}" "${gitignore_target}" "${gitignore_backup}"
install_config "${xresources_name}" "${xresources_source}" "${xresources_target}" "${xresources_backup}"
install_config "${alacritty_name}" "${alacritty_source}" "${alacritty_target}" "${alacritty_backup}"
install_config "${fontconfig_name}" "${fontconfig_source}" "${fontconfig_target}" "${fontconfig_backup}"

# Note that all of these configurations are Neovim-related:
install_neovim