#!/bin/bash
#
# LibrePortal Initialization Script
#
# Usage: ./init.sh [OPTIONS] init [password] [git_user] [git_token] [git_url] [unattended] [install_mode]
#
# OPTIONS:
#   --random-password    Generate a random password automatically
#   --local             Use local folder installation automatically
#   --unattended        Run in unattended mode (skip confirmations)
#   --skip-os-update    Skip operating system update
#   --skip-prereqs      Skip installing prerequisite apps
#
# Examples:
#   ./init.sh --random-password --local init
#   ./init.sh --random-password --local --unattended init
#   ./init.sh --random-password --local --skip-os-update --skip-prereqs init
#   ./init.sh init mypassword myuser mytoken https://github.com/user/repo.git
#

RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
BLUE='\033[0;34m'
NC='\033[0m'

isSuccessful() { echo -e "${GREEN}✓ Success${NC} $1"; }
isError()      { echo -e "${RED}✗ Error${NC} $1"; }
isNotice()     { echo -e "${YELLOW}! Notice${NC} $1"; }
isQuestion()   { echo -e -n "${BLUE}❯ Question${NC} $1 "; }

displayLibrePortalLogo() {
    local hbar; hbar=$(printf '═%.0s' $(seq 1 50))
    printf '\n╔%s╗\n' "$hbar"
    printf '║%6s%s%8s║\n' '' '╦  ┬┌┐ ┬─┐┌─┐  ╭─╮  ╔═╗┌─┐┬─┐┌┬┐┌─┐┬' ''
    printf '║%6s%s%8s║\n' '' '║  │├┴┐├┬┘├┤   │◉│  ╠═╝│ │├┬┘ │ ├─┤│' ''
    printf '║%6s%s%6s║\n' '' '╩═╝┴└─┘┴└─└─┘  ╨─╨  ╩  └─┘┴└─ ┴ ┴ ┴┴─┘' ''
    printf '╚%s╝\n\n' "$hbar"
}

init_action="$1"
for arg in "$@"; do
    case "$arg" in --*) ;; *) init_action="$arg"; break ;;
    esac
done
if [[ "${BASH_SOURCE[0]}" == "$0" ]] \
    && [[ "$init_action" == "init" ]] \
    && [[ "$LIBREPORTAL_SKIP_LOGO" != "1" ]]; then
    displayLibrePortalLogo
fi
unset init_action

checkSuccess() {
    if [ $? -eq 0 ]; then
        isSuccessful "$1"
    else
        isError "$1"
        exit 1
    fi
}

isHeader() {
    local title="$1"
    local width=52
    local inner=$((width - 2))
    local title_len=${#title}
    local total_pad=$((inner - title_len))
    if (( total_pad < 0 )); then total_pad=0; fi
    local left_pad=$((total_pad / 2))
    local right_pad=$((total_pad - left_pad))
    local hbar
    hbar=$(printf '═%.0s' $(seq 1 "$inner"))
    printf '\n╔%s╗\n' "$hbar"
    printf '║%*s%s%*s║\n' "$left_pad" '' "$title" "$right_pad" ''
    printf '╚%s╝\n\n' "$hbar"
}

# Original parameters for backward compatibility
param1="$1" # init to start script
param2="$2" # password
param3="$3" # git user
param4="$4" # git token
param5="$5" # git url
param6="$6" # unattended
param7="$7" # install mode (git/local)

# Parse command line arguments
init_random_password=false
init_local_install=false
init_unattended_mode=false
init_skip_os_update=false
init_skip_prereqs=false

install_param="init"
sudo_user_name=libreportal
sshd_config="/etc/ssh/sshd_config"
sudo_bashrc="/home/$sudo_user_name/.bashrc"
hosts_file="/etc/hosts"
hostname_file="/etc/hostname"
fqdn_file="/root/libreportal-fqdn.txt"
command_script="/usr/local/bin/libreportal"

# Directories
docker_dir="/docker"
containers_dir="$docker_dir/containers/"
ssl_dir="$docker_dir/ssl/"
ssh_dir="$docker_dir/ssh/"
wireguard_dir="$docker_dir/wireguard/"
logs_dir="$docker_dir/logs/"
configs_dir="$docker_dir/configs/"
backup_dir="$docker_dir/backups"
restore_dir="$docker_dir/restore"
migrate_dir="$docker_dir/migrate"
# Install Scripts
script_dir="$docker_dir/install"
install_configs_dir="$script_dir/configs/"
install_containers_dir="$script_dir/containers/"
install_scripts_dir="$script_dir/scripts/"

# Parse flags
init_shift_count=0
for ((i=1; i<=$#; i++)); do
    case "${!i}" in
        --random-password)
            init_random_password=true
            ((init_shift_count++))
            ;;
        --local)
            init_local_install=true
            ((init_shift_count++))
            ;;
        --unattended)
            init_unattended_mode=true
            ((init_shift_count++))
            ;;
        --skip-os-update)
            init_skip_os_update=true
            ((init_shift_count++))
            ;;
        --skip-prereqs)
            init_skip_prereqs=true
            ((init_shift_count++))
            ;;
    esac
done

# Shift parsed flags to get positional parameters
if [ $init_shift_count -gt 0 ]; then
    for ((i=1; i<=init_shift_count; i++)); do
        shift
done
    # Reset positional parameters after shifting flags
    param1="$1" # init to start script
    param2="$2" # password
    param3="$3" # git user
    param4="$4" # git token
    param5="$5" # git url
    param6="$6" # unattended
    param7="$7" # install mode (git/local)
fi

# Apply flag logic
if [ "$init_random_password" = true ]; then
    param2=$(openssl rand -base64 12 | tr -d '\n')
    isSuccessful "Generated password: $param2"
fi

if [ "$init_local_install" = true ]; then
    param7="local"
fi

# Auto-detect installation mode based on provided parameters
if [[ -z "$param7" ]]; then
    # A reinstall that doesn't re-pass the git args must not silently
    # downgrade an existing git install to local (that disables the updater
    # and blanks the saved creds). Honor a git URL already saved from a
    # prior install — only fall back to local when there's no git history.
    saved_git_url=$(grep -E '^CFG_GIT_URL=' /docker/configs/general/general_install 2>/dev/null \
                    | sed -E 's/^[^=]+=([^[:space:]#]*).*/\1/')
    if [[ -n "$param3" || -n "$param4" || -n "$param5" ]]; then
        # Git parameters provided, set to git mode
        param7="git"
        isSuccessful "Auto-detected Git installation mode (git args provided)"
    elif [[ -n "$saved_git_url" && "$saved_git_url" != "changeme" && "$saved_git_url" != "empty" ]]; then
        # No git args this run, but a prior git install is on disk — keep it
        param7="git"
        isSuccessful "Auto-detected Git installation mode (existing git config detected)"
    else
        # No git parameters and no prior git config, set to local mode
        param7="local"
        isSuccessful "Auto-detected Local installation mode"
    fi
fi


initUpdateConfigOption() {
    local config_option="$1"
    local config_value="$2"
    local config_file=""

    for category_dir in "$configs_dir"/*; do
        if [ -d "$category_dir" ] && [ -f "$category_dir/.category" ]; then
            for config_file in "$category_dir"/*; do
                if [ -f "$config_file" ] && [[ ! "$config_file" =~ \.category$ ]]; then
                    if grep -q "^$config_option=" "$config_file"; then
                        local escaped_value=$(printf '%s\n' "$config_value" | sed -e 's/[\/&]/\\&/g')
                        local original_line=$(grep "^$config_option=" "$config_file")
                        local comment_part=$(echo "$original_line" | sed -n "s|^$config_option=[^#]*\(#.*\)|\1|p")

                        if [[ -n "$comment_part" ]]; then
                            sudo sed -i "s|^$config_option=.*|$config_option=$escaped_value                     $comment_part|" "$config_file"
                        else
                            sudo sed -i "s|^$config_option=.*|$config_option=$escaped_value|" "$config_file"
                        fi
                        source "$config_file"
                        return 0
                    fi
                fi
            done
        fi
    done

    return 1
}

if [[ -n "$param7" && -f "${configs_dir}general/general_install" ]]; then
    initUpdateConfigOption "CFG_INSTALL_MODE" "$param7"
fi

if [ "$init_unattended_mode" = true ]; then
    param6="true"
fi

if [ "$init_skip_os_update" = true ]; then
    isNotice "Skipping operating system update"
fi

if [ "$init_skip_prereqs" = true ]; then
    isNotice "Skipping prerequisite apps installation"
fi

# Get script directory for local installation (only if needed)
if [ "$init_local_install" = true ]; then
    init_script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
    isNotice "Using script directory for local installation: $init_script_dir"
fi

detectLocalLibrePortal() {
    local check_dir
    
    # If --local flag is used, check script directory, otherwise check current directory
    if [ "$init_local_install" = true ]; then
        check_dir="$init_script_dir"
        echo "Checking script directory for LibrePortal structure..."
    else
        check_dir="$(pwd)"
        echo "Checking current directory for LibrePortal structure..."
    fi
    
    local required_dirs=("configs" "scripts" "containers")
    local required_files=("init.sh" "start.sh")
    local missing_count=0
    
    # Check for required directories
    for dir in "${required_dirs[@]}"; do
        if [[ ! -d "$check_dir/$dir" ]]; then
            echo "  Missing directory: $dir"
            ((missing_count++))
        fi
    done
    
    # Check for required files
    for file in "${required_files[@]}"; do
        if [[ ! -f "$check_dir/$file" ]]; then
            echo "  Missing file: $file"
            ((missing_count++))
        fi
    done
    
    if [[ $missing_count -eq 0 ]]; then
        echo "Valid LibrePortal structure detected in $check_dir"
		echo ""
        return 0
    else
        isNotice "Warning: $missing_count required items missing. Not a valid LibrePortal source."
        return 1
    fi
}

copyFilesFromLocal() {
    local source_dir
    
    # If --local flag is used, use script directory, otherwise use current directory
    if [ "$init_local_install" = true ]; then
        source_dir="$init_script_dir"
    else
        source_dir="$(pwd)"
    fi
    
    isHeader "Copying from Local Directory"
    
    # Remove existing install directory
    sudo rm -rf "$script_dir"
    
    # Create install directory
    sudo mkdir -p "$script_dir"
    
    isNotice "Copying files from $source_dir to $script_dir..."
    
    # Copy all files while preserving structure
    if sudo cp -r "$source_dir"/* "$script_dir/" 2>/dev/null; then
        sudo cp -f "$script_dir/init.sh" /root/
        setupConfigsFromRepo
        sudo chown -R $sudo_user_name:$sudo_user_name "$script_dir"
        isSuccessful "Files copied from local directory to '$script_dir'."
    else
        isError "Failed to copy files from local directory."
        exit 1
    fi
}

resetConfigVars() {
    param2=""
    param3=""
    param4=""
    param5=""
    param7=""
    GIT_USER=""
    GIT_TOKEN=""
    GIT_URL=""
    INSTALL_MODE=""
}

initCheckConfigs() {
    # Check if any config files exist (new structure) or old config files
    local config_found=false
    
    # Check for new structure
    if [ -d "$configs_dir" ]; then
        for category_dir in "$configs_dir"/*; do
            if [ -d "$category_dir" ] && [ -f "$category_dir/.category" ]; then
                # Load new structure config files
                for config_file in "$category_dir"/*; do
                    local should_load=true
                    local filename=$(basename "$config_file")
                    # Skip .category files and excluded files (hardcoded)
                    if [[ "$config_file" =~ \.category$ ]]; then
                        should_load=false
                    fi
                    
                    if [ "$should_load" = true ]; then
                        source "$config_file"
                        config_found=true
                    fi
                done
            fi
        done
    fi
    
    if [ "$config_found" = false ]; then
        isNotice "Configuration files do not exist, skipping init check"
        return
    fi

    get_cfg() {
        local var_name="$1"
        local var_value="${!var_name}"
        echo "$var_value"
    }

    [[ -z "$param2" ]] && param2=$(get_cfg CFG_LIBREPORTAL_USER_PASS)
    [[ -z "$param3" ]] && param3=$(get_cfg CFG_GIT_USER)
    [[ -z "$param4" ]] && param4=$(get_cfg CFG_GIT_KEY)
    [[ -z "$param5" ]] && param5=$(get_cfg CFG_GIT_URL)
    [[ -z "$param7" ]] && param7=$(get_cfg CFG_INSTALL_MODE)

    [[ "$param2" == "changeme" ]] && param2=""
    [[ "$param3" == "changeme" ]] && param3=""
    [[ "$param4" == "changeme" ]] && param4=""
    [[ "$param5" == "changeme" ]] && param5=""
    [[ "$param7" == "changeme" ]] && param7=""
}

validateUnattended() {
    if [[ -z "$param2" ]]; then
        isError "Password is required in unattended mode"
        exit 1
    fi

    # If install mode is not specified, default to git
    if [[ -z "$param7" ]]; then
        param7="git"
    fi

    # For git installation, validate git parameters
    if [[ "$param7" == "git" ]]; then
        if [[ -z "$param5" ]]; then
            isError "Git repository URL is required in unattended mode"
            exit 1
        fi

        if [[ -z "$param3" ]]; then
            param3="empty"
            param4="empty"
        fi

        if [[ "$param3" != "empty" && -z "$param4" ]]; then
            param4="empty"
        fi
    fi
}

initInputQuestions() {
    ### PASSWORD
    if [[ -z "$param2" ]]; then
        while true; do
            echo ""
            echo "LibrePortal User Password"
            read -p "Use custom (c) or randomized (r) password? (c/r): " choice

            case "$choice" in
                c)
                    read -p "Enter custom password: " param2
                    [[ -z "$param2" ]] && echo "Password cannot be empty." || break
                    ;;
                r)
                    param2=$(openssl rand -base64 12)
                    isSuccessful "Generated password: $param2"
                    break
                    ;;
                *)
                    echo "Invalid option. Enter c or r."
                    ;;
            esac
        done
    fi

    ### INSTALLATION METHOD
    if [[ -z "$param7" ]]; then
        echo ""
        echo "Installation Method:"
        
        # Check if local installation is available
        if detectLocalLibrePortal; then
            echo "1) Install from Git repository"
            echo "2) Install from local folder (current directory)"
            echo ""
            while true; do
                read -p "Choose option [1-2]: " install_choice
                case "$install_choice" in
                    1)
                        param7="git"
                        echo "Using Git repository installation."
                        break
                        ;;
                    2)
                        param7="local"
                        echo "Using local folder installation."
                        break
                        ;;
                    *)
                        echo "Invalid option. Choose 1 or 2."
                        ;;
                esac
            done
        else
            echo "Local installation not available - missing required files/directories."
            echo "Defaulting to Git repository installation."
            param7="git"
        fi
    fi

    ### GIT USER (only for git installation)
    if [[ "$param7" == "git" && -z "$param3" ]]; then
        echo ""
        echo "Git Authentication Method:"
        echo "1) Login required (username + token)"
        echo "2) Authenticationless (public repos / SSH keys)"
        echo ""
        while true; do
            read -p "Choose option [1-2]: " git_auth_choice
            case "$git_auth_choice" in
                1)
                    read -p "Enter Git username: " param3
                    if [[ -z "$param3" ]]; then
                        echo "Username cannot be empty for login authentication."
                    else
                        break
                    fi
                    ;;
                2)
                    param3="empty"
                    param4="empty"
                    echo "Using authenticationless Git access."
                    break
                    ;;
                *)
                    echo "Invalid option. Choose 1 or 2."
                    ;;
            esac
        done
    fi

    ### GIT TOKEN (only for git installation)
    if [[ "$param7" == "git" && "$param3" != "empty" && -z "$param4" ]]; then
        read -p "Enter Git token: " param4
        [[ -z "$param4" ]] && param4="empty"
    fi

    ### GIT URL (only for git installation)
    if [[ "$param7" == "git" && -z "$param5" ]]; then
        while true; do
            echo ""
            read -p "Enter Git repository URL: " param5
            [[ -z "$param5" ]] && echo "Git repository URL is required." || {
                # Validate and fix Git URL
                param5=$(validateAndFixGitUrl "$param5")
                echo "Using Git URL: $param5"
                break
            }
        done
    elif [[ "$param7" == "git" ]]; then
        # Also validate URL if provided as parameter
        param5=$(validateAndFixGitUrl "$param5")
        echo "Using Git URL: $param5"
    fi
}

cleanGitUrl() {
    local url="$1"
    url="${url#"${url%%[![:space:]]*}"}"
    url="${url%"${url##*[![:space:]]}"}"
    url="${url#https://}"
    url="${url#http://}"
    while [[ "$url" == */ ]]; do url="${url%/}"; done
    url="${url%.git}"
    echo "$url"
}

validateAndFixGitUrl() {
    local url="$1"
    url="${url#"${url%%[![:space:]]*}"}"
    url="${url%"${url##*[![:space:]]}"}"
    echo "$url"
}

initReloadConfigs() {
    for category_dir in "$configs_dir"/*; do
        if [ -d "$category_dir" ] && [ -f "$category_dir/.category" ]; then
            for config_file in "$category_dir"/*; do
                if [ -f "$config_file" ] && [[ ! "$config_file" =~ \.category$ ]]; then
                    source "$config_file"
                fi
            done
        fi
    done
    
    # Check old config files (backward compatibility)
    for config_file in "$configs_dir"/config_*; do
        if [ -f "$config_file" ]; then
            source "$config_file"
        fi
    done
}

writeConfig()
{
    # Defer config writes until the repo is cloned and /docker/configs is
    # populated by setupConfigsFromRepo. On a fresh install the file
    # below doesn't exist yet — initUpdateConfigs at the end of init.sh
    # is what actually persists everything.
    if [[ ! -f "${configs_dir}general/general_install" ]]; then
        return 0
    fi

    [[ -n "$param2" ]] && initUpdateConfigOption "CFG_LIBREPORTAL_USER_PASS" "$param2"
    [[ -n "$param3" ]] && initUpdateConfigOption "CFG_GIT_USER"             "$param3"
    [[ -n "$param4" ]] && initUpdateConfigOption "CFG_GIT_KEY"              "$param4"
    [[ -n "$param5" ]] && initUpdateConfigOption "CFG_GIT_URL"              "$param5"
    [[ -n "$param7" ]] && initUpdateConfigOption "CFG_INSTALL_MODE"         "$param7"
}


initDisplayConfig() 
{
    GIT_USER="$param3"
    GIT_TOKEN="$param4"
    GIT_URL="$param5"
    INSTALL_MODE="$param7"

    isHeader "Configuration Summary"
    isNotice "LibrePortal User Password: [HIDDEN]"

    if [[ "$INSTALL_MODE" == "local" ]]; then
        isNotice "Git Username: [NOT APPLICABLE]"
        isNotice "Git Token: [NOT APPLICABLE]"
    else
        [[ "$GIT_USER" == "empty" ]] \
            && isNotice "Git Username: [DISABLED]" \
            || isNotice "Git Username: $GIT_USER"

        [[ "$GIT_TOKEN" == "empty" ]] \
            && isNotice "Git Token: [DISABLED]" \
            || isNotice "Git Token: [HIDDEN]"
    fi

    [[ "$INSTALL_MODE" == "local" ]] \
        && isNotice "Installation Mode: Local Folder" \
        || isNotice "Installation Mode: Git Repository"

    if [[ "$INSTALL_MODE" != "local" ]]; then
        isNotice "Git URL: $GIT_URL"
    fi
    echo ""

    if [[ "$param6" == "true" || "$param6" == "1" ]]; then
        isNotice "Unattended mode enabled — auto-accepting configuration"
        writeConfig
    fi

    if [[ "$INSTALL_MODE" != "local" ]]; then
        read -p "Are these details correct? (y/n): " confirm
    else
        confirm=y
    fi

    if [[ "$confirm" != "y" ]]; then
        echo "Restarting configuration.."
        resetConfigVars
        initCheckConfigs
        initInputQuestions
        initDisplayConfig
    else
        writeConfig
        isSuccessful "Configuration saved."
    fi
}

initOS()
{
	isHeader "Updating Operating System"
	apt-get install sudo -y
	sudo apt-get update
	sudo apt-get dist-upgrade -y
	echo ""
	isSuccessful "OS Updated"
}

initPrerequires()
{
	isHeader "Installing Prerequired Apps"
	# apache2-utils → htpasswd, used by hashPassword for fast local bcrypt.
	sudo apt-get install git zip curl sshpass dos2unix dnsutils apt-transport-https ca-certificates software-properties-common uidmap adduser apache2-utils restic -y
	TARGET_PATH="/usr/local/bin"
	CONFIG_FILE="$HOME/.bashrc"
	if ! echo "$PATH" | grep -q "$TARGET_PATH"; then
		echo "Adding $TARGET_PATH to PATH..."
		echo "export PATH=\$PATH:$TARGET_PATH" >> "$CONFIG_FILE"
		source "$CONFIG_FILE"
		echo "PATH updated successfully!"
	else
		echo "$TARGET_PATH is already in PATH."
	fi
	isSuccessful "Prerequisite apps installed."
}

initDocker()
{
	isHeader "Installing Docker"
	if command -v docker &> /dev/null; then
		isSuccessful "Docker is already installed."
	else
		curl -fsSL https://get.docker.com | sh
		systemctl start docker
		systemctl enable docker
		isSuccessful "Docker has been installed successfully."
	fi
}

initUsers()
{
	isHeader "Creating User Accounts"
	if id "$sudo_user_name" &>/dev/null; then
		isSuccessful "User $sudo_user_name already exists."
	else
		sudo useradd -s /bin/bash -d "/home/$sudo_user_name" -m -G sudo "$sudo_user_name" 2>/dev/null
		isNotice "Setting password for $sudo_user_name user."
		echo "$sudo_user_name:$param2" | sudo chpasswd
		sudo usermod -aG docker "$sudo_user_name"
		sudo systemctl restart docker
		isSuccessful "User $sudo_user_name created successfully."
	fi
	# Manager-user sudo lives in a validated /etc/sudoers.d drop-in, not appended
	# to /etc/sudoers — a malformed line in the main file locks out sudo entirely.
	# The grant is broad for now; this single drop-in is what gets tightened to a
	# scoped command allowlist once the runtime no longer needs broad root.
	local sudoers_dropin="/etc/sudoers.d/${sudo_user_name}"
	local sudoers_tmp
	sudoers_tmp=$(mktemp)
	printf '%s ALL=(ALL) NOPASSWD: ALL\n' "$sudo_user_name" > "$sudoers_tmp"
	if sudo visudo -cf "$sudoers_tmp" >/dev/null 2>&1; then
		sudo install -m 0440 -o root -g root "$sudoers_tmp" "$sudoers_dropin"
		isSuccessful "Configured passwordless sudo for $sudo_user_name (/etc/sudoers.d/${sudo_user_name})."
	else
		isError "Refusing to install an invalid sudoers drop-in for $sudo_user_name."
	fi
	rm -f "$sudoers_tmp"
}

initFolders()
{
	isHeader "LibrePortal Folder Creation"
	folders=("$docker_dir" "$containers_dir" "$ssl_dir" "$ssh_dir" "$wireguard_dir" "$logs_dir" "$configs_dir" "$backup_dir" "$restore_dir" "$migrate_dir" "$script_dir")
	for folder in "${folders[@]}"; do
		if [ ! -d "$folder" ]; then
			sudo mkdir "$folder"
			sudo chown $sudo_user_name:$sudo_user_name "$folder"
			sudo chmod 750 "$folder"
			isSuccessful "Folder '$folder' created."
		fi
	done
	isSuccessful "All folders have been created."
}

setupConfigsFromRepo()
{
    isNotice "Setting up configuration files from repository..."

    local src="$script_dir/configs"
    local dst="/docker/configs"

    if [[ ! -d "$src" ]]; then
        isError "Source configs directory missing: $src"
        isError "The clone in $script_dir didn't include a configs/ tree — aborting."
        exit 1
    fi

    sudo mkdir -p "$dst"

    # No-clobber: only seed config files that don't already exist. On a fresh
    # install this copies the whole template; on a re-run/deploy it preserves the
    # user's live values (a plain cp -a here silently reset e.g. the Docker
    # install type back to the template default). New *keys* in existing files
    # are added separately by the add-only reconcile pass.
    if ! sudo cp -an "$src"/. "$dst"/; then
        isError "Failed to copy configs from $src to $dst — aborting."
        exit 1
    fi
    sudo chown -R "$sudo_user_name":"$sudo_user_name" "$dst"

    if [[ ! -f "$dst/general/general_install" ]]; then
        isError "Configs were copied but $dst/general/general_install is missing."
        isError "Repository layout may have changed — fix and re-run."
        exit 1
    fi
    isSuccessful "Configuration files copied from repository."

    isNotice "Applying initial configuration values..."
    [[ -n "$param2" ]] && initUpdateConfigOption "CFG_LIBREPORTAL_USER_PASS" "$param2"
    [[ -n "$param3" ]] && initUpdateConfigOption "CFG_GIT_USER"             "$param3"
    [[ -n "$param4" ]] && initUpdateConfigOption "CFG_GIT_KEY"              "$param4"
    [[ -n "$param5" ]] && initUpdateConfigOption "CFG_GIT_URL"              "$param5"
    [[ -n "$param7" ]] && initUpdateConfigOption "CFG_INSTALL_MODE"         "$param7"

    isSuccessful "Configuration setup complete."
}

initGIT()
{
    isHeader "Git Clone / Update"
    
    # Handle local installation
    if [[ "$param7" == "local" ]]; then
        isNotice "Using local folder installation."
        copyFilesFromLocal
        return
    fi
    
    GIT_USER="$param3"
    GIT_TOKEN="$param4"
    GIT_URL="$param5"

    if [[ -z "$GIT_URL" ]]; then
        isError "Git URL is empty. Please provide a valid Git repository URL."
        exit 1
    fi

    local clean_url
    clean_url=$(cleanGitUrl "$GIT_URL")
    if [[ -z "$clean_url" ]]; then
        isError "Could not normalize Git URL: $GIT_URL"
        exit 1
    fi

    local auth=""
    if [[ -n "$GIT_USER" && "$GIT_USER" != "empty" ]]; then
        auth="${GIT_USER}:${GIT_TOKEN}@"
    fi

    isNotice "Cloning $clean_url into $script_dir ..."
    sudo rm -rf "$script_dir"

    local scheme cloned=false
    for scheme in https http; do
        if sudo -u "$sudo_user_name" git clone -q "${scheme}://${auth}${clean_url}.git" "$script_dir" 2>/dev/null; then
            cloned=true
            isSuccessful "Cloned via ${scheme^^}."
            break
        fi
    done

    if ! $cloned; then
        isError "Failed to clone $clean_url over HTTPS or HTTP."
        isError "Check the URL, credentials, and that the server is reachable."
        exit 1
    fi

    sudo cp -f "$script_dir/init.sh" /root/
    setupConfigsFromRepo
    sudo chown -R "$sudo_user_name":"$sudo_user_name" "$script_dir"
}

initLibrePortalCommand()
{
	isHeader "Custom Command Setup"
	if ! grep -q "LibrePortal Command Start" $sudo_bashrc; then
		isNotice "Command maker not found. Removing old LibrePortal command."
		sed -i '/^libreportal() {$/,/^}$/d' $sudo_bashrc
	else
		isNotice "Command maker found. Removing old LibrePortal command."
		sed -i '/# LibrePortal Command Start/,/# LibrePortal Command End/d' $sudo_bashrc
	fi
	isNotice "Custom command 'libreportal' is not installed. Installing..."

	sudo rm -rf $command_script
sudo tee -a "$command_script" >/dev/null <<'EOF'
#!/usr/bin/env bash
# LibrePortal Command Start
# LibrePortal Command Version 1.4

CHECK_USER="libreportal"
CURRENT_USER=$(whoami)

# Check if the script is run by the specified user
if [ "$CURRENT_USER" != "$CHECK_USER" ]; then
    echo "Script is NOT able to run from this user."
    echo "This script should ONLY be run as: $CHECK_USER"
    exit 1
fi

command1="${1:-empty}"
command2="${2:-empty}"
command3="${3:-empty}"
command4="${4:-empty}"
command5="${5:-empty}"
command6="${6:-empty}"
command7="${7:-empty}"
command8="${8:-empty}"
command9="${9:-empty}"

path="$PWD"

reset_git_config() {
	echo ""
	echo "Resetting Git configuration for re-entry..."

	# Use dynamic config update
	commandUpdateConfigOption "CFG_GIT_USER" "changeme"
	commandUpdateConfigOption "CFG_GIT_KEY" "changeme"
	commandUpdateConfigOption "CFG_GIT_URL" "changeme"
}

# Helper function to load config files in the libreportal command
commandReloadConfigs() {
	# Load new structure config files only
	for category_dir in /docker/configs/*; do
		if [ -d "$category_dir" ] && [ -f "$category_dir/.category" ]; then
			for config_file in "$category_dir"/*; do
				local should_load=true
				local filename=$(basename "$config_file")
				# Skip .category files and excluded files (hardcoded for now)
				if [[ "$config_file" =~ \.category$ ]]; then
					should_load=false
				fi
				
				if [ "$should_load" = true ]; then
					source "$config_file"
				fi
			done
		fi
	done
}

# Helper function to update config files in the libreportal command
commandUpdateConfigOption() {
	local config_option="$1"
	local config_value="$2"
	for category_dir in /docker/configs/*; do
		if [ -d "$category_dir" ] && [ -f "$category_dir/.category" ]; then
			for config_file in "$category_dir"/*; do
				if [ -f "$config_file" ] && [[ ! "$config_file" =~ \.category$ ]]; then
					if grep -q "^$config_option=" "$config_file"; then
						# Escape special characters in the config value to prevent sed issues
						local escaped_value=$(printf '%s\n' "$config_value" | sed -e 's/[\/&]/\\&/g')
						
						# Extract the comment part first (everything after the first #)
						local original_line=$(grep "^$config_option=" "$config_file")
						local comment_part=$(echo "$original_line" | sed -n "s|^$config_option=[^#]*\(#.*\)|\1|p")
						
						# Replace the value, preserving comment if it existed
						if [[ -n "$comment_part" ]]; then
							sudo sed -i "s|^$config_option=.*|$config_option=$escaped_value                     $comment_part|" "$config_file"
						else
							sudo sed -i "s|^$config_option=.*|$config_option=$escaped_value|" "$config_file"
						fi
						source "$config_file"
						return 0
					fi
				fi
			done
		fi
	done
}

update_config_values() {
	# Reload all config files to get current values
	commandReloadConfigs

	if [[ "$CFG_INSTALL_MODE" == "local" ]]; then
		[[ "$CFG_GIT_USER" != "empty" ]] && commandUpdateConfigOption "CFG_GIT_USER" "empty"
		[[ "$CFG_GIT_KEY"  != "empty" ]] && commandUpdateConfigOption "CFG_GIT_KEY"  "empty"
		[[ "$CFG_GIT_URL"  != "empty" ]] && commandUpdateConfigOption "CFG_GIT_URL"  "empty"
		commandReloadConfigs
		return 0
	fi

	CFG_GIT_USER="${CFG_GIT_USER:-changeme}"
	if [[ -z "$CFG_GIT_USER" ]] || [[ "$CFG_GIT_USER" == "changeme" ]]; then
		while true; do
			echo "Please enter your Git username (Press Enter to set to 'empty'):"
			read -r NEW_GIT_USER
			if [[ -n "$NEW_GIT_USER" || "$NEW_GIT_USER" == "" ]]; then
				if [[ -z "$NEW_GIT_USER" ]]; then
					NEW_GIT_USER="empty"
				fi
				commandUpdateConfigOption "CFG_GIT_USER" "$NEW_GIT_USER"
				commandReloadConfigs
				echo "Updating Git Username to '$NEW_GIT_USER'"
				break
			fi
		done
	fi

	CFG_GIT_KEY="${CFG_GIT_KEY:-changeme}"
	# If Git user is disabled, force token to empty and skip prompt
	if [[ "$CFG_GIT_USER" == "empty" ]]; then
		commandUpdateConfigOption "CFG_GIT_KEY" "empty"
		commandReloadConfigs
		echo "Git authentication disabled; skipping Git token."
	else
		# Only prompt if token is unset or changeme
		if [[ -z "$CFG_GIT_KEY" || "$CFG_GIT_KEY" == "changeme" ]]; then
			while true; do
				echo "Please enter your Git access token (Press Enter to set to 'empty'):"
				read -rs NEW_GIT_KEY
				echo ""

				if [[ -z "$NEW_GIT_KEY" ]]; then
					NEW_GIT_KEY="empty"
				fi

				commandUpdateConfigOption "CFG_GIT_KEY" "$NEW_GIT_KEY"
				commandReloadConfigs
				echo "Git token updated."
				break
			done
		fi
	fi

	CFG_GIT_URL="${CFG_GIT_URL:-changeme}"
	if [[ -z "$CFG_GIT_URL" ]] || [[ "$CFG_GIT_URL" == "changeme" ]]; then
		while true; do
			echo "Please enter your Git repository URL:"
			read -rs NEW_GIT_URL
			if [[ -n "$NEW_GIT_URL" ]]; then
				commandUpdateConfigOption "CFG_GIT_URL" "$NEW_GIT_URL"
				commandReloadConfigs
				echo "Updating Git URL"
				break
			fi
			echo "Error: Git URL cannot be empty"
		done
	fi
}

commandCleanGitUrl() {
	local url="$1"
	url="${url#"${url%%[![:space:]]*}"}"
	url="${url%"${url##*[![:space:]]}"}"
	url="${url#https://}"
	url="${url#http://}"
	while [[ "$url" == */ ]]; do url="${url%/}"; done
	url="${url%.git}"
	echo "$url"
}

setup_repo() {
	while true; do
		update_config_values
		commandReloadConfigs

		CLEAN_GIT_URL=$(commandCleanGitUrl "$CFG_GIT_URL")

		local auth=""
		if [[ "$CFG_GIT_USER" != "empty" && -n "$CFG_GIT_USER" ]]; then
			auth="${CFG_GIT_USER}:${CFG_GIT_KEY}@"
		fi
		AUTH_HTTPS_REPO_URL="https://${auth}${CLEAN_GIT_URL}.git"
		AUTH_HTTP_REPO_URL="http://${auth}${CLEAN_GIT_URL}.git"

		echo ""
		echo "Configuration Summary:"
		echo ""
		
		if [[ "$CFG_INSTALL_MODE" == "local" ]]; then
			echo "Git Username: [NOT APPLICABLE]"
			echo "Git Token: [NOT APPLICABLE]"
			echo "Git URL: [NOT APPLICABLE]"
		else
			echo "Git Username: $CFG_GIT_USER"
			echo "Git Token: [HIDDEN]"
			echo "Git URL: $CLEAN_GIT_URL"
		fi
		echo ""

		read -p "Are these details correct? (y/n): " confirm_config

		if [[ "$confirm_config" == "y" ]]; then
			echo "Configuration confirmed."
			break
		else
			reset_git_config
		fi
	done
}

sync_configs_from_install() {
	local src="/docker/install/configs"
	local dst="/docker/configs"
	if [ ! -d "$src" ]; then
		echo "ERROR: $src missing — clone broken."
		return 1
	fi
	sudo mkdir -p "$dst"
	# No-clobber: preserve the user's live config values; only add new files.
	if ! sudo cp -an "$src"/. "$dst"/; then
		echo "ERROR: Failed to sync configs from $src to $dst."
		return 1
	fi
	sudo chown -R libreportal:libreportal "$dst"
	if [ ! -f "$dst/general/general_install" ]; then
		echo "ERROR: $dst/general/general_install missing after sync."
		return 1
	fi
	[ -n "$CFG_GIT_USER" ] && commandUpdateConfigOption "CFG_GIT_USER"     "$CFG_GIT_USER"
	[ -n "$CFG_GIT_KEY"  ] && commandUpdateConfigOption "CFG_GIT_KEY"      "$CFG_GIT_KEY"
	[ -n "$CFG_GIT_URL"  ] && commandUpdateConfigOption "CFG_GIT_URL"      "$CFG_GIT_URL"
	commandUpdateConfigOption "CFG_INSTALL_MODE" "git"
	echo "SUCCESS: Configs synced and credentials re-applied."
}

clone_repo() {
	sudo rm -rf /docker/install
	local clone_url
	if [ "$CFG_GIT_USER" != "empty" ]; then
		for clone_url in "$AUTH_HTTPS_REPO_URL" "$AUTH_HTTP_REPO_URL"; do
			if sudo -u libreportal git clone -q "$clone_url" "/docker/install" 2>/dev/null; then
				sudo cp -f /docker/install/init.sh /root/
				sync_configs_from_install || return 1
				echo "SUCCESS: Clone complete. Run 'libreportal run' to continue."
				return 0
			fi
		done
		echo "ERROR: Authentication failed. Please check your credentials."
		return 1
	fi
	for clone_url in "https://${CLEAN_GIT_URL}.git" "http://${CLEAN_GIT_URL}.git"; do
		if sudo -u libreportal git clone -q "$clone_url" "/docker/install" 2>/dev/null; then
			sudo cp -f /docker/install/init.sh /root/
			sync_configs_from_install || return 1
			echo "SUCCESS: Clone complete. Run 'libreportal run' to continue."
			return 0
		fi
	done
	echo "ERROR: Anonymous clone failed."
	return 1
}

clone_and_install() {
	commandReloadConfigs
	if [[ "$CFG_INSTALL_MODE" == "local" ]]; then
		echo "NOTICE: Local install detected — no Git remote to clone."
		return 0
	fi
	update_config_values;
	setup_repo;
	clone_repo;
}

cd /docker/
if [[ $command1 == "reset" ]]; then
	clone_and_install
elif [ -f "/docker/install/start.sh" ]; then
	sudo chmod 0755 /docker/install/*
	cd /docker/install
	sudo ./start.sh "$command1" "$command2" "$command3" "$command4" "$command5" "$command6" "$command7" "$command8" "$command9"
else
	clone_and_install
fi
# LibrePortal Command End
EOF
	sudo chmod +x $command_script
	sudo chown $sudo_user_name:$sudo_user_name $command_script
	source $sudo_bashrc
}

initUpdateConfigs()
{
    isHeader "Updating Configs"

    initUpdateConfigOption "CFG_LIBREPORTAL_USER_PASS" "$param2" && isSuccessful "Updated Docker user password"
    initUpdateConfigOption "CFG_GIT_USER"             "$param3" && isSuccessful "Updated Git Username"
    initUpdateConfigOption "CFG_GIT_KEY"              "$param4" && isSuccessful "Updated Git Token"
    initUpdateConfigOption "CFG_GIT_URL"              "$param5" && isSuccessful "Updated Git URL"
    initUpdateConfigOption "CFG_INSTALL_MODE"         "$param7" && isSuccessful "Updated Installation Mode"

    isHeader "Verifying Saved Configuration"
    local cfg_file="/docker/configs/general/general_install"
    if [[ ! -f "$cfg_file" ]]; then
        isError "Expected $cfg_file is missing — install cannot proceed."
        exit 1
    fi

    local saved_mode saved_user saved_url saved_key
    saved_mode=$(grep -E '^CFG_INSTALL_MODE=' "$cfg_file" | sed -E 's/^[^=]+=([^[:space:]#]*).*/\1/')
    saved_user=$(grep -E '^CFG_GIT_USER=' "$cfg_file"     | sed -E 's/^[^=]+=([^[:space:]#]*).*/\1/')
    saved_url=$(grep -E '^CFG_GIT_URL=' "$cfg_file"       | sed -E 's/^[^=]+=([^[:space:]#]*).*/\1/')
    saved_key=$(grep -E '^CFG_GIT_KEY=' "$cfg_file"       | sed -E 's/^[^=]+=([^[:space:]#]*).*/\1/')

    isNotice "Mode:  $saved_mode"
    isNotice "User:  $saved_user"
    isNotice "URL:   $saved_url"
    [[ -n "$saved_key" && "$saved_key" != "changeme" ]] \
        && isNotice "Token: [SET]" \
        || isNotice "Token: [EMPTY]"

    if [[ "$saved_mode" == "git" ]]; then
        local fail=0
        if [[ -z "$saved_url" || "$saved_url" == "changeme" ]]; then
            isError "CFG_GIT_URL didn't persist — installer will re-prompt."
            fail=1
        fi
        if [[ "$saved_user" != "empty" && ( -z "$saved_user" || "$saved_user" == "changeme" ) ]]; then
            isError "CFG_GIT_USER didn't persist — installer will re-prompt."
            fail=1
        fi
        if (( fail )); then
            isError "Aborting before handoff so you can fix this once instead of retyping every install run."
            exit 1
        fi
    fi
    isSuccessful "Configuration verified."
}

completeInitMessage()
{
	isHeader "LibrePortal Initilization Complete"

	# Run LibrePortal install as the libreportal user
	isNotice "Starting LibrePortal installation as $sudo_user_name user..."
	
	# Switch to libreportal user and run the install command
	if sudo -u "$sudo_user_name" LIBREPORTAL_SKIP_LOGO=1 bash -c "libreportal run install"; then
		:
	else
		echo ""
		echo "⚠️  LibrePortal installation encountered issues."
		echo "   You can manually run the installation with:"
		echo "   sudo -u $sudo_user_name bash -c 'libreportal run install'"
		echo ""
	fi
}

if [[ $EUID -ne 0 ]]; then
	echo "This script must be run as root."
	exit 1
else
	if [[ "$param1" == "init" ]]; then
		# Always check existing config first
		initCheckConfigs

		if [[ "$param6" == "true" || "$param6" == "1" ]]; then
			# Validate unattended params
			validateUnattended
			initDisplayConfig # in unattended mode, it will auto-accept
		else
			# Interactive mode
			initInputQuestions
			initDisplayConfig
		fi

		# Common steps (run in both interactive and unattended after confirmation)
		if [ "$init_skip_os_update" != true ]; then
			initOS
		fi
		
		if [ "$init_skip_prereqs" != true ]; then
			initPrerequires
		fi
		
		initDocker
		initUsers
		initFolders
		initGIT
		initLibrePortalCommand
		initUpdateConfigs
		completeInitMessage
	fi
fi
