#!/bin/bash

set -o pipefail

MOUNTPOINT="/mnt"
CHROOT="$MOUNTPOINT"

LOGFILE="/tmp/snukware-installer.log"
DISK_TMP="/tmp/snuk_disk"
SWAP_TMP="/tmp/snuk_swap"
ROOT_TMP="/tmp/snuk_root"

BACKTITLE="Snukware Installer"
SET="/slackware"
dots=".bashrc .bash_profile .vim .vimrc"

export LANG=C.UTF-8
export LC_ALL=C.UTF-8
export TERM=${TERM:-xterm-256color}

# -------------------------
# LOG
# -------------------------
log() {
  echo "$(date): $*" >> "$LOGFILE"
}

# -------------------------
# CHECK DEPENDENCIES
# -------------------------
require() {
  command -v "$1" >/dev/null 2>&1 || {
    echo "$1 missing"
    exit 1
  }
}

require dialog
require sgdisk
require lsblk
require mount

# -------------------------
# SAFE DIALOG WRAPPER
# -------------------------
dlg_yesno() {
  dialog --clear --backtitle "$BACKTITLE" --yesno "$1" 8 60
  return $?
}

dlg_input() {
  local out="$1"
  shift
  dialog --clear --backtitle "$BACKTITLE" --inputbox "$@" 2> "$out"
  return $?
}

dlg_msg() {
  dialog --msgbox "$1" 8 60
}


# -------------------------
# CREATE PARTITIONS
# -------------------------
# =========================================================
# PARTITIONING (FIXED)
# =========================================================
create_part() {

stty sane
clear
reset

if [ -d /sys/firmware/efi ]; then
    MODE="UEFI"
else
    MODE="BIOS"
fi

log "Mode=$MODE"

# -------------------------
# FUNCTIONS (OK inside)
# -------------------------
detect_windows() {
    for p in $(lsblk -rpno NAME,FSTYPE | awk '$2=="ntfs"{print $1}'); do
        mkdir -p /tmp/wincheck

        mount -o ro "$p" /tmp/wincheck 2>/dev/null || continue

        if [ -f /tmp/wincheck/bootmgr ] || \
           [ -d /tmp/wincheck/Windows/System32 ]; then
            umount /tmp/wincheck
            echo "$p"
            return 0
        fi

        umount /tmp/wincheck
    done
    return 1
}

find_efi_partition() {
    lsblk -rpno NAME,PARTTYPE | awk '
    tolower($2)=="c12a7328-f81f-11d2-ba4b-00a0c93ec93b" {print $1}'
}

has_free_space() {
    local disk="$1"
    local start end
    start=$(sgdisk -F "$disk" 2>/dev/null)
    end=$(sgdisk -E "$disk" 2>/dev/null)
    [ -n "$start" ] && [ -n "$end" ]
}

list_other_disks() {
    local current="$1"
    lsblk -dpno NAME | grep -E "/dev/(sd|nvme|vd)" | while read -r d; do
        [ "$d" = "$current" ] && continue
        echo "$d"
    done
}

# -------------------------
# DISK SELECTION
# -------------------------
DISKS=$(lsblk -dpno NAME,SIZE,MODEL | grep -E "/dev/(sd|nvme|vd)" || true)

MENU=()
while read -r line; do
    [ -z "$line" ] && continue
    DEV=$(echo "$line" | awk '{print $1}')
    SIZE=$(echo "$line" | awk '{print $2}')
    MODEL=$(echo "$line" | cut -d' ' -f3-)
    MENU+=("$DEV" "$SIZE $MODEL")
done <<< "$DISKS"

[ ${#MENU[@]} -eq 0 ] && { dlg_msg "No disks found"; return 1; }

: > "$DISK_TMP"

dialog --backtitle "$BACKTITLE - $MODE" \
--menu "Select target disk" \
15 70 6 \
"${MENU[@]}" \
2> "$DISK_TMP"

DISK=$(<"$DISK_TMP")
[ -z "$DISK" ] && return 1

# -------------------------
# FIX PREFIX
# -------------------------
if [[ "$DISK" == *nvme* ]]; then
    PFX="${DISK}p"
else
    PFX="${DISK}"
fi

INSTALL_MODE=""
WINDOWS_EFI=""
WIN_PART=$(detect_windows)

# -------------------------
# WINDOWS LOGIC
# -------------------------
if [ -n "$WIN_PART" ]; then
    if ! has_free_space "$DISK"; then

        OTHER_DISKS=$(list_other_disks "$DISK")

        if [ -n "$OTHER_DISKS" ]; then
            dialog --backtitle "$BACKTITLE" \
            --title "Windows detected" \
            --yesno \
"Windows uses full disk.

Other disk:
$OTHER_DISKS

Install Linux there and reuse EFI?" \
            12 70

            [ $? -ne 0 ] && return 1

            DISK=$(echo "$OTHER_DISKS" | head -n 1)

            if [[ "$DISK" == *nvme* ]]; then
                PFX="${DISK}p"
            else
                PFX="${DISK}"
            fi

            WIN_PART="external"
            WINDOWS_EFI=$(find_efi_partition)
            INSTALL_MODE=3
        else
            dlg_msg "No free space / no second disk."
            return 1
        fi
    fi
fi

# -------------------------
# MODE
# -------------------------
if [ -z "$INSTALL_MODE" ]; then
    if [ -n "$WIN_PART" ]; then
        dialog --backtitle "$BACKTITLE" \
        --menu "Install mode" \
        12 60 2 \
        1 "Erase disk" \
        2 "Install beside Windows" \
        2> /tmp/snuk_mode

        INSTALL_MODE=$(cat /tmp/snuk_mode)
    else
        INSTALL_MODE=1
    fi
fi

# -------------------------
# INPUTS
# -------------------------
: > "$SWAP_TMP"
dlg_input "$SWAP_TMP" "Swap size (MB):" 8 50 2048 || return 1
SWAP_SIZE=$(<"$SWAP_TMP")

[[ ! "$SWAP_SIZE" =~ ^[0-9]+$ ]] && { dlg_msg "Invalid swap"; return 1; }

: > "$ROOT_TMP"
dlg_yesno "Use all remaining space?"

if [ $? -eq 0 ]; then
    ROOT_SIZE="AUTO"
else
    dlg_input "$ROOT_TMP" "Root size (GB):" 8 50 50 || return 1
    ROOT_SIZE=$(<"$ROOT_TMP")
fi

# =========================================================
# PARTITIONING FIX (NO SUBSHELL PROBLEMS)
# =========================================================
{
echo 10
echo "Preparing disk..."

EFI_REUSE=0

if [ "$INSTALL_MODE" = "1" ]; then
    sgdisk --zap-all "$DISK" >/dev/null 2>&1
    sgdisk -o "$DISK" >/dev/null 2>&1

    if [ "$MODE" = "UEFI" ]; then
        sgdisk -n 1:0:+512M -t 1:EF00 -c 1:"efi" "$DISK"
        PART_BASE=2
    else
        sgdisk -n 1:1MiB:+2MiB -t 1:EF02 -c 1:"biosboot" "$DISK"
        PART_BASE=2
    fi
else

    FREE_START=$(sgdisk -F "$DISK")
    FREE_END=$(sgdisk -E "$DISK")

    if [ -z "$FREE_START" ] || [ -z "$FREE_END" ]; then
        dlg_msg "No free space"
        return 1
    fi

    if [ "$INSTALL_MODE" != "3" ]; then
        EFI=$(find_efi_partition)
        EFI_REUSE=1
    fi

    LASTNUM=$(sgdisk -p "$DISK" | awk '/^[ ]*[0-9]+/ {n=$1} END {print n}')
    PART_BASE=$((LASTNUM+1))
fi

echo 40
echo "Creating partitions..."

if [ "$ROOT_SIZE" = "AUTO" ]; then
    sgdisk -n ${PART_BASE}:0:-${SWAP_SIZE}M -t ${PART_BASE}:8300 -c ${PART_BASE}:"root" "$DISK"
    sgdisk -n $((PART_BASE+1)):0:0 -t $((PART_BASE+1)):8200 -c $((PART_BASE+1)):"swap" "$DISK"
else
    sgdisk -n ${PART_BASE}:0:+${ROOT_SIZE}G -t ${PART_BASE}:8300 -c ${PART_BASE}:"root" "$DISK"
    sgdisk -n $((PART_BASE+1)):0:+${SWAP_SIZE}M -t $((PART_BASE+1)):8200 -c $((PART_BASE+1)):"swap" "$DISK"
fi

echo 60
echo "Syncing..."

partprobe "$DISK"  >/dev/null 2>&1
udevadm settle  >/dev/null 2>&1
sleep 2

ROOT="${PFX}${PART_BASE}"
SWAP="${PFX}$((PART_BASE+1))"

# HARD CHECK
[ -b "$ROOT" ] || return 1
[ -b "$SWAP" ] || return 1

# EFI
EFI=""
EFI_REUSE=0

if [ "$MODE" = "UEFI" ]; then
    if [ "$INSTALL_MODE" = "1" ]; then
        EFI="${PFX}1"
        EFI_REUSE=0
    elif [ "$INSTALL_MODE" = "3" ]; then
        EFI="$WINDOWS_EFI"
        EFI_REUSE=1
    else
        EFI="${PFX}1"
        EFI_REUSE=1
    fi
fi

echo 75

echo "Formatting..."
mkfs.ext4 -F "$ROOT"  >/dev/null 2>&1 || return 1
mkswap "$SWAP"  >/dev/null 2>&1 || return 1

if [ "$MODE" = "UEFI" ] && [ "$EFI_REUSE" -eq 0 ]; then
    mkfs.fat -F32 "$EFI"  >/dev/null 2>&1 || return 1
fi

echo 90

echo "Mounting..."

mkdir -p "$MOUNTPOINT"
mount "$ROOT" "$MOUNTPOINT" || return 1
swapon "$SWAP" || return 1

if [ "$MODE" = "UEFI" ]; then
    mkdir -p "$MOUNTPOINT/boot/efi"
    mount "$EFI" "$MOUNTPOINT/boot/efi" || return 1
fi

echo 100
echo "Done"
} | dialog --gauge "Partitioning..." 10 60 0
}

inst_pkg() {

PKGDIR="/slackware"

SERIES_ORDER=(
    a
    ap
    d
    e
    l
    n
    p
    t
    tcl
    x
    xap
    kde
    xfce
    lxqt
    y
)

run() {

    PKGS=()

    #
    # Build package list
    #
    for SERIES in "${SERIES_ORDER[@]}"; do

        [ -d "$PKGDIR/$SERIES" ] || continue

        while IFS= read -r PKG; do
            PKGS+=("$PKG")
        done < <(
            find "$PKGDIR/$SERIES" \
                -maxdepth 1 \
                -type f \
                -name "*.txz" \
                | sort
        )

    done

    TOTAL=${#PKGS[@]}

    if [ "$TOTAL" -eq 0 ]; then
        dialog \
            --title "Snukware Installer" \
            --msgbox "No installation packages found in $PKGDIR" \
            8 60
        return 1
    fi

    (
        COUNT=0

        for PKG in "${PKGS[@]}"; do

            COUNT=$((COUNT + 1))
            PERCENT=$((COUNT * 100 / TOTAL))

            PKGNAME=$(basename "$PKG" .txz)

            #
            # Prevent long package names from stretching dialog
            #
            if [ ${#PKGNAME} -gt 60 ]; then
                PKGNAME="${PKGNAME:0:57}..."
            fi

cat <<EOF
XXX
$PERCENT
Installing the base system

Installing package $COUNT of $TOTAL
XXX
EOF
sleep 0.05

            installpkg \
                --root "$CHROOT" \
                "$PKG" >/dev/null 2>&1

        done

        cat <<EOF
XXX
100
Installing the base system

Configuring the installed system...
XXX
EOF


    ) | dialog \
        --title "Installing the base system" \
        --backtitle "$BACKTITLE" \
        --gauge "Preparing package installation..." \
        9 70 0

    return 0
}

#
# Standalone mode
#
run
}

install_sysd() {
chroot $CHROOT /bin/bash <<END
exec >/tmp/sysd-install.log 2>&1
source /etc/profile >/dev/null 2>&1
export DIALOGRC=/tmp/dialogrc
dialog --title "Updates" \
--backtitle "$BACKTITLE" \
--infobox "\ninstalling and configure systemd..." 5 55
installpkg /tmp/systemd/*.t?z >/dev/null 2>&1 || exit 1
sed -i 's/GENERATOR\=mkinitrd/GENERATOR\=dracut/g' /etc/default/geninitrd || exit 1
sed -i 's/AUTO_UPDATE_GRUB\=true/AUTO_UPDATE_GRUB\=false/g' /etc/default/geninitrd || exit 1
sed -i 's/GRUB_CMDLINE_LINUX_DEFAULT\=\"\"/GRUB_CMDLINE_LINUX_DEFAULT\=\"systemd.ssh_auto\=0 loglevel\=3 quiet\"/g' /etc/default/grub || exit 1
installpkg /tmp/k/*.t?z >/dev/null 2>&1 || exit 1
rm -rf /var/run >/dev/null 2>&1 || exit 1
ln -sf /run /var/run >/dev/null 2>&1 || exit 1
ln -sf /usr/bin/vim /usr/bin/vi || exit 1
groupadd -g 970 seat >/dev/null 2>&1
dialog --title "Configuration" \
--backtitle "$BACKTITLE" \
--infobox "\nconfiguring systemd services..." 5 55
sleep 10
install -m755 /tmp/snuk-firstboot /usr/sbin/ 2>&1 || exit 1
install -m644 /tmp/snukware-firstboot.service /etc/systemd/system/ 2>&1 || exit 1
install -m644 /tmp/update-motd.service /etc/systemd/system/ 2>&1 || exit 1
systemctl enable NetworkManager >/dev/null 2>&1 || exit 1
systemctl enable sshd >/dev/null 2>&1 || exit 1
systemctl enable accounts-daemon >/dev/null 2>&1 || exit 1
systemctl enable systemd-homed >/dev/null 2>&1 || exit 1
systemctl enable upower >/dev/null 2>&1 || exit 1
systemctl enable udisks2 >/dev/null 2>&1 || exit 1
systemctl enable seatd >/dev/null 2>&1 || exit 1
systemctl enable gdk-pixbuf-cache >/dev/null 2>&1 || exit 1
systemctl enable snukware-firstboot >/dev/null 2>&1 || exit 1
systemctl enable update-motd.service >/dev/null 2>&1 || exit 1
END
}

certs_upd() {
chroot "$CHROOT" /usr/sbin/update-ca-certificates >/dev/null 2>&1
}

set_accounts() {
install -m755 $SET/contrib/SeTpasswd $CHROOT/tmp/ || exit 1
install -m644 $SET/contrib/dialogrc $CHROOT/tmp/ || exit 1
chroot $CHROOT /bin/bash -l /tmp/SeTpasswd || exit 1
}

dhcp_NM() {
CONF=$CHROOT/etc/NetworkManager/conf.d/00-dhcp-client.conf
sed -i 's/dhcp\=dhcpcd/\#dhcp\=dhcpcd/g;s/\#dhcp\=internal/dhcp\=internal/g' $CONF || exit 1 
cat > $CHROOT/etc/resolv.conf <<EOF
nameserver 8.8.8.8 
nameserver 8.8.4.4
EOF
}

grub_upd() {

cat > "$CHROOT/tmp/grub_upd" <<'EOF'
#!/bin/bash

exec >/tmp/grub-install.log 2>&1

source /etc/profile >/dev/null 2>&1

if [ -f /etc/default/grub ]; then

    if grep -q '^GRUB_DISABLE_OS_PROBER=' \
        /etc/default/grub; then

        sed -i \
        's/^GRUB_DISABLE_OS_PROBER=.*/GRUB_DISABLE_OS_PROBER=false/' \
        /etc/default/grub

    else

        echo "GRUB_DISABLE_OS_PROBER=false" \
        >> /etc/default/grub

    fi

fi

if [ -d /sys/firmware/efi/efivars ]; then

    grub-install \
        --target=x86_64-efi \
        --efi-directory=/boot/efi \
        --bootloader-id=Snukware

else

    ROOTDEV=$(findmnt -n -o SOURCE /)

    ROOTDISK=$(lsblk -no PKNAME "$ROOTDEV")

    grub-install "/dev/${ROOTDISK}"

fi

if command -v os-prober >/dev/null 2>&1; then
    os-prober >/dev/null 2>&1
fi

grub-mkconfig -o /boot/grub/grub.cfg

EOF

chmod 0755 "$CHROOT/tmp/grub_upd" || exit 1

chroot "$CHROOT" /bin/bash /tmp/grub_upd || exit 1

rm -f "$CHROOT/tmp/grub_upd"

}

if [ -d "$CHROOT" ]; then 
	 dialog --ok-label "continue" --backtitle "$BACKTITLE" --msgbox "Welcome to Snukware Linux Installer" 5 40
	 create_part
	 inst_pkg
	 mount --types proc /proc $CHROOT/proc || exit 1
	 mount -o bind /sys $CHROOT/sys || exit 1
	 if [ -d /sys/firmware/efi/efivars ]; then
		 mount -o bind /sys/firmware/efi/efivars $CHROOT/sys/firmware/efi/efivars || exit 1
	 fi
	 mount -o bind /dev $CHROOT/dev || exit 1
	 mount -o bind /dev/pts $CHROOT/dev/pts || exit 1
	 dialog --title "Configuration" \
	 --backtitle "$BACKTITLE" \
	 --infobox "\nConfigure some component… this may take a few minutes..." 5 61
	 cp -r $SET/systemd $CHROOT/tmp/systemd || exit 1
	 cp -r $SET/k $CHROOT/tmp/k || exit 1
   	 install -m755 $SET/contrib/snuk-firstboot $CHROOT/tmp/ || exit 1
   	 install -m644 $SET/contrib/snukware-firstboot.service $CHROOT/tmp/ || exit 1
   	 install -m644 $SET/contrib/update-motd.service $CHROOT/tmp/ || exit 1
	 genfstab -U $CHROOT > $CHROOT/etc/fstab || exit 1
 else
	 echo "$CHROOT such file or directory does not exist"
	 exit 1
 fi

# update-ca-certificates
certs_upd

# enter chroot to install systemd and configure several services
install_sysd

 # install modified skel files
for i in ${dots[@]}; do
   cp -r $SET/contrib/skel/${i} $CHROOT/root/ || exit 1
   cp -r $SET/contrib/skel/${i} $CHROOT/etc/skel/ || exit 1
   cat $SET/contrib/motd > $CHROOT/etc/motd || exit 1
   cat $SET/contrib/os-release > $CHROOT/etc/os-release || exit 1
done


# sed dhclient as default NetworkManager dhcp-client
dhcp_NM

# set root and user-account
set_accounts

# install/update grub
dialog --title "Bootloader" \
--backtitle "$BACKTITLE" \
--infobox "\ninstalling GRUB bootloader..." 5 55
sleep 10

grub_upd

umount $CHROOT/proc || exit 1
	 if [ -d "$CHROOT"/sys/firmware/efi/efivars ]; then
		 umount "$CHROOT"/sys/firmware/efi/efivars || exit 1
	 fi
umount $CHROOT/sys || exit 1
umount $CHROOT/dev/pts || exit 1
umount $CHROOT/dev || exit 1

text="\n\n  Snukware succesfully installed"
width=40

padding=$(( (width - ${#text}) / 2 ))
printf -v centered "%*s%s" "$padding" "" "$text" 

dialog --title "Installation mode" \
--backtitle "$BACKTITLE" \
--msgbox "$centered" 8 "$width" 
