#!/bin/bash
set -euo pipefail

# command_not_found_handle is a noop function that prevents printing error messages if WSL interop is disabled.
function command_not_found_handle() {
	:
}

# get_first_interactive_uid returns first interactive non system user uid with uid >=1000.
function get_first_interactive_uid() {
	getent passwd | grep -E -v '/nologin|/false|/sync' | sort -t: -k3,3n | awk -F: '$3 >= 1000 { print $3; exit }'
}

# create_regular_user prompts user for a username and assign default WSL permissions.
# First argument is the prefilled username.
function create_regular_user() {
	local default_username="${1}"

	local valid_username_regex='^[a-z_][a-z0-9_-]*$'
	local DEFAULT_GROUPS='adm,cdrom,sudo,dip,plugdev'

	# Filter the prefilled username to remove invalid characters.
	# Remove all characters except a-z, 0-9, _ and -
	default_username="${default_username//[^a-z0-9_-]/}"
	# Remove leading character if not a-z or _
	default_username="${default_username#[!a-z_]}"

	# Ensure a valid username
	while true; do
		# Prefill the prompt with the Windows username.
		read -er -p "Create a default Unix user account: " -i "${default_username}" username

		# Validate the username.
		if [[ ! "${username}" =~ ${valid_username_regex} ]]; then
			echo "Invalid username. A valid username must start with a lowercase letter or underscore, and can contain lowercase letters, digits, underscores, and dashes."
			continue
		fi

		# Create the user and change its default groups.
		if ! /usr/sbin/adduser --quiet --gecos '' "${username}"; then
			echo "Failed to create user '${username}'. Please choose a different name."
			continue
		fi

		if ! /usr/sbin/usermod "${username}" -aG "${DEFAULT_GROUPS}"; then
			echo "Failed to add '${username}' to default groups. Attempting cleanup."
			/usr/sbin/deluser --quiet "${username}"
			continue
		fi

		break
	done
}

# set_user_as_default sets the given username as the default user in the wsl.conf configuration.
# It will only set it if there is no existing default under the [user] section.
function set_user_as_default() {
	local username="${1}"

	local wsl_conf="/etc/wsl.conf"
	touch "${wsl_conf}"

	# Append [user] section with default if they don't exist.
	if ! grep -q "^\[user\]" "${wsl_conf}"; then
		echo -e "\n[user]\ndefault=${username}" >>"${wsl_conf}"
		return
	fi

	# If default is missing from the user section, append it to it.
	if ! sed -n '/^\[user\]/,/^\[/{/^\s*default\s*=/p}' "${wsl_conf}" | grep -q .; then
		sed -i '/^\[user\]/a\default='"${username}" "${wsl_conf}"
	fi
}

# powershell_env outputs the contents of PowerShell.exe environment variables $Env:<ARG>
# encoded in UTF-8.
function powershell_env() {
	local var="$1"
	if [ "$#" != 1 ]; then
		echo "powershell_env: expected 1 argument, got $# ."
		return 1
	fi

	local ret
	# shellcheck disable=SC2016 # Intentional due to how we use powershell
	ret=$(powershell.exe -NoProfile -Command '& {
                            [Console]::OutputEncoding = [System.Text.Encoding]::UTF8
                            $Env:'"${var}"'}') 2>/dev/null || true
	# strip control chars like \r and \n
	ret="${ret%%[[:cntrl:]]}"
	echo "$ret"
}

# install_ubuntu_font copies the Ubuntu font into Windows filesystem and register it for the current Windows user.
function install_ubuntu_font() {
	local local_app_data
	local_app_data=$(powershell_env "LocalAppData")
	if [ -z "${local_app_data}" ]; then
		return
	fi

	local_app_data=$(wslpath -au "${local_app_data}") 2>/dev/null || true
	local fonts_dir="${local_app_data}/Microsoft/Windows/Fonts"
	local font="UbuntuMono[wght].ttf"
	mkdir -p "${fonts_dir}" 2>/dev/null
	if [ -f "${fonts_dir}/${font}" ]; then
		return
	fi

	cp "/usr/share/fonts/truetype/ubuntu/${font}" "${fonts_dir}" 2>/dev/null || true

	# Register the font for the current user.
	local dst
	dst=$(wslpath -aw "${fonts_dir}/${font}") 2>/dev/null || true
	# shellcheck disable=SC2016 # Intentional due to how we use powershell
	powershell.exe -NoProfile -Command '& {
              $null = New-Item -Path "HKCU:\Software\Microsoft\Windows NT\CurrentVersion" -Name "Fonts" 2>$null;
              $null = New-ItemProperty -Name "Ubuntu Mono (TrueType)" -Path "HKCU:\Software\Microsoft\Windows NT\CurrentVersion\Fonts" -PropertyType string -Value "'"${dst}"'" 2>$null;
  }' >/dev/null || true
}

echo "Provisioning the new WSL instance $WSL_DISTRO_NAME"
echo "This might take a while..."

# Read the Windows user name.
win_username=$(powershell_env "UserName.ToLower()")
# replace any potential whitespaces with underscores.
win_username="${win_username// /_}"

install_ubuntu_font

# Wait for cloud-init to finish if systemd and its service is enabled
# by running the script located at the same dir as this one.
this_dir=$(dirname "$(realpath "$0")")
source "${this_dir}/wait-for-cloud-init"

# Check if there is a pre-provisioned users (pre-baked on the rootfs or created by cloud-init).
user_id=$(get_first_interactive_uid)

# If we don’t have a non system user, let’s create it.
if [ -z "${user_id}" ]; then
	create_regular_user "${win_username}"

	user_id=$(get_first_interactive_uid)
	if [ -z "${user_id}" ]; then
		echo 'Failed to create a regular user account'
		exit 1
	fi
fi

# Set the newly created user as the WSL default.
username=$(id -un "${user_id}")
set_user_as_default "${username}"

# Start Ubuntu Insights consent script
"${this_dir}/ubuntu-insights.sh"
