#!/bin/bash
set -e

init_logging(){
    if [ ! -d /var/log/snigdhaos/ ]; then
        # shellcheck disable=SC2174
        mkdir -p -m 755 /var/log/snigdhaos/
    fi

    echo -e "\n>-<->-< snigdhaos-updater at $(date +"%Y-%m-%d %R %Z(%:::z)")\n" >>/var/log/snigdhaos/snigdhaos-updater
    exec &> >(stdbuf -i0 -o0 -e0 tee >(sed '/\x1b\[[0-9][EF]/d;/\r[^\n]$/d;s,\x1B\[[0-9;]*[a-zA-Z],,g' >>/var/log/snigdhais/snigdhaos-updater)) 
}

parse_pacman_log(){
    sed -i -r "s/\x1B\[([0-9]{1,3}(;[0-9]{1,2};?)?)?[mGK]//g" "$AUTOPACMAN_LOG"
    local reason
    reason="$(tac "$AUTOPACMAN_LOG" | grep -oP -m 1 '(?<=error: failed to commit transaction \().*(?=\))')"
    case "$reason" in
        "invalid or corrupted package"*)
            RETRY="Snigdha OS Updater Found Corrupted Packages😑. Retying..."
            CUSTOM_PACMAN_CONFIG="$(mktemp)"
            # shellcheck disable=SC2016
            sed 's|Include = /etc/pacman.d/chaotic-mirrorlist|Server = https://cdn-mirror.chaotic.cx/$repo/$arch|g' /etc/pacman.conf > "$CUSTOM_PACMAN_CONFIG"
            pacman_args+=("--config" "$CUSTOM_PACMAN_CONFIG")
            ;;
        "download library error")
            RETRY="Snigdha OS Updater Found Corrupted Packages😑. Retying..."
            CUSTOM_PACMAN_CONFIG="$(mktemp)"
            sed '/^ParallelDownloads.*/d' /etc/pacman.conf >"$CUSTOM_PACMAN_CONFIG"
            pacman_args+=("--config" "$CUSTOM_PACMAN_CONFIG")
            ;;
        "conflicting files")
                tac "$AUTOPACMAN_LOG" | gawk 'BEGIN { exitcode=1 }
            /error: failed to commit transaction \(conflicting files\)/ { exit exitcode }
            /\S+: (.*) exists in filesystem/ { if ($0 ~ /\S+:\/usr\/lib\/python[^\/]+\/site-packages\/[^/]+\/__pycache__\/.+\.pyc exists in filesystem/) { exitcode=0 } else { exit 1 } }
            ENDFILE {exit 1}' && pacman_args+=("--overwrite" "/usr/lib/python*/site-packages/*/__pycache__/*.pyc") && RETRY="Overwriting Pycache file conflicts..." || true
                ;;
        esac
}

update_mirrorlist(){
    if [[ -v SKIP_MIRRORLIST ]]; then
        return
    fi
    local MIRRORLIST_TEMP MINLINES=0
    MIRRORLIST_TEMP="$(mktemp)"
    # Rate-Mirrors
    if command -v rate-mirrors >/dev/null; then
        MINLINES=10
        echo -e "\n\033[0;96m=>\033[0;96m [Rate-Mirrors]Refreshing Mirrorlist...🛸\033[0m"
        rate-mirrors --allow-root --save="$MIRRORLIST_TEMP" arch --max-delay=21600 >/dev/null || { rm "$MIRRORLIST_TEMP"; }
        $INT
    # Reflector
    elif command -v reflector >/dev/null; then
        MINLINES=5
        echo -e "\n\033[0;96m=>\033[0;96m [Reflector]Refreshing Mirrorlist...🛸\033[0m"
        reflector --latest 10 --age 2 --fastest 10 --protocol https --sort rate --save "$MIRRORLIST_TEMP" || { rm "$MIRRORLIST_TEMP"; }
        $INT
    else
        return
    fi

    # What if we are not using rate-mirrors and reflector?
    if [ ! -f "$MIRRORLIST_TEMP" ]; then
        echo -e "\033[0;91mMirrorlist Update Failed!\033[0m"
        return
    fi

    if COUNT="$(grep -Ec "^Server *=" "$MIRRORLIST_TEMP")" &&  [ "$COUNT" -ge "$MINLINES" ]; then
        install -m644 "$MIRRORLIST_TEMP" /etc/pacman.d/mirrorlist
        # shellcheck disable=SC2034
        DATABASE_UPDATED="force"
    else
        echo -e "\033[0;31Mirror Count Not Satisfied!\033[0m"
    fi

    echo
    rm "$MIRRORLIST_TEMP"
}

do_update(){
    if [ -x /usr/bin/expect ]; then
        local AUTOPACMAN_LOG EXIT=0 RETRY=false CUSTOM_PACMAN_CONFIG="" SUCCESS=false
        if [ ! -v AUTOPACMAN_CONFLICTSFILE ]; then
            local AUTOPACMAN_CONFLICTSFILE
            AUTOPACMAN_CONFLICTSFILE="$(mktemp -u)"
        fi
        AUTOPACMAN_LOG="$(mktemp)"
        LANG=C LANGUAGE=C LC_ALL=C AUTOPACMAN_LOG="$AUTOPACMAN_LOG" AUTOPACMAN_PACMAN_NOCONFIRM="$PACMAN_NOCONFIRM" AUTOPACMAN_CONFLICTSFILE="$AUTOPACMAN_CONFLICTSFILE" /usr/lib/snigdhaos/snigdhaos-updater/auto-pacman "$PACMAN" "${pacman_args[@]}" || { EXIT=$?; }
        if [ -n "$CUSTOM_PACMAN_CONFIG" ]; then 
            rm "$CUSTOM_PACMAN_CONFIG"
        fi

        if [ "$EXIT" == "134" ] || [ "$EXIT" == "0" ]; then
            SUCCESS=true
        fi

        if [ "$SUCCESS" != "true" ] && [ -z "$ALREADY_RETRIED" ]; then
            parse_pacman_log
        fi

        rm "$AUTOPACMAN_LOG"

        if [ "$RETRY" != "false" ]; then
            echo -e "\n\033[0;96m=>\033[0;96m $RETRY \n\033[0m"
            ALREADY_RETRIED=true do_update
            return
        fi
        if [ -v AUTOPACMAN_CONFLICTSFILE ]; then
            rm -f "$AUTOPACMAN_CONFLICTSFILE"
            unset AUTOPACMAN_CONFLICTSFILE
        fi
        if [ "$SUCCESS" == "false" ]; then
            false
        fi
    else
        $PACMAN "${pacman_args[@]}"
    fi
}

show_changelog(){
    if [ -e "/var/log/snigdhaos/tmp/update_notices" ]; then
        echo -e "\033[0;96mUpdate:\n\033[0;96m$(gawk -F '\t' '{print $2}' /var/lib/snigdhaos/tmp/update_notices)\n\033[0m"
        rm /var/lib/snigdhaos/tmp/update_notices
    fi
}

if [ -f /etc/snigdhaos/snigdhaos-updater/config ]; then
    # shellcheck disable=SC1091
    source /etc/snigdhaos/snigdhaos-updater/config
fi

PARAMETERS=("$@")
PARSED_OPTIONS=$(getopt --options="a" --longoptions="aur,skip-mirrorlist,noconfirm" --name "$0" -- "${PARAMETERS[@]}")

if [[ $? -ne 0 ]]; then
	echo -e "\033[0;31m\nFailed to parse CLI options\n\033[0m"
fi
eval set -- "$PARSED_OPTIONS"
while true; do
	case "$1" in
	-a | --aur)
		UPDATE_AUR=1
		shift
		;;
	--skip-mirrorlist)
		SKIP_MIRRORLIST=1
		shift
		;;
	--noconfirm)
		PACMAN_NOCONFIRM=1
		shift
		;;
	--)
		shift

		if [ "$SNIGDHAOS_UPDATE_SELFUPDATE" == 1 ] && [ "$#" -eq 1 ] && [ -z "$1" ]; then
			break
		fi
		PACMAN_EXTRA_OPTS+=("${@}")
		break
		;;
	*)
		echo "Programming error"
		exit 3
		;;
	esac
done

if grep -qE 'subvol=@/.snapshots/[0-9]+/snapshot' /proc/cmdline && [[ ! -v GARUDA_SNAPSHOT_PACMAN ]]; then
	echo -e "\033[0;31mError: You are currently booted into a snapshot. Please restore the snapshot via btrfs-assistant or snapper-tools before updating your system.\n\033[0;34mNote: You can ignore this error by setting SNIGDHAOS_SNAPSHOT_PACMAN: SNIGDHAOS_SNAPSHOT_PACMAN=1 snigdhaos-updater\n\033[1;31mAny modifications made to this snapshot will be lost next reboot. ❌\033[0m"
	exit 1
fi

init_logging

/usr/lib/snigdhaos/snigdhaos-updater/aux-script migrate-snigdhaos-repo && DATABASE_UPDATED=false || true

update_mirrorlist
self_update "${PARAMETERS[@]}"

/usr/lib/snigdhaos/snigdhaos-updater/aux-scripts pre-update-routines || { if [ "$?" -eq 2 ]; then self_update "${PARAMETERS[@]}"; fi; }

pacman_args=("-Su")
if [ "$DATABASE_UPDATED" == false ]; then pacman_args+=("-y"); elif [ "$DATABASE_UPDATED" == "force" ]; then pacman_args+=("-yy"); fi
while IFS= read -r line; do
	pacman_args+=("$line")
done < <(/usr/lib/snigdhaos/snigdhaos-updater/aux-scripts package-replaces)

if [ -v PACMAN_EXTRA_OPTS ]; then
	pacman_args+=("${PACMAN_EXTRA_OPTS[@]}")
fi

do_update

if [[ -v UPDATE_AUR ]]; then
	
	if [ -x /usr/bin/paru ] && [[ -n "$SUDO_UID" ]]; then
		echo -e "\n\033[1;33m-->\033[0;34m Updating AUR packages with paru..\033[0m"
		sudo -u "#$SUDO_UID" paru -Sua || { echo -e "\033[1;31m\nParu exited with error code $?\n\033[0m"; }
	elif [ -x /usr/bin/yay ] && [[ -n "$SUDO_UID" ]]; then
		echo -e "\n\033[0;33m-->\033[0;34m Updating AUR packages with yay..\033[0m"
		sudo -u "#$SUDO_UID" yay -Sua || { echo -e "\033[1;31m\nYay exited with error code $?\n\033[0m"; }
	else
		echo -e "\n\033[0;33m--> UPDATE_AUR specified but no supported AUR helper found ❌\033[0m"
	fi
	$INT
fi

if [ -x /usr/bin/locate ]; then
	systemctl start updatedb.service --no-block
fi

/usr/lib/snigdhaos/snigdhaos-updater/aux-scripts verify-core

echo -e "\n\033[1;32m[SUCCESS]System updated ! \n\033[0m"
show_changelog
