#!/usr/bin/bash
set -euo pipefail

SERVICE_NAME="com.cyanskillfish.Governor"
OBJECT_PATH="/com/cyanskillfish/Governor"
INTERFACE="com.cyanskillfish.Governor.PerformanceMode"
RANGE_OBJECT_PATH_CURRENT="/com/cyanskillfish/Governor/Range/Current"
RANGE_INTERFACE="com.cyanskillfish.Governor.Range"

usage() {
    cat <<'EOF'
Usage: cyan-skillfish-performance-mode [OPTIONS] [COMMAND...]

Options:
    --on                  Enable performance mode
    --fixed-frequency <MHz>
                          Enable performance mode with fixed frequency
    --range <min> <max>   Set current range via SetRange (MHz, use 0 for no limit)
    --load-target <min> <max>
                          Set load target bounds via SetLoadTarget
    --temperature <throttling> <recovery>
                          Set temperature thresholds via SetTemperatureThresholds
    --off                 Disable performance mode
    --status              Show performance mode status
    -h, --help            Show this help message

Steam launch example:
  Add to Steam launch options: cyan-skillfish-performance-mode %command%

Command wrapper mode:
  cyan-skillfish-performance-mode some-game
  cyan-skillfish-performance-mode --fixed-frequency 1200 some-game
  cyan-skillfish-performance-mode --range 500 1500 some-game
  - Enables performance mode before running the command
  - Disables performance mode when the command exits
EOF
}

has_cmd() {
    command -v "$1" >/dev/null 2>&1
}

has_service_owner() {
    if has_cmd busctl; then
        busctl --system call org.freedesktop.DBus /org/freedesktop/DBus org.freedesktop.DBus NameHasOwner s "$SERVICE_NAME" 2>/dev/null | awk 'NR == 1 { print $2 }' | grep -qx true
        return $?
    fi

    if has_cmd dbus-send; then
        dbus-send --system \
            --print-reply \
            --dest=org.freedesktop.DBus \
            /org/freedesktop/DBus \
            org.freedesktop.DBus.NameHasOwner \
            string:"$SERVICE_NAME" 2>/dev/null | awk '/boolean/ { print $2; exit }' | grep -qx true
        return $?
    fi

    return 1
}

call_set_enabled() {
    local value="$1"

    if has_cmd busctl; then
        busctl --system set-property "$SERVICE_NAME" "$OBJECT_PATH" "$INTERFACE" Enabled b "$value" >/dev/null
        return $?
    fi

    if has_cmd dbus-send; then
        dbus-send --system \
            --dest="$SERVICE_NAME" \
            "$OBJECT_PATH" \
            org.freedesktop.DBus.Properties.Set \
            string:"$INTERFACE" \
            string:"Enabled" \
            variant:boolean:"$value" >/dev/null
        return $?
    fi

    echo "Error: neither busctl nor dbus-send is installed." >&2
    return 1
}

call_set_fixed_frequency() {
    local frequency="$1"

    if has_cmd busctl; then
        busctl --system call "$SERVICE_NAME" "$OBJECT_PATH" "$INTERFACE" SetFixedFrequency u "$frequency" >/dev/null
        return $?
    fi

    if has_cmd dbus-send; then
        dbus-send --system \
            --dest="$SERVICE_NAME" \
            "$OBJECT_PATH" \
            "$INTERFACE.SetFixedFrequency" \
            uint32:"$frequency" >/dev/null
        return $?
    fi

    echo "Error: neither busctl nor dbus-send is installed." >&2
    return 1
}

call_set_range() {
    local min="$1"
    local max="$2"
    if has_cmd busctl; then
        busctl --system call "$SERVICE_NAME" "$OBJECT_PATH" "$INTERFACE" SetRange uu "$min" "$max" >/dev/null
        return $?
    fi

    if has_cmd dbus-send; then
        dbus-send --system \
            --dest="$SERVICE_NAME" \
            "$OBJECT_PATH" \
            "$INTERFACE.SetRange" \
            uint32:"$min" \
            uint32:"$max" >/dev/null
        return $?
    fi

    echo "Error: neither busctl nor dbus-send is installed." >&2
    return 1
}

call_get_current_range_property() {
    local property_name="$1"

    if has_cmd busctl; then
        busctl --system get-property "$SERVICE_NAME" "$RANGE_OBJECT_PATH_CURRENT" "$RANGE_INTERFACE" "$property_name" | awk 'NR == 1 { print $NF }'
        return $?
    fi

    if has_cmd dbus-send; then
        dbus-send --system \
            --print-reply \
            --dest="$SERVICE_NAME" \
            "$RANGE_OBJECT_PATH_CURRENT" \
            org.freedesktop.DBus.Properties.Get \
            string:"$RANGE_INTERFACE" \
            string:"$property_name" | awk '/variant/ { print $3; exit }'
        return $?
    fi

    echo "Error: neither busctl nor dbus-send is installed." >&2
    return 1
}

call_get_property() {
    local property_name="$1"

    if has_cmd busctl; then
        busctl --system get-property "$SERVICE_NAME" "$OBJECT_PATH" "$INTERFACE" "$property_name" | awk 'NR == 1 { print $NF }'
        return $?
    fi

    if has_cmd dbus-send; then
        dbus-send --system \
            --print-reply \
            --dest="$SERVICE_NAME" \
            "$OBJECT_PATH" \
            org.freedesktop.DBus.Properties.Get \
            string:"$INTERFACE" \
            string:"$property_name" | awk '/variant/ { print $3; exit }'
        return $?
    fi

    echo "Error: neither busctl nor dbus-send is installed." >&2
    return 1
}

call_set_property_u32() {
    local property_name="$1"
    local value="$2"

    if has_cmd busctl; then
        busctl --system set-property "$SERVICE_NAME" "$OBJECT_PATH" "$INTERFACE" "$property_name" u "$value" >/dev/null
        return $?
    fi

    if has_cmd dbus-send; then
        dbus-send --system \
            --dest="$SERVICE_NAME" \
            "$OBJECT_PATH" \
            org.freedesktop.DBus.Properties.Set \
            string:"$INTERFACE" \
            string:"$property_name" \
            variant:uint32:"$value" >/dev/null
        return $?
    fi

    echo "Error: neither busctl nor dbus-send is installed." >&2
    return 1
}

call_set_current_range_property_u32() {
    local property_name="$1"
    local value="$2"

    if has_cmd busctl; then
        busctl --system set-property "$SERVICE_NAME" "$RANGE_OBJECT_PATH_CURRENT" "$RANGE_INTERFACE" "$property_name" u "$value" >/dev/null
        return $?
    fi

    if has_cmd dbus-send; then
        dbus-send --system \
            --dest="$SERVICE_NAME" \
            "$RANGE_OBJECT_PATH_CURRENT" \
            org.freedesktop.DBus.Properties.Set \
            string:"$RANGE_INTERFACE" \
            string:"$property_name" \
            variant:uint32:"$value" >/dev/null
        return $?
    fi

    echo "Error: neither busctl nor dbus-send is installed." >&2
    return 1
}

call_set_property_double() {
    local property_name="$1"
    local value="$2"

    if has_cmd busctl; then
        busctl --system set-property "$SERVICE_NAME" "$OBJECT_PATH" "$INTERFACE" "$property_name" d "$value" >/dev/null
        return $?
    fi

    if has_cmd dbus-send; then
        dbus-send --system \
            --dest="$SERVICE_NAME" \
            "$OBJECT_PATH" \
            org.freedesktop.DBus.Properties.Set \
            string:"$INTERFACE" \
            string:"$property_name" \
            variant:double:"$value" >/dev/null
        return $?
    fi

    echo "Error: neither busctl nor dbus-send is installed." >&2
    return 1
}

call_set_load_target() {
    local min="$1"
    local max="$2"
    if has_cmd busctl; then
        busctl --system call "$SERVICE_NAME" "$OBJECT_PATH" "$INTERFACE" SetLoadTarget dd "$min" "$max" >/dev/null
        return $?
    fi

    if has_cmd dbus-send; then
        dbus-send --system \
            --dest="$SERVICE_NAME" \
            "$OBJECT_PATH" \
            "$INTERFACE.SetLoadTarget" \
            double:"$min" \
            double:"$max" >/dev/null
        return $?
    fi

    echo "Error: neither busctl nor dbus-send is installed." >&2
    return 1
}

call_set_temperature() {
    local throttling="$1"
    local recovery="$2"
    if has_cmd busctl; then
        busctl --system call "$SERVICE_NAME" "$OBJECT_PATH" "$INTERFACE" SetTemperatureThresholds uu "$throttling" "$recovery" >/dev/null
        return $?
    fi

    if has_cmd dbus-send; then
        dbus-send --system \
            --dest="$SERVICE_NAME" \
            "$OBJECT_PATH" \
            "$INTERFACE.SetTemperatureThresholds" \
            uint32:"$throttling" \
            uint32:"$recovery" >/dev/null
        return $?
    fi

    echo "Error: neither busctl nor dbus-send is installed." >&2
    return 1
}

call_status() {
    if has_cmd busctl; then
        busctl --system get-property "$SERVICE_NAME" "$OBJECT_PATH" "$INTERFACE" Enabled
        return $?
    fi

    if has_cmd dbus-send; then
        dbus-send --system \
            --print-reply \
            --dest="$SERVICE_NAME" \
            "$OBJECT_PATH" \
            org.freedesktop.DBus.Properties.Get \
            string:"$INTERFACE" \
            string:"Enabled"
        return $?
    fi

    echo "Error: neither busctl nor dbus-send is installed." >&2
    return 1
}

cleanup() {
    call_set_enabled false || true
}

print_service_hint_if_not_running() {
    if ! has_service_owner; then
        echo "The governor service does not appear to be running." >&2
        echo "Try: sudo systemctl status cyan-skillfish-governor-smu" >&2
    fi
}

# No arguments: show usage
if [ "$#" -eq 0 ]; then
    usage
    exit 1
fi

# Handle explicit options
case "$1" in
    --on)
        if call_set_enabled true; then
            echo "Performance mode enabled"
            exit 0
        else
            echo "Error: failed to enable performance mode." >&2
            print_service_hint_if_not_running
            exit 1
        fi
        ;;
    --fixed-frequency)
        if [ "$#" -lt 2 ]; then
            echo "Error: --fixed-frequency requires a numeric MHz argument." >&2
            usage
            exit 1
        fi

        if [[ ! "$2" =~ ^[0-9]+$ ]]; then
            echo "Error: fixed frequency must be a positive integer (MHz)." >&2
            exit 1
        fi

        if call_set_fixed_frequency "$2"; then
            echo "Performance mode enabled with fixed frequency ${2} MHz"

            if [ "$#" -gt 2 ]; then
                shift 2
                if [ "${1:-}" = "--" ]; then
                    shift
                fi

                if [ "$#" -eq 0 ]; then
                    echo "Error: no command provided after --fixed-frequency" >&2
                    exit 1
                fi

                trap cleanup EXIT INT TERM
                exec "$@"
            fi

            exit 0
        else
            echo "Error: failed to set fixed frequency." >&2
            print_service_hint_if_not_running
            exit 1
        fi
        ;;
    --range)
        if [ "$#" -lt 3 ]; then
            echo "Error: --range requires two numeric arguments (min max in MHz)." >&2
            usage
            exit 1
        fi

        if [[ ! "$2" =~ ^[0-9]+$ ]] || [[ ! "$3" =~ ^[0-9]+$ ]]; then
            echo "Error: frequency range values must be non-negative integers (MHz)." >&2
            exit 1
        fi

        if call_set_range "$2" "$3"; then
            echo "Frequency range set: min=$2 MHz, max=$3 MHz"

            if [ "$#" -gt 3 ]; then
                shift 3
                if [ "${1:-}" = "--" ]; then
                    shift
                fi

                if [ "$#" -eq 0 ]; then
                    echo "Error: no command provided after --range" >&2
                    exit 1
                fi

                trap cleanup EXIT INT TERM
                exec "$@"
            fi

            exit 0
        else
            echo "Error: failed to set frequency range." >&2
            print_service_hint_if_not_running
            exit 1
        fi
        ;;
    --load-target)
        if [ "$#" -lt 3 ]; then
            echo "Error: --load-target requires two numeric arguments (min max)." >&2
            usage
            exit 1
        fi

        if ! awk -v value="$2" 'BEGIN { exit !(value >= 0.0 && value <= 1.0) }' || \
           ! awk -v value="$3" 'BEGIN { exit !(value >= 0.0 && value <= 1.0) }'; then
            echo "Error: load target values must be between 0.0 and 1.0." >&2
            exit 1
        fi

        if call_set_load_target "$2" "$3"; then
            echo "Load target set: min=$2, max=$3"

            if [ "$#" -gt 3 ]; then
                shift 3
                if [ "${1:-}" = "--" ]; then
                    shift
                fi

                if [ "$#" -eq 0 ]; then
                    echo "Error: no command provided after --load-target" >&2
                    exit 1
                fi

                trap cleanup EXIT INT TERM
                exec "$@"
            fi

            exit 0
        else
            echo "Error: failed to set load target." >&2
            print_service_hint_if_not_running
            exit 1
        fi
        ;;
    --temperature)
        if [ "$#" -lt 3 ]; then
            echo "Error: --temperature requires two numeric arguments (throttling recovery)." >&2
            usage
            exit 1
        fi

        if [[ ! "$2" =~ ^[0-9]+$ ]] || [[ ! "$3" =~ ^[0-9]+$ ]]; then
            echo "Error: temperature values must be non-negative integers (Celsius)." >&2
            exit 1
        fi

        if call_set_temperature "$2" "$3"; then
            echo "Temperature thresholds set: throttling=$2 C, recovery=$3 C"

            if [ "$#" -gt 3 ]; then
                shift 3
                if [ "${1:-}" = "--" ]; then
                    shift
                fi

                if [ "$#" -eq 0 ]; then
                    echo "Error: no command provided after --temperature" >&2
                    exit 1
                fi

                trap cleanup EXIT INT TERM
                exec "$@"
            fi

            exit 0
        else
            echo "Error: failed to set temperature thresholds." >&2
            print_service_hint_if_not_running
            exit 1
        fi
        ;;
    --off)
        if call_set_enabled false; then
            echo "Performance mode disabled"
            exit 0
        else
            if ! has_service_owner; then
                echo "Performance mode already off (service is not running)"
                exit 0
            fi

            echo "Error: failed to disable performance mode." >&2
            print_service_hint_if_not_running
            exit 1
        fi
        ;;
    --status)
        call_status
        exit $?
        ;;
    -h|--help|help)
        usage
        exit 0
        ;;
    *)
        # Treat as command wrapper mode: enable, run command, disable on exit
        call_set_enabled true || {
            echo "Warning: failed to enable performance mode." >&2
        }
        trap cleanup EXIT INT TERM
        exec "$@"
        ;;
esac
