#!/bin/bash
# =============================================================================
# wiris-dtb-config: Tool for managing and switching Device Tree on SP7021 Wiris
# =============================================================================

set -e

DTB_CONFIGS_DIR="/usr/lib/wiris-dtb"
ACTIVE_DTB_FILE="/boot/dtb"
CONF_FILE="/etc/wiris/board.conf"
CONF_DIR="/etc/wiris"

# Check root privileges for modification tasks
check_root() {
    if [ "$(id -u)" -ne 0 ]; then
        echo "ERROR: This operation requires administrative privileges (run with sudo)." >&2
        exit 1
    fi
}

# Check if /boot is a mounted filesystem
check_boot_mount() {
    if ! mountpoint -q /boot; then
        echo "ERROR: /boot is not mounted as a partition (boot partition)!" >&2
        exit 1
    fi
}

# Get running model from Device Tree
get_running_model() {
    if [ -f /sys/firmware/devicetree/base/model ]; then
        tr -d '\0' < /sys/firmware/devicetree/base/model
    else
        echo "Unknown (/sys/firmware/devicetree not available)"
    fi
}

# Determine which DTB in /usr/lib/wiris-dtb matches the active /boot/dtb
get_active_dtb() {
    if [ ! -f "$ACTIVE_DTB_FILE" ]; then
        echo "none (file $ACTIVE_DTB_FILE does not exist)"
        return
    fi

    local active_hash
    active_hash=$(sha256sum "$ACTIVE_DTB_FILE" 2>/dev/null | awk '{print $1}')

    for dtb in "$DTB_CONFIGS_DIR"/*.dtb; do
        [ -f "$dtb" ] || continue
        local cur_hash
        cur_hash=$(sha256sum "$dtb" 2>/dev/null | awk '{print $1}')
        if [ "$active_hash" = "$cur_hash" ]; then
            basename "$dtb"
            return
        fi
    done

    # Fallback to configuration file if hashes don't match
    if [ -f "$CONF_FILE" ]; then
        # shellcheck source=/dev/null
        . "$CONF_FILE"
        if [ -n "$ACTIVE_DTB" ]; then
            echo "$ACTIVE_DTB (per configuration, content may differ)"
            return
        fi
    fi

    echo "custom / unknown"
}

# List available profiles
cmd_list() {
    echo "============================================================"
    echo "  SP7021 Wiris - Device Tree Configurations"
    echo "============================================================"
    echo "Running model in RAM: $(get_running_model)"
    echo "Active on boot:       $(get_active_dtb)"
    echo ""
    echo "Available DTB profiles in $DTB_CONFIGS_DIR:"

    local active_name
    active_name=$(get_active_dtb)
    local i=1

    if [ ! -d "$DTB_CONFIGS_DIR" ] || [ -z "$(ls -A "$DTB_CONFIGS_DIR"/*.dtb 2>/dev/null)" ]; then
        echo "  (no DTB profiles found in $DTB_CONFIGS_DIR)"
        return
    fi

    for dtb in "$DTB_CONFIGS_DIR"/*.dtb; do
        [ -f "$dtb" ] || continue
        local name
        name=$(basename "$dtb")
        if [ "$name" = "$active_name" ]; then
            printf "  * %2d) %-40s [ACTIVE]\n" "$i" "$name"
        else
            printf "    %2d) %-40s\n" "$i" "$name"
        fi
        i=$((i + 1))
    done
    echo "============================================================"
}

# Set and activate a specific DTB
cmd_set() {
    local target="$1"
    check_root
    check_boot_mount

    if [ -z "$target" ]; then
        echo "ERROR: No DTB profile specified." >&2
        echo "Usage: wiris-dtb set <profile_name.dtb>" >&2
        exit 1
    fi

    local target_file=""

    # 1. Look for exact file match
    if [ -f "$DTB_CONFIGS_DIR/$target" ]; then
        target_file="$DTB_CONFIGS_DIR/$target"
    elif [ -f "$DTB_CONFIGS_DIR/$target.dtb" ]; then
        target_file="$DTB_CONFIGS_DIR/$target.dtb"
    else
        # 2. Look for partial name match
        local matches=()
        for f in "$DTB_CONFIGS_DIR"/*"$target"*.dtb; do
            [ -f "$f" ] && matches+=("$f")
        done
        if [ ${#matches[@]} -eq 1 ]; then
            target_file="${matches[0]}"
        elif [ ${#matches[@]} -gt 1 ]; then
            echo "ERROR: Multiple profiles matched '$target':" >&2
            for m in "${matches[@]}"; do
                echo "  - $(basename "$m")" >&2
            done
            exit 1
        else
            echo "ERROR: DTB profile '$target' not found in $DTB_CONFIGS_DIR." >&2
            echo "List available profiles using: wiris-dtb list" >&2
            exit 1
        fi
    fi

    local dtb_filename
    dtb_filename=$(basename "$target_file")

    echo "Activating Device Tree profile: $dtb_filename"
    cp -f "$target_file" "$ACTIVE_DTB_FILE"
    sync

    # Save to configuration file
    mkdir -p "$CONF_DIR"
    echo "# SP7021 Wiris Board Configuration" > "$CONF_FILE"
    echo "ACTIVE_DTB=\"$dtb_filename\"" >> "$CONF_FILE"

    echo "[OK] Profile '$dtb_filename' successfully written to $ACTIVE_DTB_FILE"
    echo "[INFO] Changes will take effect after reboot (run 'sudo reboot')."
}

# Apply current configuration (used internally during postinst)
cmd_apply() {
    check_root
    check_boot_mount

    local dtb_to_apply=""

    if [ -f "$CONF_FILE" ]; then
        # shellcheck source=/dev/null
        . "$CONF_FILE"
        dtb_to_apply="$ACTIVE_DTB"
    fi

    if [ -z "$dtb_to_apply" ] || [ ! -f "$DTB_CONFIGS_DIR/$dtb_to_apply" ]; then
        # Fallback to the first found DTB file
        local first_dtb
        first_dtb=$(ls -1 "$DTB_CONFIGS_DIR"/*.dtb 2>/dev/null | head -n 1)
        if [ -n "$first_dtb" ]; then
            dtb_to_apply=$(basename "$first_dtb")
        fi
    fi

    if [ -n "$dtb_to_apply" ] && [ -f "$DTB_CONFIGS_DIR/$dtb_to_apply" ]; then
        echo "Copying DTB profile '$dtb_to_apply' to $ACTIVE_DTB_FILE..."
        cp -f "$DTB_CONFIGS_DIR/$dtb_to_apply" "$ACTIVE_DTB_FILE"
        sync
        mkdir -p "$CONF_DIR"
        echo "# SP7021 Wiris Board Configuration" > "$CONF_FILE"
        echo "ACTIVE_DTB=\"$dtb_to_apply\"" >> "$CONF_FILE"
        echo "[OK] DTB profile '$dtb_to_apply' applied to $ACTIVE_DTB_FILE."
    else
        echo "WARNING: No valid DTB profile to apply was found in $DTB_CONFIGS_DIR." >&2
    fi
}

# Interactive menu
cmd_interactive() {
    cmd_list
    echo ""

    local dtbs=()
    for dtb in "$DTB_CONFIGS_DIR"/*.dtb; do
        [ -f "$dtb" ] && dtbs+=("$dtb")
    done

    if [ ${#dtbs[@]} -eq 0 ]; then
        exit 0
    fi

    read -r -p "Enter profile number to activate (or Enter/q to quit): " choice
    if [[ "$choice" =~ ^[0-9]+$ ]] && [ "$choice" -ge 1 ] && [ "$choice" -le "${#dtbs[@]}" ]; then
        local selected_dtb="${dtbs[$((choice - 1))]}"
        cmd_set "$(basename "$selected_dtb")"
    else
        echo "Exiting without changes."
    fi
}

# Help message
cmd_help() {
    echo "Usage: wiris-dtb <command> [arguments]"
    echo ""
    echo "Commands:"
    echo "  list, status        Display available profiles and the currently active DTB"
    echo "  set <profile>       Switch and activate a DTB profile to /boot/dtb"
    echo "  apply               Re-apply the active profile from /etc/wiris/board.conf"
    echo "  help, -h, --help    Show this help message"
    echo ""
    echo "When executed without arguments in an interactive terminal, a selection menu is displayed."
}

# Main router
case "${1:-}" in
    list|status)
        cmd_list
        ;;
    set|select)
        shift
        cmd_set "${1:-}"
        ;;
    apply)
        cmd_apply
        ;;
    help|-h|--help)
        cmd_help
        ;;
    "")
        if [ -t 0 ]; then
            cmd_interactive
        else
            cmd_list
        fi
        ;;
    *)
        # If the argument matches a file, directly invoke set
        if [ -f "$DTB_CONFIGS_DIR/$1" ] || [ -f "$DTB_CONFIGS_DIR/$1.dtb" ]; then
            cmd_set "$1"
        else
            echo "Unknown command: $1" >&2
            cmd_help >&2
            exit 1
        fi
        ;;
esac
