#!/data/data/com.termux/files/usr/bin/env bash

# shellcheck disable=SC2164
# shellcheck disable=SC2155
# shellcheck disable=SC2181
# shellcheck disable=SC2236
# shellcheck disable=SC2143

DOTFILES_DIR="$HOME/.dotload"
NOTES=""
DEFAULT_DOTFILES_REPO="dotfiles"

if [[ $(echo "$0" | cut -c1-6) == "/snap/" ]]; then
    HOME="/home/$(whoami)"
    NOTES="Snap version "
fi

hyperlink() {
    echo -e "\e]8;;$1\e\\$2\e]8;;\e\\"
}

# Prints the header for the dotload script
echo -e "$NOTES\e[1m($(hyperlink "https://github.com/okineadev/dotload" "GitHub"))\e[0m"
echo ""

error_msg() {
    local key="$1"
    local value="$2"
    local message="$3"

    echo -e "\e[1;31mERROR!\e[0m"
    echo ""
    echo -e "  \e[1mEntered $key:\e[0m \"$value\""
    echo -e "  $message"
    echo ""

    exit 1
}

validate() {
    local validate_type="$1"
    local string="$2"
    local pretty_name;
    local max_lenght;
    local check_punctuations="true"

    if [[ "$1" == "username" ]]; then
        validate_type="username"
        pretty_name="Username"
        max_lenght=39

    elif [[ "$1" == "branch" ]]; then
        validate_type="branch name"
        pretty_name="Branch name"
        max_lenght=255

    elif [[ "$1" == "repo_name" ]]; then
        validate_type="repo name"
        pretty_name="Repo name"
        max_lenght=100

    elif [[ "$1" == "url" ]]; then
        validate_type="URL"
        pretty_name="URL"
        max_lenght=2048
        check_punctuations="false"
    fi

    if [[ ${#string} -gt $max_lenght ]]; then
        error_msg "$validate_type" "$string" "$pretty_name should not exceed \e[1m$max_lenght\e[0m characters."

    elif [ -z "$string" ]; then
        error_msg "$validate_type" "$string" "$pretty_name cannot be empty"

    elif [[ "$1" =~ ^(username|branch)$ && "$string" =~ ^-.*$ ]]; then
        error_msg "$validate_type" "$string" "$pretty_name cannot have '-' character at start."
    fi

    # Check for invalid characters in the username
    if [[ "$string" =~ [[:space:]] ]]; then
        error_msg "$validate_type" "$string" "$pretty_name contains spaces which are \e[1;4;31mnot allowed\e[0m."
    elif [[ "$check_punctuations" == "true" && "$string" =~ [[:punct:]] ]]; then
        error_msg "$validate_type" "$string" "$pretty_name contains punctuation characters or emoji which are \e[1;4;31mnot allowed\e[0m."
    elif [[ "$string" =~ [[:cntrl:]] ]]; then
        error_msg "$validate_type" "$string" "$pretty_name contains control characters which are \e[1;4;31mnot allowed.\e[0m"
    elif [[ "$string" =~ [[:print:]] && ! "$string" =~ [[:graph:]] ]]; then
        error_msg "$validate_type" "$string" "$pretty_name contains non-printable characters which are \e[1;4;31mnot allowed.\e[0m"
    fi

    if [[ "$validate_type" == "URL" ]]; then
        if [[ ! $(echo "$string" | grep -E '^(http[s]|git@).*$') ]]; then
            error_msg "$validate_type" "$string" "Invalid URL, link can starts only with this protocols: '\e[1mhttp\e[0m', '\e[1mhttps\e[0m', ssh ('\e[1mgit@\e[0m')"
        fi
    fi
}

# Function to check if the repository exists
check_repo_exists() {
    if ! git ls-remote "$1" HEAD >/dev/null 2>&1; then
        echo -e "  Repository does not exist: \e[4m$repo_url\e[0m"
        echo ""
        exit 1
    fi
}

# Function to read a value from the dotload.conf file
read_declaration() {
    local declaration="$DOTFILES_DIR/dotload.conf"
    local key=$1
    local value=$(sed -n "s/.*$key=\([^ ]*\).*/\1/p" <"$declaration")
    echo "$value"
}

prompt() {
    local attempts=0
    local question="$1"

    while true; do
        if ((attempts == 4)); then
            echo -e "Too many invalid responses. Exiting program.\n"
            exit 1
        fi

        # shellcheck disable=SC2059
        printf "$question \e[1m(Y/n)\e[0m: "
        read -r response
        if echo "$response" | grep -Eiq '^(y|yes)$'; then
            return 1

        elif echo "$response" | grep -Eiq '^(n|no)$'; then
            return 0

        else
            if [ "$attempts" -lt 3 ]; then
                echo -e "\n\e[1;31mInvalid response\e[0m. Please enter '\e[1my\e[0m' or '\e[1mn\e[0m'."
                sleep "1"
            fi
            ((attempts++))
        fi
    done
    unset attempts
}

# Function to print informational messages
print_info() {
    echo -e "\e[1;32mⓘ  INFO:\e[0m $1"
}

# Function to print warning messages
warning() {
    echo -e "\e[33;5;7;1m⚠  WARNING:\e[0m $1"
}

# Function to print error messages
error() {
    echo -e "\e[1;31mERROR!\e[0m"
}

# Function to download and install dotfiles from a git repository
dotload() {
    local branch=""

    # Check if a branch is specified
    if [ -n "$2" ]; then
        if [[ "$2" == "--branch" || "$2" == "-b" ]]; then
            local specified_branch="$3"
        elif [[ -z "$3" && -n "$2" ]]; then
            local specified_branch="$2"
        fi

        # Validate the specified branch
        if [[ -n "$specified_branch" || -z "$specified_branch" ]]; then
            validate "branch" "$specified_branch"
            branch="--branch=$specified_branch"
        fi
    fi

    local username;
    local repo_url;
    local repo_name;

    if [[ $(echo "$1" | grep -E '^((http[s]://|^)(\S+\.\S+)*/|git@\S+\.\S+:)\S+/\S+(\.git|$)$') ]]; then
        if [[ $(echo "$1" | grep -E '^[a-zA-Z0-9-]+\.[a-zA-Z]+(/[a-zA-Z0-9-]+){2}(\.git|$)$') ]]; then
            # Append https
            repo_url="https://$1"
        else
            repo_url="$1"
        fi

        if [[ ! $repo_url =~ \.git$ ]]; then
            repo_url="$repo_url.git"
        fi

        validate "url" "$repo_url"

        username="$(echo "$repo_url" | sed -E 's@^.+/([^/]+)/.*$@\1@')"
        repo_name="$(echo "$repo_url" | sed -E 's@^.+/[^/]+/([^/.]+)\.git$@\1@')"

    elif [[ $(echo "$1" | grep -E '^@[^\s@]+(/\S+|$)$') ]]; then
        if [[ $(echo "$1" | grep -E '^@[^\s@]+/\S+$') ]]; then
            username=$(echo "$1" | cut -d '/' -f 1 | cut -d '@' -f 2)
            repo_name=$(echo "$1" | cut -d '/' -f 2)
        elif [[ $1 =~ ^@[^\s@]+$ ]]; then
            username=${1##*@}
            local repo_name="$DEFAULT_DOTFILES_REPO"
        fi

        repo_url="https://github.com/$username/$repo_name.git"
    fi

    # Validate the username
    validate "username" "$username"
    validate "repo_name" "$repo_name"

    # Check if dotfiles directory already exists and is up to date
    if [[ -d "$DOTFILES_DIR" && "$(git -C "$DOTFILES_DIR" remote get-url origin)" == "$repo_url" && -z $branch ]]; then
        warning "dotfiles for \e[1m@$username\e[0m already exists."
        local current_dir=$(pwd)
        cd "$DOTFILES_DIR"

        local branch=$(git rev-parse --abbrev-ref HEAD)
        local hash=$(git rev-parse --short=8 HEAD)

        echo -e "⊦ \e[1m@$username/$repo_name\e[0m"
        echo -e "⊦ Branch: $branch"
        echo -e "╰ Commit hash: $hash\n"

        unset hash
        unset branch

        cd "$current_dir"
        unset current_dir
    else
        # Check if the repository exists
        check_repo_exists "$repo_url"

        if [ -d "$DOTFILES_DIR" ]; then
            echo -e "Replacing dotfiles with user files \e[1m@$username\e[0m."
            rm -rf "$DOTFILES_DIR"
        else
            echo -e "Cloning \e[1m@$username\e[0m dotfiles to $DOTFILES_DIR"
        fi

        echo -e "⊦ \e[1m@$username/$repo_name\e[0m"
        if [ ! -z "$specified_branch" ]; then
            echo -e "⊦ Branch: $specified_branch"
        fi

        local hash=$(git ls-remote "$repo_url" HEAD | awk '{print $1}' | cut -c1-8)
        echo -e "╰ Commit hash: $hash\n"
        unset hash

        # shellcheck disable=SC2086
        git clone "$repo_url" "$DOTFILES_DIR" --quiet --depth=1 $branch >/dev/null 2>&1
    fi

    local custom_install_script

    # Solution for `git ls-files`: https://superuser.com/a/987438
    custom_install_script=$(git -C "$DOTFILES_DIR" ls-files | grep -E '^(((script/)?(bootstrap|setup)|install)(\.sh|$))$' | head -n 1)

    if [ -f "$DOTFILES_DIR/dotload.conf" ]; then
        if [ ! -z "$(read_declaration "installation_script")" ]; then
            # override automatically finded file
            custom_install_script=$(read_declaration "installation_script")
        fi

        local script_is_optional=""
        if [[ "$(read_declaration "script_is_optional")" == "true" ]]; then
            script_is_optional=" (optional)"
        fi
    fi

    # Run the custom install script if available
    if [ -n "$custom_install_script" ]; then
        print_info "Custom install script available.\a"

        prompt "↪  Do you want to execute the install script?$script_is_optional"
        if [[ $? -eq 1 ]]; then
            echo -e "Running install script ...\n"
            local current_dir=$(pwd)
            cd "$DOTFILES_DIR"

            bash "$custom_install_script"

            cd "$current_dir"
            unset current_dir

            echo ""
            echo -e "\e[1;32mDone!\e[0m"
            exit 0
        else
            echo -e "Canceled running of install script.\n"
            if [[ ! -n $script_is_optional ]]; then
                exit 0
            fi
        fi
    fi

    echo -e "[\e[1mSymlinking dotfiles from ~/.dotload to \$HOME directory\e[0m]\n"

    prompt "↪  You want to symlink your dotfiles to a \e[1m\$HOME\e[0m directory?"
    if [[ $? -eq 0 ]]; then
        echo "Action cancelled."
        exit 0
    fi

    echo ""

    # Symlink new dotfiles
    local current_dir=$(pwd)
    cd "$DOTFILES_DIR"

    for file in $(git ls-files "$DOTFILES_DIR" | grep -E '^\.'); do
        local dir=$(dirname "$HOME/$file")

        if [ ! -d "$dir" ]; then
            mkdir -p "$dir"
        fi

        printf "• Symlinking \e[1m%s\e[0m ..." "$file"
        local output="$(ln -sf "$DOTFILES_DIR/$file" "$HOME/$file")"
        if [[ $output -eq 0 ]]; then
            tput cub 3
            printf "\e[1;32m✓\e[0m  \n"
        else
            tput cub 3
            printf "\e[1;31m✕\e[0m  \n"
            echo -e "  \e[1;31mError\e[0m: $output"
        fi

        unset output
    done

    cd "$current_dir"
    unset current_dir

    echo ""
    echo -e "\e[1;32mDone!\e[0m"
}

print_usage() {
    echo "Usage: dotload [@username/[repo_name]] | <repo_url>] [branch]"
    echo ""
    echo "Options:"
    echo "  @username   The username of the GitHub user whose dotfiles you want to clone."
    echo "  [repo_name] (Optional) The name of the git repository from which you want to clone dotfiles."
    echo "              If not specified, the name \"dotfiles\" will be used by default"
    echo ""
    echo "  <repo_url>  The URL of the git repository from which you want to clone dotfiles."
    echo "  branch      (Optional) The branch of the repository you want to clone. If not specified, the default branch is used."
    echo ""
    echo "Examples:"
    echo "  dotload @username"
    echo "  dotload @username/dotfiles"
    echo "  dotload @username dev-branch"
    echo "  dotload https://github.com/username/dotfiles"
    echo "  dotload https://github.com/username/dotfiles dev-branch"
    echo ""
}


# Function to print the help information for the dotload script
print_dotload_help() {
    echo "dotload - A simple script to download dotfiles from a git repository"
    echo ""
    echo "Usage:"
    echo "  dotload @<username>/[repo_name] [--branch branch_name | -b branch_name]"
    echo "  dotload <repo_url> [--branch branch_name | -b branch_name]"
    echo ""
    echo "Options:"
    echo "  @<username>        The username of the GitHub user whose dotfiles you want to clone."
    echo "  [repo_name]        (Optional) The name of the git repository from which you want to clone dotfiles."
    echo "  <repo_url>         The URL of the git repository from which you want to clone dotfiles."
    echo "  [branch_name]      (Optional) The branch of the repository you want to clone. If not specified, the default branch is used."
    echo ""
    echo "Examples:"
    echo "  dotload @username"
    echo "  dotload @username/dotfiles"
    echo "  dotload @username dev-branch"
    echo "  dotload https://github.com/username/dotfiles.git"
    echo "  dotload https://github.com/username/dotfiles.git --branch main"
    echo ""
}

# Check if the script is invoked with no arguments or with help option
if [[ -z $1 || $1 == "--help" || $1 == "help" ]]; then
    print_usage

# Check if the script is invoked with a username
elif [[ $(echo "$1" | grep -E '^@[^\s@]+(/\S+|$)$') || $(echo "$1" | grep -E '^((http[s]://|^)(\S+\.\S+)*/|git@\S+\.\S+:)\S+/\S+(\.git|$)$') ]]; then
    if [[ $2 == "--help" ]]; then
        print_dotload_help
        exit 0
    fi
    dotload "$@"
else
    echo -e "Unknown command.\nSee '$0 --help'"
fi
