#!/bin/bash

# Downgrade EndeavourOS (and Arch) packages.
#
# Usage: eos-downgrade names-of-packages
#
# Package sources:
# - local package cache
# - latest available EndeavourOS packages at github
# - archived older EndeavourOS packages at github (currently many previous releases are missing)
#
# Caveats:
# - beta status ==> warning for potential bugs!
# - requires github.com currently for EOS packages
# - only x86_64 architecture

printf2() { printf "$@" >&2 ; }
echo2()   { echo "$@" >&2 ; }

warn2()   { echo2 "==> $progname: warning:" "$@" ; }

Usage() {
    local exit_code="$1"

    cat <<EOF >&2
Downgrade EndeavourOS and Arch packages.

Note: The EndeavourOS files will be fetched from github.com.
      This may cause issues in some locations.

Usage: $progname [options] <package-name(s)>
Options:
    -h, --help     This help.

EOF
    [ -n "$exit_code" ] && exit $exit_code
}

AddRemoteCurrent() {
    echo2 "==> checking latest remote packages ..."

    local url="https://github.com/endeavouros-team/repo/tree/master/endeavouros/$arch"
    local remote_currents

    remote_currents=$(curl -Lsm 30 -o- "$url" | grep '\.pkg\.tar\.' | grep ' Link--primary" title=' | grep -Pv '\.sig"'| sed -e 's|.* title="\([^"]*\)".*|\1|' -e 's|^|latest:  |')

    if [ -n "$remote_currents" ] ; then
        data_latest=$(printf "%s\n" "$remote_currents")
    fi
}

AddRemoteArchive() {
    # Get archived remote pkgname without folders.
    echo2 "==> checking remote package archive ..."

    local contents code=0
    local remote_filenames
    local archive_url=https://github.com/endeavouros-team/archive/releases/expanded_assets/packages

    contents=$(curl --fail -Lsm 10 -o- "$archive_url")
    code=$?
    if [ $code -ne 0 ] ; then
        warn2 "no data received from the package archive, curl code $code"
        return 1
    fi
    remote_filenames="$(echo "$contents" | grep '/packages/.*pkg\.tar\.[zx][zxst]*"'  | sed -e 's|.*/packages/\([^"]*\)".*|\1|' -e 's|^|archive: |')"

    if [ -n "$remote_filenames" ] ; then
        data_archive=$(printf "%s\n" "$remote_filenames")
    else
        warn2 "fetched package archive data is empty"
    fi
}

AddLocals() {
    local pn="$1"
    local local_filenames
    local locals=()
    local tmp
    local pkg pkgname

    local_filenames=$(/usr/bin/ls -1 /var/cache/pacman/pkg/${pn}-*.{zst,xz} 2>/dev/null | sed 's|^/var/cache/pacman/pkg/||')

    for pkg in $local_filenames ; do
        pkgname=$(pkg-name-components N "$pkg")     # !!!!
        if IsEosPkg "$pkgname" ; then
            locals+=("$pkg")
        fi
    done

    if [ ${#locals[@]} -gt 0 ] ; then
        data_cache=$(printf "cache:   %s\n" "${locals[@]}" | grep -Pv "^cache:[ ]*$")
    fi
}

Options() {
    local opts

    opts="$(/usr/bin/getopt -o=h --longoptions help --name "$progname" -- "$@")" || {
        Options -h
        return 1
    }

    eval set -- "$opts"

    while true ; do
        case "$1" in
            -h | --help)  Usage 0 ;;
            
            --) shift ; break ;;
        esac
        shift
    done
    [ -n "$1" ] || Usage 1
    pkgnames=("$@")
}

Main_eos() {
    if [ -z "$1" ] ; then
        return
    fi
    local arch=x86_64
    local data data_cache="" data_latest="" data_archive=""

    local archive_dl_url=https://github.com/endeavouros-team/archive/releases/download/packages
    local latest_dl_url=https://github.com/endeavouros-team/repo/raw/master/endeavouros/$arch

    AddRemoteArchive
    AddRemoteCurrent

    local pkgname
    local filespec
    local URLs=() pkgs=()

    for pkgname in "$@" ; do
        AddLocals "$pkgname"
        data=$(printf "%s\n" "$data_cache" "$data_latest" "$data_archive" | sort -V)
        filespec="$(echo "$data" | grep "$pkgname" | fzf --tac)"
        case "$?" in
            0) ;;
            *) echo2 "Nothing for $pkgname."
               continue
               ;;
        esac
        case "$filespec" in
            "cache:"*)   filespec="/var/cache/pacman/pkg/$(   echo "$filespec" | awk '{print $2}')" ;;
            "latest:"*)  filespec="$latest_dl_url/$(          echo "$filespec" | awk '{print $2}')" ;;
            "archive:"*) filespec="$archive_dl_url/$(         echo "$filespec" | awk '{print $2}')" ;;
            *)
                echo2 "Sorry, nothing found for $pkgname."
                continue
                ;;
        esac
        URLs+=("$filespec")
        pkgs+=("$pkgname")
    done

    if [ ${#URLs[@]} -gt 0 ] ; then
        commands_eos+=("pacman -U ${URLs[*]}")
        AddIgnoreAsk "${pkgs[@]}"
    fi
}

Main_arch() {
    if [ -n "$1" ] ; then
        commands_arch+=("/usr/bin/downgrade $*")
    fi
}

IsEosPkg() {
    local pkg="$1"
    local eos

    # Some (obviously EndeavourOS) packages may have been removed from the current EndeavourOS packages, but they may exist in archive or local cache.
    # Check them first.
    case "$pkg" in
        *-endeavouros | *-eos | endeavouros-* | eos-*) return 0 ;;
    esac
    for eos in $eos_pkgs ; do
        [ "$pkg" = "$eos" ] && return 0
    done
    return 1
}

Separate_packages() {
    local arg eos

    for arg in "$@" ; do
        if IsEosPkg "$arg" ; then
            pkgnames_eos+=("$arg")
        else
            pkgnames_arch+=("$arg")
        fi
    done

    if [ ${#pkgnames_arch[@]} -gt 0 ] ; then
        if [ ! -x /usr/bin/downgrade ] ; then
            echo2 "Install 'downgrade' to downgrade Arch packages: ${pkgnames_arch[*]}"
            return 1
        fi
    fi
}

AddIgnore() {
    local pkg="$1"
    local sedline="/packages listed in IgnorePkg/a \IgnorePkg = $pkg"

    commands_eos+=("sed -i $file -e \"$sedline\"")
}

AddIgnoreAsk() {
    local pkg reply
    local file=/etc/pacman.conf

    for pkg in "$@" ; do
        if [ -z "$(grep -w "$pkg" "$file" | grep "^IgnorePkg[ ]*=")" ] ; then   # should check commenting as well...
            read -p "add $pkg to IgnorePkg? [y/N] " reply >&2
            case "$reply" in
                [Yy]*) AddIgnore "$pkg" ;;
            esac
        fi
    done
}

Main() {
    local progname=eos-downgrade
    local pkgnames=()
    local pkgnames_eos=() pkgnames_arch=()
    local commands_eos=() commands_arch=()
    local eos_pkgs=$(pacman -Sl endeavouros | awk '{print $2}')

    source /usr/share/endeavouros/scripts/eos-script-lib-yad || return 1

    Options "$@"

    Separate_packages "${pkgnames[@]}" || return 1

    Main_eos  "${pkgnames_eos[@]}"
    Main_arch "${pkgnames_arch[@]}"

    if [ ${#commands_eos[@]} -gt 0 ] ; then
        echo "==> EndeavourOS downgrades:"
        printf "   %s\n" "${commands_eos[@]}"
        commands_eos=$(printf "%s; " "${commands_eos[@]}")
        $EOS_ROOTER "$commands_eos"
    fi

    if [ ${#commands_arch[@]} -gt 0 ] ; then
        echo "==> Arch downgrades:"
        printf "   %s\n" "${commands_arch[@]}"
        commands_arch=$(printf "%s; " "${commands_arch[@]}")
        $EOS_ROOTER "$commands_arch"
    fi
}

Main "$@"
