#!/bin/bash

#defining variables
nerdfontsrepo='https://api.github.com/repos/ryanoasis/nerd-fonts'
aFontInstalled="False"
removeZipFiles="True"
dist_dir="$HOME/.local/share/fonts"
down_dir="$(command -V xdg-user-dir &>/dev/null && xdg-user-dir DOWNLOAD || echo "$HOME/Downloads")/NerdFonts"
cache_dir="${XDG_CACHE_HOME:-$HOME/.cache}/nerdFonts"
update_fonts="False"
force_update="False"
os=$(uname)
isUnzip=$(whereis unzip | awk -F' ' '{print $2}')
isCurl=$(whereis curl | awk -F' ' '{print $2}')

# Set colors
RED=$(tput setaf 1)
GREEN=$(tput setaf 2)
BLUE=$(tput setaf 4)
RESET=$(tput sgr0)

# For Macs, need to set a few different things
if [[ "$os" == 'Darwin' ]]; then
	dist_dir="$HOME/Library/Fonts"
	cache_dir="$HOME/Library/Caches/NerdFonts"
fi

# help message
usage() {
	echo "${BLUE}getNF: A Better way to install NerdFonts${RESET}"
	echo ""
	echo "${BLUE}Usage:${RESET}"
	echo "${BLUE}-h print this help message and exit"
	echo "-f force reinstall an already installed font"
	echo "-k Keep the downloaded fonts zip files${RESET}"
	echo ""
	echo "- ${BLUE}Choose one or more fonts (by index/number) to install"
	echo "- Hit Return/Enter to install the selected fonts"
	echo "- Type 'q' to quit${RESET}"
	echo ""
}

# Setting flags
while getopts :hkf option; do
	case "${option}" in
	h) usage && exit 0 ;;
	k) removeZipFiles="False" ;;
	f) force_update="True" ;;
	*) usage && exit 0 ;;
	esac
done

# Check if dependencies exist
[ -z "$isUnzip" ] && echo "${RED}Dependency unzip is not installed on your system.${RESET}" && exit
[ -z "$isCurl" ] && echo "${RED}Dependency curl is not installed on your system.${RESET}" && exit

# Check if the distDir and downDir exists, if it doesn't, create it
[ -d "$dist_dir" ] && echo "${BLUE}Fonts directory exists, good.${RESET}" || (mkdir -p "$dist_dir" && echo "${GREEN}Created the fonts directory.${RESET}")
[ -d "$down_dir" ] && echo "${BLUE}Fonts download directory exists, good.${RESET}" || (mkdir -p "$down_dir" && echo "${GREEN}Created fonts download directory..${RESET}")
[ -d "$cache_dir" ] || mkdir -p "$cache_dir"

## Handle release version
# Set the name of the file to store the release number
release_file="$cache_dir/release.txt"
# Get the local release version
[ -f "$release_file" ] && cached_release=$(cat "$release_file") || cached_release=""
# Get the latest release number from NerdFonts github repo
release=$(curl --silent "$nerdfontsrepo/releases/latest" |
	awk -v RS=',' -F'"' '/tag_name/ {print $4}')
# Compare the latest release number with the cached release number
if [ "$release" != "$cached_release" ]; then
	update_fonts=True
	# Update the cached release number
	echo "$release" >"$release_file"
fi

## Handle the font names
# Download the file list and extract the font names
font_list=$(curl -s "$nerdfontsrepo/contents/patched-fonts?ref=master" |
	awk -v RS=',' -F'"' '/name/ {print $4}')
# Convert the list of fonts into an array of fonts
declare -a fonts
# Read the input string and populate the array, we do this to get rid of the `readarray` command
while IFS= read -r line; do
	fonts+=("$line")
done <<<"$font_list"
#define a file for the installed fonts names to be stored in
installed_fonts_file="$cache_dir/installed.txt"
[ -f "$installed_fonts_file" ] && installed_fonts_list=$(cat "$installed_fonts_file") || installed_fonts_list=()
# Convert the list of installed fonts into an array of fonts
declare -a installed_fonts
while IFS= read -r line; do
	installed_fonts+=("$line")
done <<<"$installed_fonts_list"
# a list of currently selectd fonts
selected_fonts=()

# Remove installed fonts from the list of all fonts if there is no new release
if [[ $update_fonts = "False" ]]; then
	available_fonts=()
	for font in "${fonts[@]}"; do
		if [[ ! " ${installed_fonts[@]} " =~ " ${font} " ]]; then
			available_fonts+=("$font")
		fi
	done
else
	echo "" >"$installed_fonts_file"
	available_fonts=("${fonts[@]}")
fi

function download_font() {
	echo "${BLUE}$1 download started...${RESET}"
	curl -LJO# "https://github.com/ryanoasis/nerd-fonts/releases/download/$release/$1.zip"
	echo "${GREEN}$1 download finished${RESET}"
}

function install_font() {
    echo "${BLUE}$1 installation started...${RESET}"
	unzip -qqo "$1.zip" -d "$dist_dir/$1"
	echo "${GREEN}$1 installation finished${RESET}"
}

function remove_zip_files() {
	echo "${BLUE}Removing downloaded zip files from $down_dir...${RESET}"
	for font in "${selected_fonts[@]}"; do
		rm "$down_dir/$font.zip"
	done
	echo "${GREEN}Downloaded zip files removal suceeded!${RESET}"
}

function update_fonts_cache() {
	echo "${BLUE}Updating fc-cache...${RESET}"
	fc-cache -f 2>&1
	echo "${GREEN}fc-cache: update succeeded!${RESET}"
}

# Remove already selected fonts from the menu
if [ $force_update = "True" ]; then
	font_options=("${fonts[@]}")
else
	font_options=("${available_fonts[@]}")
fi
# Define function to print menu
function menu {
	echo "${BLUE}Select one or more fonts:${RESET}"
	(for i in "${!font_options[@]}"; do
		printf "%d) %s\n" "$((i + 1))" "${font_options[$i]}"
	done && printf "q) Quit\n") | pr -3 -t -w "$(tput cols)"
}

# call the menu funciton to list the available fonts
menu

# Parse input like 1-3
function parse_range {
	if ! [[ $1 =~ ^[0-9]+-[0-9]+$ ]]; then
		echo "${RED}Invalid input format: $1. Expected format: X-Y.${RESET}"
		return 1
	fi
	IFS='-' read -ra range <<<"$1"
	range_start=${range[0]}
	range_end=${range[1]}
	for ((i = range_start; i <= range_end; i++)); do
		index=$((i - 1))
		if ((index >= 0 && index < ${#font_options[@]})); then
			selected_fonts[index]=${font_options[index]}
		else
			echo "${RED}Invalid option: $i. Try again.${RESET}"
			return 1
		fi
	done
}

## Handle user input
while true; do
	read -p "${BLUE}Enter font number(s) (e.g. 1,2,3 or 1-3 or 1,3-5):${RESET} " choices
	for choice in $(echo "$choices" | tr ',' ' '); do
		if [[ $choice == "q" ]]; then
			echo "${GREEN}Goodbye!${RESET}"
			exit
		# check if they entered a range (e.g. 1-3)
		elif [[ $choice == *-* ]]; then
			parse_range "$choice" || continue 2
		elif ((choice >= 1 && choice <= ${#font_options[@]})); then
			index=$((choice - 1))
			selected_fonts[index]=${font_options[index]}
		else
			echo "${RED}Invalid option: $choice. Try again.${RESET}"
			continue 2
		fi
	done
	break
done

# loop over the selected fonts and download them
if ((${#selected_fonts[@]} > 0)); then
	for i in "${selected_fonts[@]}"; do
		pushd "$down_dir" >/dev/null
		# remove the zip file of the download font if it exists, this is due to curl not having an overwrite function
		if [ -f "$down_dir/$i.zip" ]; then
			rm "$down_dir/$i.zip"
		fi
		download_font "$i" &&
			install_font "$i" &&
			echo "$i" >>"$installed_fonts_file"
		aFontInstalled=True
		popd >/dev/null
	done
else
	echo "${RED}No fonts were selected, exiting.${RESET}"
	exit
fi

# If a font was installed
if [ "$aFontInstalled" = "True" ]; then
	# Update the fonts cache
	update_fonts_cache
	# remove downloaded archives if the option -k was not passed
	if [ "$removeZipFiles" = "True" ]; then
		remove_zip_files
	else
		echo "${GREEN}The downloaded zip files can be found in $down_dir${RESET}"
	fi
fi

echo "${GREEN}Enjoy your new fonts!${RESET}"
