#!/bin/bash
#===============================================================================

# shellcheck disable=SC1091
source /usr/lib/biglinux-livecd/kernel-options
# shellcheck disable=SC1091
source /usr/lib/biglinux-livecd/live-state
# Script Name: startbiglive
# Description: Live session bootstrap for BigLinux
#              Initializes display manager, configures monitors, and launches
#              the live setup wizard before starting the desktop session.
# Package:     biglinux-livecd
#
# Dependencies:
#   - systemctl (display manager detection)
#   - xrandr (X11 multi-monitor configuration)
#   - python3 (live setup wizard)
#   - kwin_wayland, mutter (Wayland compositors)
#===============================================================================

#-------------------------------------------------------------------------------
# Logging helper
#-------------------------------------------------------------------------------
_log() {
	logger -t "startbiglive" "$*"
}

_valid_xkb_layout() {
	[[ $1 =~ ^[A-Za-z0-9_.+-]+(\([A-Za-z0-9_.+-]+\))?$ ]]
}

_split_xkb_layout() {
	xkb_layout=$1
	xkb_variant=
	if [[ $xkb_layout =~ ^([^()]+)\(([^()]+)\)$ ]]; then
		xkb_layout=${BASH_REMATCH[1]}
		xkb_variant=${BASH_REMATCH[2]}
	fi
}

_fcitx5_keyboard_input_method() {
	if [[ -n $2 ]]; then
		printf 'keyboard-%s-%s\n' "$1" "$2"
	else
		printf 'keyboard-%s\n' "$1"
	fi
}

_configure_fcitx5_keyboard_profile() {
	local layout=$1 variant=$2 input_method profile_directory
	input_method=$(_fcitx5_keyboard_input_method "$layout" "$variant")
	profile_directory=$HOME/.config/fcitx5
	mkdir -p -- "$profile_directory"
	cat >"$profile_directory/profile" <<EOF
[Groups/0]
# Group Name
Name="Live Keyboard"
# Layout
Default Layout=$layout
# Default Input Method
DefaultIM=$input_method

[Groups/0/Items/0]
# Name
Name=$input_method
# Layout
Layout=

[GroupOrder]
0="Live Keyboard"
EOF
}

#-------------------------------------------------------------------------------
# Anti-loop protection: prevent infinite SDDM restart loops
# Tracks how many times startbiglive has been invoked. If the session keeps
# failing and SDDM's Relogin=true restarts it, we stop after a few attempts
# to avoid burning CPU and confusing the user.
#-------------------------------------------------------------------------------
user_id=$(id -u)
runtime_dir=${XDG_RUNTIME_DIR:-/run/user/$user_id}
attempt_file=/tmp/startbiglive-attempts
if [[ $runtime_dir == /run/user/"$user_id" && -d $runtime_dir && ! -L $runtime_dir ]] &&
	[[ $(stat -c '%u' -- "$runtime_dir") == "$user_id" ]]; then
	attempt_file=$runtime_dir/startbiglive-attempts
else
	_log "WARNING - Runtime directory unavailable during session startup; using legacy loop counter"
fi
max_attempts=3
attempt_cooldown=120 # reset counter if last attempt was this many seconds ago

_check_loop_protection() {
	local now attempts last_time attempt_directory temporary_attempt_file
	now=$(date +%s)

	if [[ -f $attempt_file && ! -L $attempt_file ]] &&
		[[ $(stat -c '%u' -- "$attempt_file") == "$user_id" ]]; then
		read -r attempts last_time <"$attempt_file" 2>/dev/null
		attempts=${attempts:-0}
		last_time=${last_time:-0}
		local elapsed=$((now - last_time))

		# Reset counter if enough time has passed (system may have recovered)
		if [[ $elapsed -gt $attempt_cooldown ]]; then
			attempts=0
		fi

		if [[ $attempts -ge $max_attempts ]]; then
			_log "ERROR - Session failed $max_attempts times in a row. Stopping to prevent loop."
			echo ""
			echo "╔══════════════════════════════════════════════════════════════╗"
			echo "║  BigLinux Live - Failed to start graphical session           ║"
			echo "╠══════════════════════════════════════════════════════════════╣"
			echo "║                                                              ║"
			echo "║  The system tried to start $max_attempts times without success.     ║"
			echo "║                                                              ║"
			echo "║  This may be caused by graphics hardware/driver              ║"
			echo "║  incompatibility. Possible solutions:                        ║"
			echo "║                                                              ║"
			echo "║  1. Restart the session manager:                             ║"
			echo "║     sudo systemctl restart $display_manager                  ║"
			echo "║                                                              ║"
			echo "║  2. Check the error logs:                                    ║"
			echo "║     journalctl -b -t startbiglive                            ║"
			echo "║                                                              ║"
			echo "║  3. Reboot and try the free drivers boot option              ║"
			echo "║                                                              ║"
			echo "║  To access a terminal, press Ctrl+Alt+F2                     ║"
			echo "╚══════════════════════════════════════════════════════════════╝"
			echo ""
			# Keep the process alive so SDDM doesn't restart it
			sleep infinity
			exit 1
		fi
	else
		attempts=0
	fi

	attempt_directory=$(dirname -- "$attempt_file")
	temporary_attempt_file=$(mktemp -- "$attempt_directory/.startbiglive-attempts.XXXXXX") || {
		_log "WARNING - Could not create session loop counter"
		return 0
	}
	if ! (
		umask 077
		printf '%s %s\n' "$((attempts + 1))" "$now" >"$temporary_attempt_file"
	); then
		rm -f -- "$temporary_attempt_file"
		_log "WARNING - Could not write session loop counter"
		return 0
	fi
	if ! mv -fT -- "$temporary_attempt_file" "$attempt_file"; then
		rm -f -- "$temporary_attempt_file"
		_log "WARNING - Could not install session loop counter"
		return 0
	fi
	_log "Session attempt $((attempts + 1))/$max_attempts"
}

# Clear loop counter (called when session starts successfully)
_clear_loop_counter() {
	rm -f -- "$attempt_file"
}

#-------------------------------------------------------------------------------
# Wait for GPU/DRM device to be available
# On some hardware, the GPU takes a moment after boot to become accessible
#-------------------------------------------------------------------------------
_wait_for_gpu() {
	local max_wait=15
	local count=0
	while [[ $count -lt $max_wait ]]; do
		if ls /dev/dri/card* &>/dev/null; then
			_log "GPU device ready after ${count}s"
			return 0
		fi
		sleep 1
		((count++))
	done
	_log "WARNING - GPU device not found after ${max_wait}s"
	return 1
}

#-------------------------------------------------------------------------------
# Detect multi-GPU configuration (any combination: NVIDIA+Intel, NVIDIA+AMD,
# Intel+AMD, etc.) and identify the primary (boot) GPU for fallback
#-------------------------------------------------------------------------------
is_multi_gpu=0
primary_card=""
has_nvidia_proprietary=0

_detect_multi_gpu() {
	local cards=()
	local card

	# Enumerate only base card devices (card0, card1, ...) not outputs (card0-HDMI-1)
	for card in /sys/class/drm/card[0-9]; do
		[[ -e "$card/device/boot_vga" ]] && cards+=("$card")
	done

	if [[ ${#cards[@]} -lt 2 ]]; then
		_log "Single GPU detected"
		return
	fi

	is_multi_gpu=1

	# Check for NVIDIA proprietary driver (needs special EGL handling)
	if lsmod | grep -q '^nvidia '; then
		has_nvidia_proprietary=1
	fi

	# Find the primary (boot) GPU — this is the integrated one in hybrid setups
	# boot_vga=1 indicates the GPU selected by firmware for initial display
	for card in "${cards[@]}"; do
		if [[ "$(cat "$card/device/boot_vga" 2>/dev/null)" == "1" ]]; then
			local card_name
			card_name=$(basename "$card")
			primary_card="/dev/dri/${card_name}"
			local driver_name
			driver_name=$(basename "$(readlink "$card/device/driver" 2>/dev/null)" 2>/dev/null)
			_log "Multi-GPU detected: primary=$card_name ($driver_name), nvidia_proprietary=$has_nvidia_proprietary"
			return
		fi
	done

	# Fallback: if no boot_vga found, try switcherooctl
	if command -v switcherooctl &>/dev/null; then
		local default_gpu
		default_gpu=$(switcherooctl list 2>/dev/null | grep -B1 'Default:.*yes' | head -1 | grep -oP '/dev/dri/card\d+')
		if [[ -n "$default_gpu" ]]; then
			primary_card="$default_gpu"
			_log "Multi-GPU: primary GPU from switcherooctl: $primary_card"
			return
		fi
	fi

	# Last resort: use card0 (which is typically the primary/integrated GPU)
	primary_card="/dev/dri/card0"
	_log "Multi-GPU detected: using card0 as primary (could not determine boot_vga)"
}

#-------------------------------------------------------------------------------
# Start kwin_wayland compositor with health check and multi-stage fallback
# Fallback chain:
#   1. Default hardware rendering
#   2. Multi-GPU: primary (integrated) GPU only, with Mesa EGL if NVIDIA present
#   3. Software rendering via llvmpipe
# Returns 0 if the wizard completed, 1 if kwin could not start at all
#-------------------------------------------------------------------------------
_start_kwin_wizard() {
	local wizard_command="/usr/bin/python /usr/share/biglinux/livecd/main.py"
	local -a kwin_args=(--drm --no-lockscreen --xwayland)
	local kwin_pid

	_detect_multi_gpu

	# Attempt 1: hardware-accelerated rendering (default GPU selection)
	_log "Starting kwin_wayland (hardware rendering)..."
	dbus-run-session kwin_wayland "${kwin_args[@]}" --exit-with-session "$wizard_command" &
	kwin_pid=$!

	# Give kwin a few seconds to initialize; check it didn't crash immediately
	sleep 3
	if kill -0 "$kwin_pid" 2>/dev/null; then
		_log "kwin_wayland started successfully (PID=$kwin_pid)"
		wait "$kwin_pid"
		return 0
	fi

	# Attempt 2: Multi-GPU — force primary (integrated) GPU only
	if [[ $is_multi_gpu -eq 1 && -n $primary_card ]]; then
		_log "WARNING - kwin_wayland (default) exited early, trying primary GPU only ($primary_card)..."

		local env_vars=()
		env_vars+=("KWIN_DRM_DEVICES=$primary_card")

		# If NVIDIA proprietary driver is present, force Mesa EGL to avoid
		# the NVIDIA EGL driver being selected for the integrated GPU
		if [[ $has_nvidia_proprietary -eq 1 && -e /usr/share/glvnd/egl_vendor.d/50_mesa.json ]]; then
			env_vars+=("__EGL_VENDOR_LIBRARY_FILENAMES=/usr/share/glvnd/egl_vendor.d/50_mesa.json")
		fi

		env "${env_vars[@]}" \
			dbus-run-session kwin_wayland "${kwin_args[@]}" --exit-with-session "$wizard_command" &
		kwin_pid=$!

		sleep 3
		if kill -0 "$kwin_pid" 2>/dev/null; then
			_log "kwin_wayland started on primary GPU (PID=$kwin_pid)"
			wait "$kwin_pid"
			return 0
		fi

		_log "WARNING - kwin_wayland on primary GPU also failed"
	else
		_log "WARNING - kwin_wayland (hardware) exited early"
	fi

	# Attempt 3: software rendering via llvmpipe
	_log "Retrying with software rendering..."

	LIBGL_ALWAYS_SOFTWARE=1 \
		GALLIUM_DRIVER=llvmpipe \
		dbus-run-session kwin_wayland "${kwin_args[@]}" --exit-with-session "$wizard_command" &
	kwin_pid=$!

	sleep 3
	if kill -0 "$kwin_pid" 2>/dev/null; then
		_log "kwin_wayland started with software rendering (PID=$kwin_pid)"
		wait "$kwin_pid"
		return 0
	fi

	_log "ERROR - kwin_wayland failed with both hardware and software rendering"
	return 1
}

#-------------------------------------------------------------------------------
# Start mutter compositor (GNOME) with health check and multi-stage fallback
# Fallback chain:
#   1. Default hardware rendering
#   2. Multi-GPU: force copy mode + simple KMS + Mesa EGL if NVIDIA present
#   3. Software rendering via llvmpipe
# Returns 0 if the wizard completed, 1 if mutter could not start at all
#-------------------------------------------------------------------------------
_start_mutter_wizard() {
	local wizard_cmd="/usr/bin/gnome-bbv-live-session"
	local mutter_pid

	_detect_multi_gpu

	# Attempt 1: hardware-accelerated rendering (default)
	_log "Starting mutter (hardware rendering)..."
	mutter --wayland "$wizard_cmd" &
	mutter_pid=$!

	sleep 3
	if kill -0 "$mutter_pid" 2>/dev/null; then
		_log "mutter started successfully (PID=$mutter_pid)"
		wait "$mutter_pid"
		return 0
	fi

	# Attempt 2: Multi-GPU — force simple KMS and copy mode
	if [[ $is_multi_gpu -eq 1 ]]; then
		_log "WARNING - mutter (default) exited early, trying multi-GPU workarounds..."

		local env_vars=()
		env_vars+=("MUTTER_DEBUG_FORCE_KMS_MODE=simple")
		env_vars+=("MUTTER_DEBUG_MULTI_GPU_FORCE_COPY_MODE=1")

		# If NVIDIA proprietary driver is present, force Mesa EGL
		if [[ $has_nvidia_proprietary -eq 1 && -e /usr/share/glvnd/egl_vendor.d/50_mesa.json ]]; then
			env_vars+=("__EGL_VENDOR_LIBRARY_FILENAMES=/usr/share/glvnd/egl_vendor.d/50_mesa.json")
		fi

		env "${env_vars[@]}" \
			mutter --wayland "$wizard_cmd" &
		mutter_pid=$!

		sleep 3
		if kill -0 "$mutter_pid" 2>/dev/null; then
			_log "mutter started with multi-GPU workarounds (PID=$mutter_pid)"
			wait "$mutter_pid"
			return 0
		fi

		_log "WARNING - mutter with multi-GPU workarounds also failed"
	else
		_log "WARNING - mutter (hardware) exited early"
	fi

	# Attempt 3: software rendering via llvmpipe
	_log "Retrying mutter with software rendering..."

	LIBGL_ALWAYS_SOFTWARE=1 \
		GALLIUM_DRIVER=llvmpipe \
		mutter --wayland "$wizard_cmd" &
	mutter_pid=$!

	sleep 3
	if kill -0 "$mutter_pid" 2>/dev/null; then
		_log "mutter started with software rendering (PID=$mutter_pid)"
		wait "$mutter_pid"
		return 0
	fi

	_log "ERROR - mutter failed with both hardware and software rendering"
	return 1
}

#-------------------------------------------------------------------------------
# Apply default configuration when wizard could not run
# This ensures the system can still boot to a desktop even if the wizard fails
#-------------------------------------------------------------------------------
_apply_default_config() {
	_log "Applying default configuration (wizard was skipped)"
	initialize_default_live_state
}

#-------------------------------------------------------------------------------
# Detect active display manager (must run before loop protection for messages)
#-------------------------------------------------------------------------------
display_manager_service=$(readlink -f /etc/systemd/system/display-manager.service 2>/dev/null || true)
display_manager=${display_manager_service##*/}
display_manager=${display_manager%.service}
case $display_manager in
sddm | gdm | lightdm | lxdm) ;;
*) display_manager=unknown ;;
esac
# LightDM may omit this for X11 live sessions.
session_type="${XDG_SESSION_TYPE:-x11}"
export XDG_SESSION_TYPE="$session_type"

_check_loop_protection

#-------------------------------------------------------------------------------
# X11: Configure multi-monitor mirroring
# Duplicates all connected monitors to show the same content
#-------------------------------------------------------------------------------
_configure_x11_mirroring() {
	local query first_monitor resolution_first_monitor monitor
	local -a monitors xrandr_configuration
	query=$(xrandr --query) || return 0
	mapfile -t monitors < <(awk '$2 == "connected" { print $1 }' <<<"$query")
	first_monitor=${monitors[0]:-}
	[[ -n $first_monitor ]] || return 0
	resolution_first_monitor=$(awk -v monitor="$first_monitor" '
        $1 == monitor && $2 == "connected" { found = 1; next }
        found && $1 ~ /^[0-9]+x[0-9]+$/ { print $1; exit }
    ' <<<"$query")

	xrandr_configuration=()
	for monitor in "${monitors[@]}"; do
		if [[ "$monitor" != "$first_monitor" ]]; then
			xrandr_configuration+=(
				--output "$monitor"
				--same-as "$first_monitor"
				--mode "$resolution_first_monitor"
			)
		fi
	done

	# Apply mirroring configuration
	((${#xrandr_configuration[@]} == 0)) || xrandr "${xrandr_configuration[@]}"
}

if [[ $session_type == x11 ]]; then
	_configure_x11_mirroring &
fi

#-------------------------------------------------------------------------------
# SDDM: Disable screen lock and kwallet for live session
#-------------------------------------------------------------------------------
if [[ $display_manager == sddm ]]; then
	# Neither file need exist yet on a fresh live session, and sed cannot add a
	# line to a section that is not there: appending the section whole works in
	# both cases, and KConfig merges a repeated group header.
	mkdir -p "$HOME/.config"
	if ! grep -q 'Autolock=false' "$HOME/.config/kscreenlockerrc" 2>/dev/null; then
		printf '%s\n' '[Daemon]' 'Autolock=false' 'LockOnResume=false' \
			>>"$HOME/.config/kscreenlockerrc"
	fi
	# Disable kwallet to prevent password prompts during the live KDE session.
	if ! grep -q 'Enabled=false' "$HOME/.config/kwalletrc" 2>/dev/null; then
		printf '%s\n' '[Wallet]' 'Enabled=false' >>"$HOME/.config/kwalletrc"
	fi
fi

#-------------------------------------------------------------------------------
# Check the allowlisted custom live boot mode from the kernel command line.
#-------------------------------------------------------------------------------
if [[ -e /livefs-pkgs.txt ]]; then
	boot_mode=
	boot_mode_status=0
	boot_mode=$(kernel_option_value biglinux.bootcmd) || boot_mode_status=$?
	if ((boot_mode_status == 0)); then
		if boot_command=$(live_boot_command_path "$boot_mode") && [[ -x $boot_command ]]; then
			_log "Starting allowlisted live boot mode: $boot_mode"
			exec "$boot_command"
		fi
		_log "ERROR - Refusing unsupported live boot mode: $boot_mode"
		exit 1
	elif ((boot_mode_status == 2)); then
		_log "ERROR - Refusing ambiguous biglinux.bootcmd arguments"
		exit 1
	fi
fi

#-------------------------------------------------------------------------------
# Launch live setup wizard
# Different launch methods depending on session type and display manager
#-------------------------------------------------------------------------------
if [[ "$session_type" == "x11" ]]; then
	if [[ "$display_manager" == "sddm" ]]; then
		systemctl --user start plasma-kglobalaccel.service 2>/dev/null
	fi
	_log "Starting setup wizard on X11"
	python /usr/share/biglinux/livecd/main.py
else
	# Wayland session: launch appropriate compositor with setup wizard
	if [[ "$display_manager" == "sddm" ]]; then
		export DESKTOP_SESSION=KDE
		export XDG_SESSION_DESKTOP=KDE
		export QT_QPA_PLATFORMTHEME=kvantum
		export GDMSESSION=KDE
		export XDG_CURRENT_DESKTOP=KDE
		export QT_SCALE_FACTOR_ROUNDING_POLICY=RoundPreferFloor
		systemctl --user start plasma-kglobalaccel.service 2>/dev/null

		# Wait for GPU to be ready before starting compositor
		_wait_for_gpu

		# Start kwin_wayland with health check and software rendering fallback
		if ! _start_kwin_wizard; then
			_log "Compositor could not start on any renderer"
		fi
		# The wizard records every choice in the live state, so that is what
		# says whether it ran. The compositor surviving three seconds never
		# did: a wizard that died at the fourth left the desktop with no
		# settings at all and nothing noticed.
		if [[ ! -f $(live_state_path language) ]]; then
			_apply_default_config
		fi
	elif [[ "$display_manager" == "gdm" ]]; then
		export DESKTOP_SESSION=gnome
		export XDG_SESSION_DESKTOP=gnome
		export GDMSESSION=gnome
		export XDG_CURRENT_DESKTOP=gnome
		export QT_SCALE_FACTOR_ROUNDING_POLICY=RoundPreferFloor
		gsettings set org.gnome.desktop.interface icon-theme bigicons-papient
		gsettings set org.gnome.desktop.interface cursor-theme Bibata-Modern-Classic

		# Wait for GPU to be ready before starting compositor
		_wait_for_gpu

		# Start mutter with health check and software rendering fallback
		if ! _start_mutter_wizard; then
			_log "Compositor could not start on any renderer (GNOME)"
		fi
		if [[ ! -f $(live_state_path language) ]]; then
			_apply_default_config
		fi
	fi
fi

wait

# This is not required by the wizard and can wait until its first interaction ends.
if [[ -e /usr/share/sync-kde-and-gtk-places/sync-gnome-theme-to-qt.sh ]]; then
	/usr/share/sync-kde-and-gtk-places/sync-gnome-theme-to-qt.sh
fi

#-------------------------------------------------------------------------------
# Apply language and locale settings from user selection
#-------------------------------------------------------------------------------
# shellcheck disable=SC2154
live_language_file=$(live_state_path language)
if [[ -f $live_language_file && ! -L $live_language_file ]]; then
	live_language=$(<"$live_language_file")
	if [[ $live_language =~ ^[a-z]{2,3}(_[A-Z]{2})?$ ]]; then
		live_locale=$live_language.UTF-8
		export LANGUAGE=$live_locale
		export LANG=$live_locale
		export LC_MESSAGES=$live_locale
		export LC_ALL=$live_locale
		printf '%s\n' "$live_language" >"$HOME/.config/user-dirs.locale"
		printf '[Formats]\nLANG=%s\n' "$live_locale" >"$HOME/.config/plasma-localerc"
	else
		_log "ERROR - Ignoring invalid live locale selection"
	fi
fi

#-------------------------------------------------------------------------------
# Apply keyboard layout from user selection before starting the final desktop
#-------------------------------------------------------------------------------
live_keyboard_file=$(live_state_path keyboard)
if [[ -f $live_keyboard_file && ! -L $live_keyboard_file ]]; then
	live_keyboard=$(<"$live_keyboard_file")
	if _valid_xkb_layout "$live_keyboard"; then
		_split_xkb_layout "$live_keyboard"
		if [[ -n $xkb_variant ]]; then
			setxkbmap "$xkb_layout" -variant "$xkb_variant" 2>/dev/null || true
		else
			setxkbmap "$xkb_layout" 2>/dev/null || true
		fi
		sudo -n localectl set-x11-keymap "$xkb_layout" pc105 "$xkb_variant" terminate:ctrl_alt_bksp 2>/dev/null || true
		mkdir -p -- "$HOME/.config"
		cat >"$HOME/.config/kxkbrc" <<EOF
[Layout]
DisplayNames=
LayoutList=$xkb_layout
Model=pc105
Options=terminate:ctrl_alt_bksp
ResetOldOptions=true
Use=true
VariantList=$xkb_variant
EOF
		if [[ $display_manager == sddm ]]; then
			_configure_fcitx5_keyboard_profile "$xkb_layout" "$xkb_variant"
		fi
	else
		_log "ERROR - Ignoring invalid live keyboard selection"
	fi
fi

#-------------------------------------------------------------------------------
# Create user directories and installer shortcut on desktop
#-------------------------------------------------------------------------------
xdg-user-dirs-update
xdg_desktop_directory=$(xdg-user-dir DESKTOP)
if [[ $xdg_desktop_directory != "$HOME" && $xdg_desktop_directory != "$HOME/"* ]]; then
	_log "ERROR - Refusing desktop directory outside the user home"
	xdg_desktop_directory=$HOME/Desktop
fi
mkdir -p -- "$xdg_desktop_directory"
installer_shortcut=$xdg_desktop_directory/calamares-biglinux.desktop
install -m 0755 -- /usr/share/applications/com.biglinux.calamares-config.desktop "$installer_shortcut"
# The calamares package ships a generic "Install Manjaro Linux" entry, so the
# menu would list two installers and only one of them is ours. Delete it rather
# than shadow it: a Hidden=true override in ~/.local/share/applications is
# written at the moment Plasma builds its menu cache, and Plasma kept showing
# the entry anyway. The live user has passwordless sudo; -n keeps a missing rule
# from blocking the session on a password prompt.
sudo -n rm -f /usr/share/applications/calamares.desktop 2>/dev/null ||
	_log "WARNING - Could not remove the generic Calamares menu entry"

cd -- "$HOME" || exit 1

#-------------------------------------------------------------------------------
# Wait for user manager and D-Bus session bus to be ready
# This prevents cinnamon-session/gnome-session from crashing due to missing D-Bus
#-------------------------------------------------------------------------------
_wait_for_user_session() {
	local max_wait=60
	local count=0

	# Ensure XDG_RUNTIME_DIR is set (needed for systemctl --user)
	if [[ -z ${XDG_RUNTIME_DIR:-} ]]; then
		user_id=$(id -u) || return 1
		XDG_RUNTIME_DIR=/run/user/$user_id
		export XDG_RUNTIME_DIR
		_log "Set XDG_RUNTIME_DIR=$XDG_RUNTIME_DIR"
	fi

	# Ensure D-Bus session bus address is available
	if [[ -z ${DBUS_SESSION_BUS_ADDRESS:-} && -S $XDG_RUNTIME_DIR/bus ]]; then
		export DBUS_SESSION_BUS_ADDRESS="unix:path=$XDG_RUNTIME_DIR/bus"
		_log "Set DBUS_SESSION_BUS_ADDRESS from runtime dir"
	fi

	while [[ $count -lt $max_wait ]]; do
		if systemctl --user is-active default.target &>/dev/null 2>&1; then
			_log "User session ready after ${count}s"
			return 0
		fi
		sleep 1
		((count++))
	done

	_log "WARNING - user session not ready after ${max_wait}s, attempting rescue..."

	# Rescue attempt: try to explicitly start the user target
	systemctl --user start default.target 2>/dev/null

	# Give it a few more seconds
	local rescue_wait=10
	for ((i = 0; i < rescue_wait; i++)); do
		if systemctl --user is-active default.target &>/dev/null 2>&1; then
			_log "User session recovered after rescue attempt"
			return 0
		fi
		sleep 1
	done

	_log "WARNING - user session could not be started, proceeding anyway"
	return 1
}

_wait_for_user_session

# GNOME Desktop Icons checks this metadata before launching desktop files.
if [[ -f "$installer_shortcut" ]]; then
	gio set "$installer_shortcut" metadata::trusted true 2>/dev/null || true
fi

_reset_gnome_portals() {
	# The wizard can activate the portal before the GNOME environment exists.
	# Reset it so the desktop session selects the GNOME Settings backend.
	dbus-update-activation-environment --systemd \
		DESKTOP_SESSION XDG_SESSION_DESKTOP GDMSESSION XDG_CURRENT_DESKTOP \
		2>/dev/null || true
	systemctl --user import-environment \
		DESKTOP_SESSION XDG_SESSION_DESKTOP GDMSESSION XDG_CURRENT_DESKTOP \
		2>/dev/null || true
	systemctl --user stop \
		xdg-desktop-portal.service \
		xdg-desktop-portal-gtk.service \
		xdg-desktop-portal-gnome.service \
		2>/dev/null || true
}

_plasma_live_layout_name() {
	local desktop_state desktop_state_file layout
	desktop_state_file=$(live_state_path desktop) || return 1
	[[ -f $desktop_state_file && ! -L $desktop_state_file ]] || return 1
	desktop_state=$(<"$desktop_state_file")
	layout=$(cut -f2 -d" " <<<"$desktop_state")
	[[ $layout =~ ^[A-Za-z0-9_.+-]+$ ]] || return 1
	printf '%s\n' "$layout"
}

_prepare_plasma_live_defaults() {
	local layout
	if ! install_live_state_defaults; then
		_log "WARNING - Could not install Plasma live defaults"
		return 0
	fi
	[[ -n ${HOME:-} && $HOME != / ]] || return 0
	rm -f -- "$HOME/.big_desktop_theme" "$HOME/.kdebiglinux/lastlogin" "$HOME/.kdebiglinux/lastused"
	if layout=$(_plasma_live_layout_name); then
		rm -rf -- "$HOME/.kdebiglinux/$layout"
	fi
}

# libadwaita apps use their own color-scheme setting and can ignore GTK INI files
# in non-GNOME sessions. GNOME reads color-scheme from dconf directly, and the
# forced override would fight the wizard's choice there, so skip it on gdm.
live_theme_file=$(live_state_path desktop-theme)
if [[ $display_manager != gdm && -f $live_theme_file && ! -L $live_theme_file ]]; then
	case "$(<"$live_theme_file")" in
	dark)
		export ADW_DEBUG_COLOR_SCHEME=prefer-dark
		;;
	light)
		export ADW_DEBUG_COLOR_SCHEME=default
		;;
	esac
	dbus-update-activation-environment --systemd ADW_DEBUG_COLOR_SCHEME 2>/dev/null || true
	systemctl --user import-environment ADW_DEBUG_COLOR_SCHEME 2>/dev/null || true
fi

# Fix to KDE Plasma using en_US
rm -f -- "$HOME"/.cache/ksycoca*

#-------------------------------------------------------------------------------
# Start appropriate desktop session based on detected environment
# Using exec to prevent fallthrough to systemctl restart
#-------------------------------------------------------------------------------

# BigCommunity Core: Launch Calamares directly
if grep -iq 'BigCommunity-Core.iso' /proc/cmdline; then
	exec /usr/bin/calamares-biglinux_polkit

elif [[ "$display_manager" == "gdm" ]]; then
	# GNOME: Clean up and start gnome-session
	rm -f "$HOME/Empty Bash" "$HOME/Empty Desktop File.desktop" "$HOME/Empty File"
	xdg-user-dirs-update
	_reset_gnome_portals
	exec startgnome-community

elif [[ -e /usr/share/wayland-sessions/hyprland.desktop ]]; then
	# Hyprland detected
	exec Hyprland

elif [[ "$display_manager" == "sddm" || "$display_manager" == "lxdm" ]]; then
	# KDE Plasma
	_prepare_plasma_live_defaults
	if [[ "$session_type" == "x11" ]]; then
		exec startkde-biglinux
	else
		exec startkde-biglinux wayland
	fi

elif [[ -e /usr/share/xsessions/xfce.desktop ]]; then
	# XFCE: Clean up and start xfce session
	rm -f "$HOME/Empty Bash" "$HOME/Empty Desktop File.desktop" "$HOME/Empty File"
	xdg-user-dirs-update
	exec startxfce-community

elif [[ -e /usr/bin/startcinnamon-community ]]; then
	# Cinnamon: Clean up and start cinnamon-session
	rm -f "$HOME/Empty Bash" "$HOME/Empty Desktop File.desktop" "$HOME/Empty File"
	xdg-user-dirs-update
	exec startcinnamon-community
fi

# Fallback: restart display manager only if no session starter was found
sudo systemctl restart "$display_manager"
