#!/bin/bash

# Manager for manual interventions.

echo2() { echo -e "$@" >&2; }
WARN()  { echo2 "==> $progname: warning: $1"; }
DIE()   { echo2 "==> $progname: error: $1"; exit 1; }

RUN() {
    echo2 "   ->" "$@"
    if "$@" ; then
        return 0
    else
        DIE "'$*' failed."
        exit 1
    fi
}

MarkOk() {
    echo2 "  ==> marking '$1' as handled"
    echo "$1" >> "$handled_fixes"
}
IsOk() { grep "^$1$" "$handled_fixes" &>/dev/null; }

FetchInterventionsFile() {
    local -r pname=eos-manual-intervention
    local -r fname=$pname.interventions
    local -r github=https://raw.githubusercontent.com/endeavouros-team/PKGBUILDS/master/$pname/$fname
    local -r gitlab=https://gitlab.com/endeavouros-filemirror/PKGBUILDS/raw/master/$pname/$fname

    if [ ! -d "$dir" ] ; then
        mkdir -p "$dir" || DIE "cannot create folder '${dir/$HOME/\~}'"
    fi

    wget -qO "$mifile" "$github" || wget -qO "$mifile" "$gitlab"

    if [ $(stat -c %s "$mifile") -gt 0 ] ; then
        source "$mifile"
    else
        DIE "failed to download ${mifile/$HOME/\~} from github/gitlab"
    fi
}

RunInterventionsIfNeeded() {
    local count=${#MI_func_names[@]}
    local ix mifunc descr
    local ret=2
    local updated=no

    # ret:
    #      0 = intervention handled and system updated ==> all is OK
    #      1 = error occurred
    #      2 = intervention marked as OK but system might not be updated

    if [ $only_show_count = yes ] ; then
        echo "$((count/2))"
        return 2
    fi

    if [ $count -eq 0 ] ; then
        echo2 "==> No manual interventions available."
        return 2
    fi

    for ((ix=0; ix < count; ix+=2)) ; do
        mifunc="${MI_func_names[$ix]}"
        descr="${MI_func_names[$((ix+1))]}"
        if IsOk "$mifunc" ; then
            echo2 "$mifunc:\talready OK"
        else
            echo2 "$mifunc: $descr"
            $mifunc
            ret=$?
            case "$ret" in
                0) MarkOk "$mifunc"; updated=yes ;;
                2) MarkOk "$mifunc" ;;
                1) break ;;
            esac
        fi
    done

    Cleanup

    case "$ret" in
        0|2) [ $updated = yes ] && ret=0 ;;
    esac
    return $ret
}

NewsPage() {
    local bb
    for bb in exo-open kde-open xdg-open firefox ; do
        if [ -x /bin/$bb ] ; then
            /bin/$bb https://archlinux.org/news &
            break
        fi
    done
    [ "$1" ] && exit $1
}

CheckPacmanConf() {
    local -r conf=/etc/pacman.conf
    local lines="$(grep -n "^[ \t]*IgnorePkg[ \t]*=[ \t]*[a-zA-Z0-9]" $conf)"
    if [ "$lines" ] ; then
        cat <<EOF >&2

==> $progname: warning:
==> File $conf contains IgnorePkg line(s).
    This *may* affect manual interventions because partial upgrades are not supported.
EOF
        readarray -t lines < <(echo "$lines")
        printf "      %s\n" "${lines[@]}" >&2
        echo2 ""

        local reply=""
        read -p "==> Do you want to continue [yes/NO]? " reply >&2
        case "$reply" in
            [yY]*) ;;
            *) exit 0 ;;
        esac
    fi
}

Cleanup() {
    rm -f "$mifile"
}

Help() {
    cat <<EOF >&2
Purpose: Execute and manage essential manual interventions.
Usage:   $progname [options]
Options: -h, --help            This help.
         -n, --show-arch-news  Show the Arch news page in a browser.
         --count               Only show the number of available interventions, don't run them.
EOF
    [ "$1" ] && exit $1
}

Options() {
    local arg
    for arg in "$@" ; do
        case "$arg" in
            -h | --help)           Help 0 ;;
            -n | --show-arch-news) NewsPage 0 ;;
            --count)               only_show_count=yes ;;
        esac
    done
}

Main() {
    local -r progname=${0##*/}
    local -r dir="$HOME/.config/$progname"
    local -r mifile="$dir/$progname.interventions"
    local -r handled_fixes="$dir/$progname.handled"
    local MI_func_names=()
    local only_show_count=no

    Options "$@"
    CheckPacmanConf
    FetchInterventionsFile
    RunInterventionsIfNeeded
}

Main "$@"
