#!/bin/sh
# power-cycle <host>                — off, wait POWER_CYCLE_OFF_SECS (default 5), on
# power-cycle off|on|status <host>  — explicit single action
# power-cycle list                  — show configured host -> plug mappings
#
# Targets Shelly Gen2 plugs (Plus Plug US/S, etc.) via their local HTTP RPC.
# No cloud, no account. The host must be reachable on the same network/VPN.
#
# Config: ~/.config/power-cycle/plugs.conf
#   one entry per line:  <host>  <plug-base-url>
#   blank lines and lines starting with # are ignored.
# Example:
#   apricot  http://10.0.0.117
#   plum     http://10.0.0.119
#
# Env:
#   POWER_CYCLE_OFF_SECS   seconds to stay off during a cycle (default 5)
#   POWER_CYCLE_TIMEOUT    per-request curl timeout in seconds (default 5)

set -eu

config="${XDG_CONFIG_HOME:-$HOME/.config}/power-cycle/plugs.conf"
off_secs=${POWER_CYCLE_OFF_SECS:-5}
http_timeout=${POWER_CYCLE_TIMEOUT:-5}

die() { echo "power-cycle: $*" >&2; exit 1; }

usage() {
    sed -n '2,/^$/p' "$0" | sed 's/^# \{0,1\}//'
    exit 2
}

lookup_plug() {
    # echoes the plug base URL for $1, or exits non-zero with a hint.
    host=$1
    [ -f "$config" ] || die "no config at $config — create it (see 'power-cycle' help)"
    url=$(awk -v h="$host" '
        /^[[:space:]]*(#|$)/ { next }
        $1 == h { print $2; found=1; exit }
        END { exit !found }
    ' "$config") || die "no plug configured for '$host' in $config"
    [ -n "$url" ] || die "empty plug URL for '$host' in $config"
    printf %s "$url"
}

shelly_set() {
    # shelly_set <base-url> <true|false>
    base=$1; state=$2
    curl --fail --silent --show-error --max-time "$http_timeout" \
        "$base/rpc/Switch.Set?id=0&on=$state" >/dev/null \
        || die "plug $base unreachable — for modem outages, fall back to BLE (SwitchBot app)"
}

shelly_status() {
    # echoes "on" or "off"
    base=$1
    body=$(curl --fail --silent --show-error --max-time "$http_timeout" \
        "$base/rpc/Switch.GetStatus?id=0") \
        || die "plug $base unreachable"
    case "$body" in
        *'"output":true'*)  echo on  ;;
        *'"output":false'*) echo off ;;
        *) die "unrecognized Shelly response: $body" ;;
    esac
}

cmd_list() {
    [ -f "$config" ] || die "no config at $config"
    awk '/^[[:space:]]*(#|$)/ { next } { printf "  %-15s %s\n", $1, $2 }' "$config"
}

case "${1:-}" in
    ''|-h|--help|help) usage ;;
    list)              cmd_list ;;
    off)               [ $# -eq 2 ] || usage; shelly_set "$(lookup_plug "$2")" false ;;
    on)                [ $# -eq 2 ] || usage; shelly_set "$(lookup_plug "$2")" true ;;
    status)            [ $# -eq 2 ] || usage; shelly_status "$(lookup_plug "$2")" ;;
    *)
        [ $# -eq 1 ] || usage
        host=$1
        base=$(lookup_plug "$host")
        echo "cycling $host: off -> ${off_secs}s -> on"
        shelly_set "$base" false
        sleep "$off_secs"
        shelly_set "$base" true
        echo "done. give the host ~30-90s to finish booting."
        ;;
esac
