#!/usr/bin/env bash
# Copyright (C) 2023 Rudra Saraswat
# 
# This file is part of blend.
# 
# blend is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# 
# blend is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with blend.  If not, see <http://www.gnu.org/licenses/>.

if [ ! -f '/run/.containerenv' ]; then
    echo 'not running in container'
    exit 1
fi

shopt -s extglob

while true; do
    case $1 in
        --uid)
            if [ -n "$2" ]; then
                _cuid="$2"
                shift
                shift
            fi
            ;;
        --group)
            if [ -n "$2" ]; then
                _cgid="$2"
                shift
                shift
            fi
            ;;
        --username)
            if [ -n "$2" ]; then
                _uname="$2"
                shift
                shift
            fi
            ;;
        --home)
            if [ -n "$2" ]; then
                _uhome="$2"
                shift
                shift
            fi
            ;;
        -*)
            exit 1
            ;;
        *)
            break
            ;;
    esac
done

echo 'Starting container... (this may take a few minutes)'
echo

bmount() {
    ! [[ -d "$1" ]] && ! [[ -f "$1" ]] && return 0 # check if source dir exists
    ! [[ -e "$2" ]] && findmnt "$2" &>/dev/null && umount "$2" # unmount target dir if a mount

    [[ -d "$1" ]] && mkdir -p "$2" # create target dir if source is a dir
    [[ -f "$1" ]] && mkdir -p "$(dirname "$2")"; touch "$2" # create target file if source is a file

    mountflags="rslave"

    ! [[ -z "$3" ]] && mountflags="$3"

    mount --rbind -o "$mountflags" "$1" "$2" &>/dev/null
}

if [[ ! -f '/.init_blend.lock' ]]; then

###

if command -v apt-get &>/dev/null; then
    apt-get update &>/dev/null
    DEBIAN_FRONTEND=noninteractive apt-get -y install bash bc curl less wget apt-utils apt-transport-https dialog \
                                                diffutils findutils gnupg2 sudo time util-linux libnss-myhostname \
                                                lsof ncurses-base passwd inotify-tools pinentry-curses libegl1-mesa \
                                                libgl1-mesa-glx libvulkan1 mesa-vulkan-drivers dbus &>/dev/null

elif command -v pacman &>/dev/null; then
    pacman --noconfirm -Syyu &>/dev/null
    pacman --noconfirm -Sy bash bc curl wget diffutils findutils gnupg sudo time util-linux vte-common lsof ncurses pinentry \
                             mesa opengl-driver vulkan-intel vulkan-radeon base-devel git inotify-tools dbus dbus-broker &>/dev/null

elif command -v dnf &>/dev/null; then
    dnf config-manager --set-enabled crb &>/dev/null
    dnf install -y epel-release &>/dev/null
    dnf install -y --allowerasing bash bc curl wget diffutils findutils dnf-plugins-core gnupg2 less lsof passwd pinentry \
                                    procps-ng vte-profile ncurses util-linux sudo time shadow-utils vulkan mesa-vulkan-drivers \
                                    mesa-dri-drivers inotify-tools dbus &>/dev/null

fi

mkdir -p /usr/local/bin
wget -O /usr/local/bin/host-spawn "https://github.com/1player/host-spawn/releases/latest/download/host-spawn-$(uname -m)" &>/dev/null
chmod 755 /usr/local/bin/host-spawn

fi

###

for i in /var/log/journal /var/lib/systemd/coredump /var/lib/flatpak; do
    bmount "/run/host/${i}" "$i" ro
done

for i in /etc/host.conf /run/media /media /mnt /var/mnt \
         /run/libvirt /etc/machine-id /run/netconfig/ /run/udev \
         /run/systemd/journal /run/systemd/seats /run/systemd/sessions \
         /run/systemd/users /run/systemd/resolve/ /srv /var/lib/libvirt; do
    bmount "/run/host/${i}" "$i" rw
done

init_ro_mounts="
        /run/systemd/journal
        /var/log/journal
        /run/systemd/resolve
        /run/systemd/seats
        /run/systemd/sessions
        /run/systemd/users
        /var/lib/systemd/coredump
        /etc/localtime"

### Section START https://github.com/89luca89/distrobox/blob/main/distrobox-init#L772
host_sockets="$(find /run/host/run -name 'user' \
    -prune -o -path /run/host/run/media \
    -prune -o -name 'nscd' \
    -prune -o -name 'bees' \
    -prune -o -name 'system_bus_socket' \
    -prune -o -type s -print \
    2> /dev/null || :)"
### Section END

for i in ${host_sockets}; do
    container_socket="$(echo -n "$i" | sed 's/\/run\/host//g')"
    if [ ! -S "${container_socket}" ] && [ ! -L "${container_socket}" ]; then
        rm -f "${container_socket}"
        mkdir -p "$(dirname "${container_socket}")"
        ln -s "$i" "${container_socket}"
    fi
done

bmount "/run/host/usr/share/themes" "/usr/local/share/themes" ro
bmount "/run/host/usr/share/icons" "/usr/local/share/icons" ro
bmount "/run/host/usr/share/fonts" "/usr/local/share/fonts" ro

bmount "/usr/bin/host-blend" "/usr/bin/blend" ro

# sudo touch /.init_blend.lock

if [[ ! -f '/.init_blend.lock' ]]; then

#######################################################################

# NVIDIA driver integration. This is straight from https://github.com/89luca89/distrobox/blob/main/distrobox-init#L816,
# entirely thanks to an effort by Luca Di Maio, save for a few tweaks for init-blend. Thanks, in case you're reading this!

NVIDIA_FILES="$(find /run/host/usr/ \
    -path "/run/host/usr/share/doc*" -prune -o \
    -path "/run/host/usr/src*" -prune -o \
    -path "/run/host/usr/lib*/modules*" -prune -o \
    -path "/run/host/usr/share/man*" -prune -o \
    -path "/run/host/usr/lib*" -prune -o \
    -type f -iname "*nvidia*" -print 2</dev/null || :)"
for nvidia_file in ${NVIDIA_FILES}; do
    dest_file="$(printf "%s" "${nvidia_file}" | sed 's|/run/host||g')"
    bmount "${nvidia_file}" "${dest_file}" ro
done

# Then we find all the ".so" libraries, there are searched separately
# because we need to extract the relative path to mount them in the
# correct path based on the guest's setup
NVIDIA_LIBS="$(find /run/host/usr/lib* \
    -iname "*nvidia*.so*" \
    -o -iname "libcuda*.so*" \
    -o -iname "libnvcuvid*.so*" \
    -o -iname "libnvoptix*.so*" ||
    :)"
for nvidia_lib in ${NVIDIA_LIBS}; do
    dest_file="$(printf "%s" "${nvidia_lib}" |
        sed 's|/run/host/usr/lib/x86_64-linux-gnu/||g' |
        sed 's|/run/host/usr/lib64/||g' |
        sed 's|/run/host/usr/lib/||g')"

    # In the guest we need to adjust the destination path, so if we're on
    # debian based containers, we need to target /usr/lib/x86_64-linux-gnu/
    if [ -e "/usr/lib/x86_64-linux-gnu/" ]; then
        bmount "${nvidia_lib}" "/usr/lib/x86_64-linux-gnu/${dest_file}" ro
        # /usr/lib64 is common in rpm based distros
    elif [ -e "/usr/lib64" ]; then
        bmount "${nvidia_lib}" "/usr/lib64/${dest_file}" ro
        # fallback to /usr/lib if none of the previous
    else
        bmount "${nvidia_lib}" "/usr/lib/${dest_file}" ro
    fi
done

# Refresh ldconfig cache, also detect if there are empty files remaining
# and clean them.
# This could happen when upgrading drivers and changing versions.
empty_libs="$(ldconfig 2>&1 | grep -Eo "File.*is empty" | cut -d' ' -f2)"
if [ -n "${empty_libs}" ]; then
    # shellcheck disable=SC2086
    rm -f ${empty_libs}
fi

#######################################################################

### Section START (based on https://github.com/89luca89/distrobox/blob/main/distrobox-init#L816)

if [ -d "/usr/lib/rpm/" ]; then
    mkdir -p /usr/lib/rpm/macros.d
    net_mounts=""
    for net_mount in \
        ${HOST_MOUNTS_RO} ${HOST_MOUNTS} \
        '/dev' '/proc' '/sys' '/tmp' \
        '/etc/host.conf' '/etc/hosts' '/etc/resolv.conf' '/etc/localtime' \
        '/usr/share/zoneinfo'; do

        net_mounts="${net_mount}:${net_mounts}"

    done
    net_mounts=${net_mounts%?}
    echo "%_netsharedpath ${net_mounts}" > /usr/lib/rpm/macros.d/macros.blend
elif [ -d "/etc/dpkg/" ]; then
    mkdir -p /etc/dpkg/dpkg.cfg.d /etc/apt/apt.conf.d

    echo -n > /etc/dpkg/dpkg.cfg.d/00_blend
    for net_mount in ${HOST_MOUNTS_RO} ${HOST_MOUNTS} '/etc/hosts' '/etc/resolv.conf' '/etc/localtime'; do
        printf "path-exclude %s/*\n" "${net_mount}" >> /etc/dpkg/dpkg.cfg.d/00_blend
    done

    echo -n > /etc/apt/apt.conf.d/00_blend
    for init_mount in ${init_ro_mounts}; do
        printf 'DPkg::Pre-Invoke {"if findmnt %s >/dev/null; then umount -l %s; fi";};\n' \
            "${init_mount}" "${init_mount}" >> /etc/apt/apt.conf.d/00_blend

        printf 'DPkg::Post-Invoke {"if [ -e /run/host/%s ] || [ -e /run/host/$(readlink -fm /run/host/%s) ]; then mount --rbind $(readlink -fm /run/host/%s) %s 2>/dev/null || mount --rbind /run/host/$(readlink -fm /run/host/%s) %s; fi";};\n' \
            "${init_mount}" "${init_mount}" "${init_mount}" "${init_mount}" "${init_mount}" "${init_mount}" >> /etc/apt/apt.conf.d/00_blend
    done

### Section END
elif [ -d "/usr/share/libalpm/scripts" ]; then
	echo "#!/bin/sh" > /usr/share/libalpm/scripts/00_blend_pre_hook.sh
    echo "#!/bin/sh" > /usr/share/libalpm/scripts/01_blend_post_hook.sh
	echo "#!/bin/sh" > /usr/share/libalpm/scripts/02_blend_post_hook.sh

    for net_mount in ${HOST_MOUNTS_RO}; do
        echo "findmnt ${net_mount} &>/dev/null && umount ${net_mount} || :" >> /usr/share/libalpm/scripts/00_blend_pre_hook.sh
        echo "test -e /run/host/${net_mount} && mount --rbind -o ro /run/host/${net_mount} ${net_mount} || :" >> /usr/share/libalpm/scripts/02_blend_post_hook.sh
    done

    echo -e '#!/bin/sh\necho -e "#!/bin/sh\nexit 0" > /usr/share/libalpm/scripts/systemd-hook' >/usr/share/libalpm/scripts/01_blend_post_hook.sh

    chmod 755 /usr/share/libalpm/scripts/*blend*.sh

    for p in 00_blend_pre_hook 01_blend_post_hook 02_blend_post_hook; do
        when=PostTransaction

        [[ -z "${p##*pre*}" ]] && when=PreTransaction
cat << EOF > "/usr/share/libalpm/hooks/${p}.hook"
[Trigger]
Operation = Install
Operation = Upgrade
Type = Package
Target = *
[Action]
Description = blend ${p}
When = ${when}
Exec = /usr/share/libalpm/scripts/${p}.sh
EOF
    done
fi

mkdir -p /etc/sudoers.d
if ! grep -q 'Defaults !fqdn' /etc/sudoers.d/sudoers &>/dev/null; then
	printf "Defaults !fqdn\n" >> /etc/sudoers.d/sudoers
fi
if ! grep -q "\"${_uname}\" ALL = (root) NOPASSWD:ALL" /etc/sudoers.d/sudoers &>/dev/null; then
	printf "\"%s\" ALL = (root) NOPASSWD:ALL\n" "$_uname" >> /etc/sudoers.d/sudoers
fi
if [[ $_cuid -eq 1000 ]] && grep -q ubuntu /etc/passwd; then
    userdel -r ubuntu &>/dev/null
    groupdel ubuntu &> /dev/null
    grep -v ubuntu /etc/passwd > /etc/passwd.tmp
    grep -v ubuntu /etc/group > /etc/group.tmp
    mv /etc/passwd.tmp /etc/passwd
    mv /etc/group.tmp /etc/group
fi
if ! grep -q "^${_uname}:" /etc/group; then
	if ! groupadd --force --gid "$_cgid" "$_uname"; then
		printf "%s:x:%s:" "$_uname" "$_cgid" >> /etc/group
	fi
fi
useradd --uid "$_cuid" --gid "$_cgid" --shell "/bin/bash" --no-create-home --home "$_uhome" "$_uname" &>/dev/null

chown root /etc/sudo.conf
chown root /usr/bin/sudo
chmod 4755 /usr/bin/sudo

fi

if ! command -v inotify-tools &>/dev/null; then
    if command -v apt-get &>/dev/null; then
        apt-get update &>/dev/null
        DEBIAN_FRONTEND=noninteractive apt-get -y install inotify-tools &>/dev/null

    elif command -v pacman &>/dev/null; then
        pacman --noconfirm -Syyu &>/dev/null
        pacman --noconfirm -Sy inotify-tools &>/dev/null

    elif command -v dnf &>/dev/null; then
        dnf install -y --allowerasing inotify-tools &>/dev/null
    fi
fi

source /run/.containerenv
CONTAINER_NAME="$name"

if [[ ! -f '/.init_blend.lock' ]] && command -v pacman &>/dev/null; then
    cd /; git clone https://aur.archlinux.org/yay.git &>/dev/null; cd yay
    chown -R "$_uname" . &>/log
    sudo -u "$_uname" makepkg --noconfirm -si &>/dev/null
    cd /; rm -rf yay

    touch /.init_blend.lock
fi

for full_file in /usr/bin/*; do
    if [[ -x "$full_file" ]]; then
        file="$(basename "${full_file}")"
        if [[ ! -f "${HOME}/.local/bin/blend_bin/${file}.${CONTAINER_NAME}" ]]; then
            mkdir -p "${HOME}/.local/bin/blend_bin"
            echo "#!/bin/bash" > "${HOME}/.local/bin/blend_bin/${file}.${CONTAINER_NAME}"
            echo '[ -f /run/.containerenv ] && { if [[ -e "/usr/bin/'"${file}"'" ]]; then /usr/bin/'"${file}"' "$@"; exit $?; else echo "This command can be accessed from the host, or from the container '"'${CONTAINER_NAME}'"'."; exit 127; fi } || :' >> "${HOME}/.local/bin/blend_bin/${file}.${CONTAINER_NAME}"
            echo 'BLEND_ALLOW_ROOT= BLEND_NO_CHECK= blend enter -cn '"${CONTAINER_NAME}"' -- '"${file}"' "$@"' >> "${HOME}/.local/bin/blend_bin/${file}.${CONTAINER_NAME}"
            chmod 755 "${HOME}/.local/bin/blend_bin/${file}.${CONTAINER_NAME}"
        fi
    fi
done

mkdir -p /usr/share/applications
touch "/usr/share/applications/empty_file.desktop"

for full_file in /usr/share/applications/*.desktop; do
    file="$(basename "${full_file}")"

    echo -n > "${HOME}/.local/share/applications/blend;${CONTAINER_NAME};${file}"

    while read -r line; do
        if [[ $line == Name* ]]; then
            echo "${line} (container ${CONTAINER_NAME})" >> "${HOME}/.local/share/applications/blend;${CONTAINER_NAME};${file}"
        elif [[ $line == Exec* ]]; then
            echo "Exec=blend enter -cn ${CONTAINER_NAME} -- ${line:5}" >> "${HOME}/.local/share/applications/blend;${CONTAINER_NAME};${file}"
        elif [[ $line == Icon* ]]; then
            if [[ -e "${line:5}" ]]; then
                mkdir -p "${HOME}/.local/share/blend/icons/${CONTAINER_NAME}_${file}"; cp "${line:5}" "${HOME}/.local/share/blend/icons/${CONTAINER_NAME}_${file}"
                echo "Icon=${HOME}/.local/share/blend/icons/${CONTAINER_NAME}_${file}/$(basename "${line:5}")" >> "${HOME}/.local/share/applications/blend;${CONTAINER_NAME};${file}"
            else
                ICON_PATH="$(find /usr/share/icons/hicolor -type f -iname "*${line:5}*" -print -quit 2>/dev/null)"
                mkdir -p "$(dirname "${ICON_PATH}" | sed 's/\/usr\/share/'"\/home\/${_uname}"'\/.local\/share/g')"
                FINAL_ICON_PATH="$(dirname "${ICON_PATH}" | sed 's/\/usr\/share/'"\/home\/${_uname}"'\/.local\/share/g')/$(echo "${file%.*}").$(basename "${ICON_PATH}" | sed 's/^.*\.//')"
                cp "${ICON_PATH}" "${FINAL_ICON_PATH}" &>/dev/null
                echo "Icon=${FINAL_ICON_PATH}" >> "${HOME}/.local/share/applications/blend;${CONTAINER_NAME};${file}"
            fi
        else
            echo "$line" >> "${HOME}/.local/share/applications/blend;${CONTAINER_NAME};${file}"
        fi
    done < "/usr/share/applications/${file}"

    sed -i 's/DBusActivatable=true/DBusActivatable=false/g' "${HOME}/.local/share/applications/blend;${CONTAINER_NAME};${file}"
    sed -i '/^TryExec/d' "${HOME}/.local/share/applications/blend;${CONTAINER_NAME};${file}"

    chmod 755 "${HOME}/.local/share/applications/blend;${CONTAINER_NAME};${file}"
done

echo "Started container."

mkdir -p /usr/share/applications /usr/bin
inotifywait -m /usr/share/applications /usr/bin -e create,delete,move 2>/dev/null |
    while read dir action file; do
        ( if [[ "$dir" == "/usr/bin/" ]]; then
            if [[ "$action" == *"CREATE"* ]]; then
                if [[ ! -f "${HOME}/.local/bin/blend_bin/${file}.${CONTAINER_NAME}" ]] && [[ -x "/usr/bin/${file}" ]]; then
                    mkdir -p "${HOME}/.local/bin/blend_bin"
                    echo "#!/bin/bash" > "${HOME}/.local/bin/blend_bin/${file}.${CONTAINER_NAME}"
                    echo '[ -f /run/.containerenv ] && { if [[ -e "/usr/bin/'"${file}"'" ]]; then /usr/bin/'"${file}"' "$@"; exit $?; else echo "This command can be accessed from the host, or from the container '"'${CONTAINER_NAME}'"'."; exit 127; fi } || :' >> "${HOME}/.local/bin/blend_bin/${file}.${CONTAINER_NAME}"
                    echo 'BLEND_ALLOW_ROOT= BLEND_NO_CHECK= blend enter -cn '"${CONTAINER_NAME}"' -- '"${file}"' "$@"' >> "${HOME}/.local/bin/blend_bin/${file}.${CONTAINER_NAME}"
                    chmod 755 "${HOME}/.local/bin/blend_bin/${file}.${CONTAINER_NAME}"
                fi
            elif [[ "$action" == *"DELETE"* ]]; then
                rm -f "${HOME}/.local/bin/blend_bin/${file}.${CONTAINER_NAME}"
            elif [[ "$action" == *"MOVED_FROM"* ]]; then
                rm -f "${HOME}/.local/bin/blend_bin/${file}.${CONTAINER_NAME}"
            elif [[ "$action" == *"MOVED_TO"* ]]; then
                if [[ ! -f "${HOME}/.local/bin/blend_bin/${file}.${CONTAINER_NAME}" ]] && [[ -x "/usr/bin/${file}" ]]; then
                    mkdir -p "${HOME}/.local/bin/blend_bin"
                    echo "#!/bin/bash" > "${HOME}/.local/bin/blend_bin/${file}.${CONTAINER_NAME}"
                    echo '[ -f /run/.containerenv ] && { if [[ -e "/usr/bin/'"${file}"'" ]]; then /usr/bin/'"${file}"' "$@"; exit $?; else echo "This command can be accessed from the host, or from the container '"'${CONTAINER_NAME}'"'."; exit 127; fi } || :' >> "${HOME}/.local/bin/blend_bin/${file}.${CONTAINER_NAME}"
                    echo 'BLEND_ALLOW_ROOT= BLEND_NO_CHECK= blend enter -cn '"${CONTAINER_NAME}"' -- '"${file}"' "$@"' >> "${HOME}/.local/bin/blend_bin/${file}.${CONTAINER_NAME}"
                    chmod 755 "${HOME}/.local/bin/blend_bin/${file}.${CONTAINER_NAME}"
                fi
            fi
        fi ) &
        ( if [[ "$dir" == "/usr/share/applications/" ]]; then
            if [[ "$action" == *"CREATE"* ]] || [[ "$action" == *"MOVED_TO"* ]]; then
                if [[ "$file" == *'.desktop' ]]; then
                    echo -n > "${HOME}/.local/share/applications/blend;${CONTAINER_NAME};${file}"

                    while read -r line; do
                        if [[ $line == Name* ]]; then
                            echo "${line} (${CONTAINER_NAME})" >> "${HOME}/.local/share/applications/blend;${CONTAINER_NAME};${file}"
                        elif [[ $line == Exec* ]]; then
                            echo "Exec=blend enter -cn ${CONTAINER_NAME} -- ${line:5}" >> "${HOME}/.local/share/applications/blend;${CONTAINER_NAME};${file}"
                        elif [[ $line == Icon* ]]; then
                            if [[ -e "${line:5}" ]]; then
                                mkdir -p "${HOME}/.local/share/blend/icons/${CONTAINER_NAME}_${file}"; cp "${line:5}" "${HOME}/.local/share/blend/icons/${CONTAINER_NAME}_${file}"
                                echo "Icon=${HOME}/.local/share/blend/icons/${CONTAINER_NAME}_${file}/$(basename "${line:5}")" >> "${HOME}/.local/share/applications/blend;${CONTAINER_NAME};${file}"
                            else
                                ICON_PATH="$(find /usr/share/icons/hicolor -type f -iname "*${line:5}*" -print -quit 2>/dev/null)"
                                mkdir -p "$(dirname "${ICON_PATH}" | sed 's/\/usr\/share/'"\/home\/${_uname}"'\/.local\/share/g')"
                                FINAL_ICON_PATH="$(dirname "${ICON_PATH}" | sed 's/\/usr\/share/'"\/home\/${_uname}"'\/.local\/share/g')/$(echo "${file%.*}").$(basename "${ICON_PATH}" | sed 's/^.*\.//')"
                                cp "${ICON_PATH}" "${FINAL_ICON_PATH}" &>/dev/null
                                echo "Icon=${FINAL_ICON_PATH}" >> "${HOME}/.local/share/applications/blend;${CONTAINER_NAME};${file}"
                            fi
                        else
                            echo "$line" >> "${HOME}/.local/share/applications/blend;${CONTAINER_NAME};${file}"
                        fi
                    done < "/usr/share/applications/${file}"

                    sed -i 's/DBusActivatable=true/DBusActivatable=false/g' "${HOME}/.local/share/applications/blend;${CONTAINER_NAME};${file}"
                    sed -i '/^TryExec/d' "${HOME}/.local/share/applications/blend;${CONTAINER_NAME};${file}"

                    chmod 755 "${HOME}/.local/share/applications/blend;${CONTAINER_NAME};${file}"
                fi
            elif [[ "$action" == *"DELETE"* ]]; then
                rm -f "${HOME}/.local/share/applications/blend;${CONTAINER_NAME};${file}"
            elif [[ "$action" == *"MOVED_FROM"* ]]; then
                rm -f "${HOME}/.local/share/applications/blend;${CONTAINER_NAME};${file}"
            fi
        fi ) &
    done &

while true; do
    for i in /etc/hosts /etc/localtime /etc/resolv.conf; do
        cp "/run/host/${i}" / &>/dev/null || :
    done
    sleep 5
done