#!/usr/bin/env bash
# =============================================================
# Bash Alias Manager
# Filename: bash_alias_manager.sh
# Alias:    aliasmanager
#
# Manage ~/.bash_aliases interactively:
#   - Add, list, run, edit, and delete aliases
#   - Create new scripts from template
#   - First-run setup: scripts folder, .bashrc patch
#   - Safe: backup → validate → restore on failure
#
# Compatible with: Ubuntu, Linux Mint (bash shell)
# =============================================================

# --- Core files ----------------------------------------------
ALIAS_FILE="$HOME/.bash_aliases"
BASHRC="$HOME/.bashrc"
BACKUP="$HOME/.bash_aliases.bck"
CONFIG_FILE="$HOME/.config/newalias.conf"

# --- Colors --------------------------------------------------
YELLOW="\e[33m"
GREEN="\e[32m"
RED="\e[31m"
CYAN="\e[36m"
RESET="\e[0m"

# =============================================================
# FIRST-RUN SETUP
# =============================================================

setup() {
    echo -e "${CYAN}=== Bash Alias Manager — First-Run Setup ===${RESET}"
    echo

    # --- Ask scripts folder ----------------------------------
    echo "Where do you want to store your scripts?"
    echo "Press Enter to use default: ~/scripts"
    read -rp "Scripts folder: " input_dir
    [ -z "$input_dir" ] && input_dir="$HOME/scripts"

    local scripts_dir
    scripts_dir="${input_dir/#\~/$HOME}"

    if [ ! -d "$scripts_dir" ]; then
        mkdir -p "$scripts_dir" && \
            echo -e "${GREEN}Created: $scripts_dir${RESET}" || {
            echo -e "${RED}Failed to create $scripts_dir — aborting.${RESET}"
            exit 1
        }
    fi

    # --- Ensure ~/.bash_aliases exists -----------------------
    [ -f "$ALIAS_FILE" ] || touch "$ALIAS_FILE"

    # --- Patch ~/.bashrc if needed ---------------------------
    local patch='if [ -f ~/.bash_aliases ]; then . ~/.bash_aliases; fi'
    if ! grep -qF ".bash_aliases" "$BASHRC"; then
        echo "" >> "$BASHRC"
        echo "# Load aliases" >> "$BASHRC"
        echo "$patch" >> "$BASHRC"
        echo -e "${GREEN}Patched ~/.bashrc to load ~/.bash_aliases${RESET}"
    else
        echo -e "${GREEN}~/.bashrc already loads ~/.bash_aliases — no change needed.${RESET}"
    fi

    # --- Add aliasmanager shell function for this script ------
    # A function (not alias) is used so that after the script exits,
    # ~/.bash_aliases is sourced automatically in the current shell.
    local self_path
    self_path="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/$(basename "${BASH_SOURCE[0]}")"

    if ! grep -qF "aliasmanager()" "$ALIAS_FILE"; then
        {
            echo ""
            echo "# Bash Alias Manager — reloads aliases after each run"
            echo "aliasmanager() { \"$self_path\" \"\$@\" && source ~/.bash_aliases; }"
        } >> "$ALIAS_FILE"
        echo -e "${GREEN}Added function: aliasmanager → $self_path${RESET}"
    fi

    # --- Save config -----------------------------------------
    mkdir -p "$(dirname "$CONFIG_FILE")"
    echo "SCRIPTS_DIR=$scripts_dir" > "$CONFIG_FILE"
    echo -e "${GREEN}Config saved: $CONFIG_FILE${RESET}"
    echo
    echo -e "${YELLOW}Setup complete. Run:  source ~/.bash_aliases${RESET}"
    echo
}

load_config() {
    if [ ! -f "$CONFIG_FILE" ]; then
        setup
    fi

    # Read config manually — never source untrusted files
    local raw
    raw=$(grep "^SCRIPTS_DIR=" "$CONFIG_FILE" | head -1 | cut -d'=' -f2-)
    raw="${raw/#\~/$HOME}"

    # Reject paths with shell metacharacters
    if [[ -z "$raw" || "$raw" =~ [\;\|\&\`\$\(\)\<\>] ]]; then
        echo -e "${RED}Config file looks corrupt or tampered: $CONFIG_FILE${RESET}"
        echo "Delete it and run the script again to redo setup."
        exit 1
    fi

    SCRIPTS_DIR="$raw"
}

# =============================================================
# HELPERS
# =============================================================

backup_aliases() {
    cp "$ALIAS_FILE" "$BACKUP" || {
        echo -e "${RED}Backup failed — aborting.${RESET}"
        exit 1
    }
}

restore_aliases() {
    cp "$BACKUP" "$ALIAS_FILE"
    echo -e "${YELLOW}Backup restored.${RESET}"
}

validate_aliases() {
    bash -n "$ALIAS_FILE"
}

log_aliases() {
    local logfile
    logfile="$(dirname "$CONFIG_FILE")/bash-alias-log.txt"
    grep "^alias " "$ALIAS_FILE" > "$logfile"
}

expand_path() {
    echo "${1/#\~/$HOME}"
}

make_exec() {
    chmod +x "$1" || \
        echo -e "${YELLOW}Warning: could not chmod +x $1 — continuing anyway.${RESET}"
}

alias_exists() {
    grep -qF "alias $1=" "$ALIAS_FILE"
}

remove_alias() {
    local escaped
    escaped=$(printf '%s\n' "$1" | sed 's/[[\.*^$()+?{|]/\\&/g')
    sed -i "/^alias ${escaped}=/d" "$ALIAS_FILE"
}

get_script_path_for_alias() {
    local alias_line="$1"
    echo "$alias_line" | sed 's/^alias [^=]*="\(.*\)"$/\1/'
}

# =============================================================
# ADD ALIAS
# =============================================================

add_alias() {
    echo -e "${YELLOW}=== Add Alias ===${RESET}"
    backup_aliases

    read -rp "Alias name: " name

    if [[ -z "$name" ]]; then
        echo -e "${RED}Name cannot be empty.${RESET}"
        return
    fi
    if [[ ! "$name" =~ ^[a-zA-Z0-9_-]+$ ]]; then
        echo -e "${RED}Invalid name. Use only letters, digits, _ or -.${RESET}"
        return
    fi

    echo "Script path (Enter = $SCRIPTS_DIR):"
    read -r raw_path
    [ -z "$raw_path" ] && raw_path="$SCRIPTS_DIR"

    local path_expanded
    path_expanded=$(expand_path "$raw_path")

    if [ -d "$path_expanded" ]; then
        path_expanded="${path_expanded%/}/$name"
    fi

    if [ ! -f "$path_expanded" ]; then
        echo -e "${RED}File not found: $path_expanded${RESET}"
        return
    fi

    make_exec "$path_expanded"

    if alias_exists "$name"; then
        echo -e "${YELLOW}Alias '$name' already exists — overwriting.${RESET}"
        remove_alias "$name"
    fi

    echo "alias ${name}=\"${path_expanded}\"" >> "$ALIAS_FILE"

    if validate_aliases; then
        log_aliases
        echo -e "${GREEN}Done. Run:  source ~/.bash_aliases${RESET}"
    else
        restore_aliases
        echo -e "${RED}Syntax error — alias file restored from backup.${RESET}"
    fi
}

# =============================================================
# CREATE NEW SCRIPT
# =============================================================

create_script() {
    echo -e "${YELLOW}=== Create New Script ===${RESET}"

    read -rp "Script name (without .sh): " name

    if [[ -z "$name" ]]; then
        echo -e "${RED}Name cannot be empty.${RESET}"
        return
    fi
    if [[ ! "$name" =~ ^[a-zA-Z0-9_-]+$ ]]; then
        echo -e "${RED}Invalid name. Use only letters, digits, _ or -.${RESET}"
        return
    fi

    local script_path="$SCRIPTS_DIR/${name}.sh"

    if [ -f "$script_path" ]; then
        echo -e "${RED}File already exists: $script_path${RESET}"
        return
    fi

    # Write minimal template
    printf '#!/usr/bin/env bash\n' > "$script_path"
    make_exec "$script_path"
    echo -e "${GREEN}Created: $script_path${RESET}"

    # Offer to create alias
    read -rp "Create alias '$name' for this script? [Y/n]: " yn
    if [[ -z "$yn" || "$yn" =~ ^[Yy]$ ]]; then
        backup_aliases

        if alias_exists "$name"; then
            echo -e "${YELLOW}Alias '$name' already exists — overwriting.${RESET}"
            remove_alias "$name"
        fi

        echo "alias ${name}=\"${script_path}\"" >> "$ALIAS_FILE"

        if validate_aliases; then
            log_aliases
            echo -e "${GREEN}Alias added — reloading aliases...${RESET}"
            echo -e "${YELLOW}Run:  source ~/.bash_aliases${RESET}"
        else
            restore_aliases
            echo -e "${RED}Syntax error — alias file restored from backup.${RESET}"
        fi
    fi

    # Offer to open in editor
    read -rp "Open in editor now? [Y/n]: " ed
    if [[ -z "$ed" || "$ed" =~ ^[Yy]$ ]]; then
        ${EDITOR:-nano} "$script_path"
    fi
}

# =============================================================
# LIST / RUN / EDIT / DELETE
# =============================================================

list_aliases() {
    echo -e "${YELLOW}=== Alias List ===${RESET}"

    mapfile -t aliases < <(grep "^alias " "$ALIAS_FILE")

    if [ ${#aliases[@]} -eq 0 ]; then
        echo "No aliases defined."
        return
    fi

    for i in "${!aliases[@]}"; do
        echo -e "${GREEN}[$((i+1))]${RESET} ${aliases[$i]}"
    done

    echo
    echo "Enter number       → RUN the script"
    echo "Enter e<number>    → EDIT script   (e.g. e2)"
    echo "Enter d<number>    → DELETE alias  (e.g. d3)"
    echo "Enter nothing      → exit"
    read -rp "Choice: " choice

    [ -z "$choice" ] && return

    # --- DELETE ---
    if [[ "$choice" =~ ^d([0-9]+)$ ]]; then
        local num="${BASH_REMATCH[1]}"
        if (( num >= 1 && num <= ${#aliases[@]} )); then
            local alias_line="${aliases[$((num-1))]}"
            local alias_name
            alias_name=$(echo "$alias_line" | sed 's/^alias \([^=]*\)=.*/\1/')

            backup_aliases
            remove_alias "$alias_name"

            if validate_aliases; then
                log_aliases
                echo -e "${GREEN}Deleted: $alias_name${RESET}"
                echo "Run:  source ~/.bash_aliases"
            else
                restore_aliases
                echo -e "${RED}Delete failed — alias file restored from backup.${RESET}"
            fi
        else
            echo -e "${RED}Invalid number.${RESET}"
        fi
        return
    fi

    # --- EDIT ---
    if [[ "$choice" =~ ^e([0-9]+)$ ]]; then
        local num="${BASH_REMATCH[1]}"
        if (( num >= 1 && num <= ${#aliases[@]} )); then
            local alias_line="${aliases[$((num-1))]}"
            local cmd
            cmd=$(get_script_path_for_alias "$alias_line")

            if [ -z "$cmd" ]; then
                echo -e "${RED}Could not parse script path.${RESET}"
                return
            fi
            if [ ! -f "$cmd" ]; then
                echo -e "${RED}Script file not found: $cmd${RESET}"
                return
            fi

            echo -e "${GREEN}Opening: $cmd${RESET}"
            ${EDITOR:-nano} "$cmd"
        else
            echo -e "${RED}Invalid number.${RESET}"
        fi
        return
    fi

    # --- RUN ---
    if [[ "$choice" =~ ^[0-9]+$ ]]; then
        if (( choice >= 1 && choice <= ${#aliases[@]} )); then
            local alias_line="${aliases[$((choice-1))]}"
            local cmd
            cmd=$(get_script_path_for_alias "$alias_line")

            if [ -z "$cmd" ]; then
                echo -e "${RED}Could not parse command for alias.${RESET}"
                return
            fi

            echo -e "${GREEN}Running: $cmd${RESET}"
            bash "$cmd"
        else
            echo -e "${RED}Invalid number.${RESET}"
        fi
    else
        echo -e "${RED}Invalid input.${RESET}"
    fi
}

# =============================================================
# MAIN
# =============================================================

main() {
    load_config

    echo -e "${YELLOW}=== Bash Alias Manager ===${RESET}"
    echo "1) Add alias"
    echo "2) List / Run / Edit / Delete"
    echo "3) Create new script"
    echo
    read -rp "Choose: " opt

    case "$opt" in
        1) add_alias ;;
        2) list_aliases ;;
        3) create_script ;;
        *) echo -e "${RED}Invalid option.${RESET}" ;;
    esac
}

main
