#!/bin/sh
#
# reprise - Diagnose and repair a broken SliTaz system.
#
# Copyright (C) 2026 SliTaz GNU/Linux - BSD License
#

VERSION="0.1"

# Share directory holding lib.sh and check modules. Overridable so the
# tool can run straight from a source checkout: REPRISE_SHARE=. ./reprise
REPRISE_SHARE="${REPRISE_SHARE:-/usr/share/reprise}"

# Root of the system to inspect. "/" for the running system, set by
# --rescue to point at a mounted broken system.
REPRISE_ROOT="/"

REPRISE_FIX=""
REPRISE_REPORT=""
REPRISE_SEND=""
REPRISE_UPDATE_DB=""

# Team endpoints, plain HTTP on purpose: busybox wget on old SliTaz
# releases has no TLS, and broken systems are the target.
REPRISE_SEND_URL="${REPRISE_SEND_URL:-http://reprise.slitaz.org/report}"
REPRISE_DB_URL="${REPRISE_DB_URL:-http://reprise.slitaz.org/known-issues.json}"

# usage - print command line help.
usage() {
    cat << EOT
Usage: reprise [option]

Diagnose and repair a broken SliTaz system.

Options:
  --fix           Attempt to fix the problems found (asks before acting)
  --report        Print a plain-text report suitable for sharing
  --send          Send the report to the SliTaz team (asks nothing more)
  --update-db     Fetch the latest known-issues database
  --rescue=DIR    Inspect a SliTaz system mounted on DIR
  --version       Show version and exit
  --help          Show this help and exit
EOT
}

# Parse the command line.
for arg in "$@"; do
    case "$arg" in
        --fix)
            REPRISE_FIX="yes" ;;
        --report)
            REPRISE_REPORT="yes" ;;
        --send)
            REPRISE_SEND="yes" ;;
        --update-db)
            REPRISE_UPDATE_DB="yes" ;;
        --rescue=*)
            REPRISE_ROOT="${arg#--rescue=}" ;;
        --version)
            echo "reprise $VERSION"
            exit 0 ;;
        --help|-h)
            usage
            exit 0 ;;
        *)
            echo "reprise: unknown option: $arg" >&2
            usage
            exit 1 ;;
    esac
done

export REPRISE_ROOT REPRISE_FIX REPRISE_REPORT

# Load the shared helpers.
if [ ! -f "$REPRISE_SHARE/lib.sh" ]; then
    echo "reprise: cannot find $REPRISE_SHARE/lib.sh" >&2
    exit 1
fi
. "$REPRISE_SHARE/lib.sh"

# Preflight: a rescue root must at least look like a SliTaz system.
if [ "$REPRISE_ROOT" != "/" ]; then
    if [ ! -d "$REPRISE_ROOT" ]; then
        log_err "$REPRISE_ROOT is not a directory"
        exit 1
    fi
    if [ ! -f "$(reprise_path /etc/slitaz-release)" ]; then
        log_err "$REPRISE_ROOT does not look like a SliTaz root"
        log_err "(no etc/slitaz-release found, is the partition mounted?)"
        exit 1
    fi
fi

# run_checks - iterate check modules and run check_<name> on each,
# then fix_<name> when --fix is set and the check reported a problem.
run_checks() {
    checks="$REPRISE_SHARE/checks"
    total=0
    broken=0
    for module in "$checks"/*.sh; do
        [ -f "$module" ] || continue
        name=$(basename "$module" .sh)
        . "$module"
        total=$((total + 1))
        log_info "Checking: $name"
        if "check_$name"; then
            log_ok "$name: OK"
        else
            broken=$((broken + 1))
            log_err "$name: problems found"
            if [ -n "$REPRISE_FIX" ] && type "fix_$name" >/dev/null 2>&1; then
                "fix_$name"
            fi
        fi
    done
    if [ "$total" -eq 0 ]; then
        log_warn "No check module found in $checks"
    fi
    log_info "Checks run: $total - problems: $broken"
    [ "$broken" -eq 0 ]
}

# report - print a plain-text shareable report.
# No color, no prompt, safe to pipe (lib.sh already disabled colors).
report() {
    local status release xlog
    echo "=== Reprise $VERSION report - $(date '+%Y-%m-%d %H:%M') ==="
    echo ""
    echo "--- System"
    release=$(reprise_path /etc/slitaz-release)
    if [ -f "$release" ]; then
        echo "SliTaz release : $(cat "$release")"
    else
        echo "SliTaz release : not found"
    fi
    if [ "$REPRISE_ROOT" = "/" ]; then
        echo "Kernel         : $(uname -sr)"
        echo "Arch           : $(uname -m)"
        echo "Uptime         :$(uptime 2>/dev/null)"
    else
        echo "Rescue root    : $REPRISE_ROOT"
    fi
    echo ""
    echo "--- Disk usage"
    if [ "$REPRISE_ROOT" = "/" ]; then
        df -h
    else
        df -h "$REPRISE_ROOT"
    fi
    echo ""
    echo "--- Checks"
    run_checks
    status=$?
    echo ""
    if [ "$REPRISE_ROOT" = "/" ] && have_cmd dmesg; then
        echo "--- dmesg (last 50 lines)"
        dmesg 2>/dev/null | tail -50
        echo ""
    fi
    xlog=$(reprise_path /var/log/Xorg.0.log)
    if [ -f "$xlog" ]; then
        echo "--- Xorg.0.log (last 50 lines)"
        tail -50 "$xlog"
        echo ""
    fi
    echo "=== End of report ==="
    return $status
}

# send_report - generate a full report and POST it to the SliTaz team.
# The report is kept in /tmp when sending fails, so the user can still
# send it again later by hand.
send_report() {
    local tmp reply rescue_opt
    tmp="/tmp/reprise-report.$$"
    rescue_opt=""
    [ "$REPRISE_ROOT" != "/" ] && rescue_opt="--rescue=$REPRISE_ROOT"
    log_info "Generating the report..."
    "$0" --report $rescue_opt > "$tmp" 2>&1
    log_info "Sending to $REPRISE_SEND_URL"
    reply=""
    if wget --help 2>&1 | grep -q 'post-file'; then
        reply=$(wget -q -O - --post-file="$tmp" "$REPRISE_SEND_URL")
    elif have_cmd curl; then
        reply=$(curl -sf --data-binary "@$tmp" "$REPRISE_SEND_URL")
    elif wget --help 2>&1 | grep -q 'post-data'; then
        reply=$(wget -q -O - --post-data="$(cat "$tmp")" "$REPRISE_SEND_URL")
    fi
    if [ -n "$reply" ]; then
        log_ok "$reply"
        rm -f "$tmp"
    else
        log_err "Sending failed (no network or no POST-capable wget/curl)"
        log_info "Report kept in $tmp, retry later with: reprise --send"
        return 1
    fi
}

# update_db - fetch the latest known-issues database. The DB is only
# ever displayed (fix_cmd is never executed), so a fresh copy is safe:
# the worst a bad database can do is give a bad hint.
update_db() {
    local tmp db count
    db="$REPRISE_SHARE/known-issues.json"
    tmp="/tmp/reprise-db.$$"
    if [ -e "$db" ] && [ ! -w "$db" ]; then
        log_err "Cannot write $db, run as root to update the database"
        return 1
    fi
    log_info "Fetching $REPRISE_DB_URL"
    if have_cmd wget; then
        wget -q -O "$tmp" "$REPRISE_DB_URL"
    elif have_cmd curl; then
        curl -sf -o "$tmp" "$REPRISE_DB_URL"
    else
        log_err "Neither wget nor curl found"
        return 1
    fi
    if [ ! -s "$tmp" ]; then
        rm -f "$tmp"
        log_err "Download failed (no network?)"
        return 1
    fi
    # Sanity check: must be a JSON array (crude check without jq).
    if have_cmd jq; then
        if ! jq -e 'type == "array"' "$tmp" > /dev/null 2>&1; then
            rm -f "$tmp"
            log_err "Downloaded file is not a valid issues database"
            return 1
        fi
    elif ! grep -q '^\[' "$tmp"; then
        rm -f "$tmp"
        log_err "Downloaded file is not a valid issues database"
        return 1
    fi
    [ -f "$db" ] && cp "$db" "$db.bak"
    mv "$tmp" "$db"
    count=$(grep -c '"id"' "$db")
    log_ok "Known-issues database updated ($count entries)"
}

if [ -n "$REPRISE_UPDATE_DB" ]; then
    update_db
elif [ -n "$REPRISE_SEND" ]; then
    send_report
elif [ -n "$REPRISE_REPORT" ]; then
    report
else
    run_checks
    status=$?
    if [ "$status" -ne 0 ]; then
        # Close the loop: a fix may have been published since this
        # database shipped. Offer one refresh + re-check, then the
        # report upload. REPRISE_DB_FRESH guards against looping.
        if [ -z "$REPRISE_DB_FRESH" ]; then
            echo ""
            if ask "Update the known-issues database and check again?"; then
                if update_db; then
                    REPRISE_DB_FRESH=1 exec "$0" "$@"
                fi
            fi
        fi
        echo ""
        if ask "Send a report to the SliTaz team?"; then
            send_report
        fi
    fi
    exit $status
fi
