#!/bin/sh
set -eu

PYTHON="/opt/pyacket/current/venv/bin/python"
STATE_ROOT="/var/lib/pyacket/users"
requested_uid=""
display=""
wayland_display=""
xauthority=""
session_type=""

while [ "$#" -gt 0 ]; do
    case "$1" in
        --uid)
            [ "$#" -ge 2 ] || { echo "--uid 값이 필요합니다." >&2; exit 64; }
            requested_uid="$2"; shift 2 ;;
        --display)
            [ "$#" -ge 2 ] || exit 64
            display="$2"; shift 2 ;;
        --wayland-display)
            [ "$#" -ge 2 ] || exit 64
            wayland_display="$2"; shift 2 ;;
        --xauthority)
            [ "$#" -ge 2 ] || exit 64
            xauthority="$2"; shift 2 ;;
        --session-type)
            [ "$#" -ge 2 ] || exit 64
            session_type="$2"; shift 2 ;;
        --)
            shift
            break ;;
        *)
            echo "알 수 없는 launcher 옵션: $1" >&2
            exit 64 ;;
    esac
done

if [ "$(id -u)" -ne 0 ]; then
    echo "pyacket root launcher는 pkexec 또는 sudo를 통해 실행해야 합니다." >&2
    exit 77
fi
if [ ! -x "$PYTHON" ]; then
    echo "pyacket Python runtime을 찾을 수 없습니다: $PYTHON" >&2
    exit 69
fi

# pkexec는 인증을 요청한 사용자의 UID를 PKEXEC_UID로 제공하고,
# sudo는 SUDO_UID를 제공한다. 명령행 --uid는 교차 검증용으로만 사용한다.
origin_uid="${PKEXEC_UID:-${SUDO_UID:-$requested_uid}}"
case "$origin_uid" in
    ''|*[!0-9]*) origin_uid=0 ;;
esac
if [ -n "$requested_uid" ] && [ "$origin_uid" != "$requested_uid" ] && [ "$origin_uid" != "0" ]; then
    echo "요청 UID와 인증 주체가 일치하지 않습니다." >&2
    exit 77
fi

passwd_entry="$(getent passwd "$origin_uid" 2>/dev/null || true)"
if [ -n "$passwd_entry" ]; then
    origin_user="$(printf '%s' "$passwd_entry" | cut -d: -f1)"
    origin_gid="$(printf '%s' "$passwd_entry" | cut -d: -f4)"
    origin_home="$(printf '%s' "$passwd_entry" | cut -d: -f6)"
else
    origin_user=root
    origin_gid=0
    origin_home=/root
    origin_uid=0
fi

user_state="$STATE_ROOT/$origin_uid"
mkdir -p "$user_state/config" "$user_state/state" "$user_state/cache"
# root process가 쓰는 경로를 일반 사용자가 수정할 수 있게 두면 symlink 기반
# privileged-file overwrite가 가능하다. state/log는 root 전용으로 두고 launcher가
# 실행 코드와 상태를 모두 통제한다. 사용자가 명시적으로 저장한 PCAP/.pyckt만
# 저장 완료 뒤 원래 UID/GID로 복원한다.
chown -R 0:0 "$user_state" 2>/dev/null || true
find "$user_state" -type d -exec chmod 0700 {} + 2>/dev/null || true
find "$user_state" -type f -exec chmod 0600 {} + 2>/dev/null || true

# GUI는 root로 실행하되, 설정/로그는 원래 사용자별 보호된 상태 디렉터리에 저장한다.
# PCAP/.pyckt 저장 후 소유권을 원래 사용자로 복원하기 위한 숫자 UID/GID도 전달한다.
export HOME="$origin_home"
export USER="$origin_user"
export LOGNAME="$origin_user"
export PYACKET_ELEVATED="1"
export PYACKET_ORIGINAL_UID="$origin_uid"
export PYACKET_ORIGINAL_GID="$origin_gid"
export PYACKET_ORIGINAL_USER="$origin_user"
# root process가 사용자-controlled Python/Qt loader 경로를 상속하지 않도록 제한한다.
unset PYTHONPATH PYTHONHOME PYTHONSTARTUP PYTHONINSPECT PYTHONUSERBASE
unset LD_PRELOAD LD_LIBRARY_PATH LD_AUDIT
unset QT_PLUGIN_PATH QT_QPA_PLATFORM_PLUGIN_PATH QML2_IMPORT_PATH
unset GTK_PATH GIO_EXTRA_MODULES GI_TYPELIB_PATH
export PYTHONNOUSERSITE=1
export PYTHONSAFEPATH=1
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
export XDG_CONFIG_HOME="$user_state/config"
export XDG_STATE_HOME="$user_state/state"
export XDG_CACHE_HOME="$user_state/cache"

user_runtime_dir="/run/user/$origin_uid"
root_runtime_dir="/run/pyacket-$origin_uid-$$"
mkdir -p "$root_runtime_dir"
chmod 0700 "$root_runtime_dir"
export XDG_RUNTIME_DIR="$root_runtime_dir"
if [ -d "$user_runtime_dir" ] && [ -S "$user_runtime_dir/bus" ]; then
    export DBUS_SESSION_BUS_ADDRESS="unix:path=$user_runtime_dir/bus"
fi

case "$display" in
    "") ;;
    :[0-9]*|[A-Za-z0-9_.-]*:[0-9]*) export DISPLAY="$display" ;;
    *) echo "안전하지 않은 DISPLAY 값은 무시합니다." >&2 ;;
esac
case "$wayland_display" in
    "") ;;
    */*|*..*) echo "안전하지 않은 WAYLAND_DISPLAY 값은 무시합니다." >&2 ;;
    *)
        if [ -S "$user_runtime_dir/$wayland_display" ]; then
            ln -s "$user_runtime_dir/$wayland_display" "$root_runtime_dir/$wayland_display"
            export WAYLAND_DISPLAY="$wayland_display"
        else
            echo "Wayland socket을 찾지 못해 X11 fallback을 시도합니다: $wayland_display" >&2
        fi
        ;;
esac
case "$session_type" in
    x11|wayland) export XDG_SESSION_TYPE="$session_type" ;;
esac
if [ -n "$xauthority" ] && [ -f "$xauthority" ]; then
    xauth_owner="$(stat -c '%u' "$xauthority" 2>/dev/null || printf '%s' 999999)"
    if [ "$xauth_owner" = "$origin_uid" ] || [ "$xauth_owner" = "0" ]; then
        export XAUTHORITY="$xauthority"
    fi
elif [ -f "$origin_home/.Xauthority" ]; then
    export XAUTHORITY="$origin_home/.Xauthority"
fi

umask 022
cleanup() {
    chown -R 0:0 "$user_state" 2>/dev/null || true
    find "$user_state" -type d -exec chmod 0700 {} + 2>/dev/null || true
    find "$user_state" -type f -exec chmod 0600 {} + 2>/dev/null || true
    rm -rf "$root_runtime_dir" 2>/dev/null || true
}
trap cleanup EXIT

cd /opt/pyacket/current
set +e
"$PYTHON" -m pyacket "$@"
status=$?
set -e
exit "$status"
