#!/bin/bash

# shellcheck disable=SC2164

# Defining variables
PREFIX='/data/data/com.termux/files/usr'
nerdfontsrepo='https://api.github.com/repos/ryanoasis/nerd-fonts'
dist_dir="$PREFIX/share/termux-nf/fonts"
down_dir="$HOME/share/termux-nf/Downloads"
cache_dir="/data/data/com.termux/cache"
TERMUX_DIR="$HOME/.termux/font.ttf"
# Set the name of the file to store the release number
release_file="$cache_dir/release.txt"
# Define a file for the installed fonts names to be stored in
installed_fonts_file="$cache_dir/installed.txt"
aFontInstalled="False"
keepZipFiles="False"
update_fonts="False"
force_update="False"

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

# Help message
usage() {
    cat << EOF
Termux-NF: A Better way to install NerdFonts on Termux

Usage:
  getnf [options]

OPTIONS:
  -h		  print this help message and exit
  -f		  force reinstall an already installed font
  -k		  keep the downloaded fonts zip files
  -i <font>   directly install the specified fonts

To install fonts using the menu:
- Choose one or more fonts (by index/number) to install
- Hit Return/Enter to install the selected fonts
- Type 'q' to quit

To install fonts directly:
- Get the exact name of a font from the menu
- Use 'getnf -i "<font-name>"' to install a font
- Use 'getnf -i "<name1>,<name2>"' to install multiple fonts
EOF
}

info() {
    printf "%s\n" "$1"
}

confirm() {
    printf "${GREEN}%b${RESET}\n" "$1"
}

alert() {
    printf "${RED}%b${RESET}\n" "$1"
}

error() {
    alert "$1" >&2
    exit 1
}

ensure_installed() {
    if ! command -v "$1" > /dev/null; then
        error "Dependency $1 is not installed on your system."
    fi
}

create_dir() {
    if [[ -d "$1" ]]; then
        info "$2 directory exists, good."
    else
        mkdir -p "$1"
        confirm "Created the $2 directory."
    fi
}

check_dependencies() {
    # Check if dependencies exist
    ensure_installed unzip
    ensure_installed curl

    # Check if the distDir and downDir exist, if they don't, create them
    create_dir "$dist_dir" "Fonts"
    create_dir "$down_dir" "Fonts Download"
    [[ -d "$cache_dir" ]] || mkdir -p "$cache_dir"
}

handle_release_version() {
    # Get the local release version
    [[ -f "$release_file" ]] && cached_release=$(cat "$release_file")
    # 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
}

download_font() {
    info "$1 download started..."
    curl -LJO# "https://github.com/ryanoasis/nerd-fonts/releases/download/$release/$1.zip"
    confirm "$1 download finished"
}

extract_font() {
    info "$1 installation started..."
    unzip -qqo "$1.zip" -d "$dist_dir/$1"
    confirm "$1 installation finished"
}

remove_zip_files() {
    info "Removing downloaded zip files from $down_dir..."
    for font in "${SELECTED_FONTS[@]}"; do
        rm "$down_dir/$font.zip"
    done
    confirm "Downloaded zip files removal succeeded!"
}

install_font() {
    pushd "$down_dir" > /dev/null
    # Remove the zip file of the download font if it exists due to curl not having an overwrite function
    if [[ -f "$down_dir/$1.zip" ]]; then
        rm "$down_dir/$1.zip"
    fi
    download_font "$1" &&
        extract_font "$1" &&
        echo "$1" >> "$installed_fonts_file"
    aFontInstalled="True"
    popd > /dev/null
}

font_url_exists() {
    url="https://github.com/ryanoasis/nerd-fonts/releases/download/$release/$1.zip"
    curl --output /dev/null --silent --head --fail "$url" && return 0 || return 1
}

direct_install() {
    for font_name in $(echo "$1" | tr ',' ' '); do
        if font_url_exists "$font_name"; then
            SELECTED_FONTS+=("$font_name")
        else
            error "Invalid font name: $font_name. Try again."
        fi
    done
}

post_install() {
   # Remove downloaded archives if the option -k was not passed
    if [[ "$keepZipFiles" == "False" ]]; then
        remove_zip_files
    else
        confirm "The downloaded zip files can be found in $down_dir"
    fi
}

menu() {
    local options=("$@")
    info "Select one or more fonts:"
    (
        for i in "${!options[@]}"; do
            printf "%d) %s\n" "$((i + 1))" "${options[$i]}"
        done
        printf "q) Quit\n"
    ) | pr -3 -t -w "$(tput cols)"
}

# Parse input like 1-3
parse_range() {
    if ! [[ $1 =~ ^[0-9]+-[0-9]+$ ]]; then
        alert "Invalid input format: $1. Expected format: X-Y."
        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
            alert "Invalid option: $i. Try again."
            return 1
        fi
    done
}

menu_install() {
    # 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 all_fonts
    # Read the input string and populate the array
    #mapfile -t all_fonts <<< "$font_list"
    while IFS= read -r line; do
        all_fonts+=("$line")
    done <<< "$font_list"

    # Get the list of installed fonts
    if [[ -f "$installed_fonts_file" ]]; then
        installed_font_list=$(cat "$installed_fonts_file")
        # 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_font_list"
    fi

    # Remove installed fonts from the list of all fonts if there is no new release
    # or if the user does not want to force the update
    if [[ "$update_fonts" == "False" && "$force_update" == "False" ]]; then
        declare -a font_options
        for font in "${all_fonts[@]}"; do
            if [[ " ${installed_fonts[*]} " != *" $font "* ]]; then
                font_options+=("$font")
            fi
        done
    else
        echo "" > "$installed_fonts_file"
        font_options=("${all_fonts[@]}")
    fi

    # Call the menu function to list the available fonts
    menu "${font_options[@]}"

    # Handle user input
    while true; do
        read -rp "Enter font number(s) (e.g. 1,2,3 or 1-3 or 1,3-5): " choices
        for choice in $(echo "$choices" | tr ',' ' '); do
            if [[ $choice == "q" ]]; then
                confirm "Goodbye!"
                exit
            # Choice is 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
                alert "Invalid option: $choice. Try again."
                continue 2
            fi
        done
        echo "Selected fonts: ${SELECTED_FONTS[*]}"
        break
    done
}

# Applying font on termux
termux() {
    cd $dist_dir
    arrange_files() {

    	# Check if any .ttf files exist
        if ls *.ttf 1>/dev/null 2>&1; then
        # List only .ttf files if they exist
            files=(*.ttf)
        else
        # Otherwise, list all files
            files=(*)
        fi

    		# List the files numerically
    		echo "${BLUE}List of Installed Fonts:${RESET}"
    		for i in "${!files[@]}"; do
                echo "${BLUE}$((i+1)). ${files[$i]}${RESET}"
    		done
}

# activating the function
arrange_files

select_file() {
    # Prompt the user to select a file
    read -p "${BLUE}Enter the number of the file:${RESET} " choice

    # Validate the user input
    if [[ $choice =~ ^[0-9]+$ ]] && [ $choice -ge 1 ] && [ $choice -le ${#files[@]} ]; then
        selected_file="${files[$((choice-1))]}"

        # Check if the selected file is a directory
        if [ -d "$selected_file" ]; then
            cd "$selected_file" || { echo "${RED}Failed to enter directory $selected_file"${RESET}; exit 1; }
            arrange_files   # Arrange files in the selected directory
            select_file     # Prompt the user to select a file again
        else
            cp "$selected_file" "$HOME/.termux/font.ttf" || { echo "${RED}Failed to apply font"${RESET}; exit 1; }
						echo "${GREEN}Font Applied.${RESET}"
        fi
    else
        echo "${RED}Invalid choice. Please enter a valid number.${RESET}"
        select_file
    fi
}

# activating the function
select_file

echo "    ${BLUE}[${RED}*${BLUE}] ${BLUE}Reloading Settings..."
    	am broadcast --user 0 -a com.termux.app.reload_style com.termux > /dev/null
    	{ echo "    ${BLUE}[${RED}*${BLUE}] ${GREEN}Applied Successfully."; echo; }

}

main() {
    # Setting flags
    while getopts ":hkfi:" option; do
        case "${option}" in
            h) usage && exit 0 ;;
            k) keepZipFiles="True" ;;
            f) force_update="True" ;;
            i) FONTNAMES="$OPTARG" ;;
            :) error "Option '-$OPTARG' requires at least one font name." ;;
            *) usage && exit 0 ;;
        esac
    done
    # Shift parsed options
    shift $((OPTIND - 1))

    check_dependencies
    handle_release_version

    # List of selected fonts
    declare -a SELECTED_FONTS

    # Put the selected fonts into the list
    if [[ -n "$FONTNAMES" ]]; then
        direct_install "$FONTNAMES"
    else
        menu_install
    fi

    # Loop over the selected fonts and download them
    if ((${#SELECTED_FONTS[@]} > 0)); then
        for i in "${SELECTED_FONTS[@]}"; do
            install_font "$i"
        done
    else
        error "No fonts were selected, exiting."
    fi

    # If a font was installed
    if [[ "$aFontInstalled" == "True" ]]; then
        post_install
    fi

    # To check if Termux is being used
    if [ $(ps -ef| grep -c com.termux) -gt 0 ]; then
        termux
    fi
}

main "$@"