#!/usr/bin/env bash
set -euo pipefail
# POS: system schedule — Scheduled jobs: run a command on a timer; notify on threshold/change/error/always or silently
# POS_SUBCMDS: run list config enable disable status migrate menu
# POS_FLAGS: --dry-run

source "$(dirname "$0")/../lib/common.sh" 2>/dev/null || source "$(dirname "$0")/common.sh"
source "$(dirname "$0")/../lib/scheduler-lib.sh" 2>/dev/null || source "$(dirname "$0")/scheduler-lib.sh"
source "$(dirname "$0")/../lib/notify.sh" 2>/dev/null || source "$(dirname "$0")/notify.sh"
source "$(dirname "$0")/../lib/menu-lib.sh" 2>/dev/null || source "$(dirname "$0")/menu-lib.sh"

usage() {
    cat <<EOF
Usage: pos system schedule <subcommand> [--dry-run]

Scheduled jobs. Each job is a file in $SCHEDULE_DIR/<name>.env:

    INTERVAL=hourly            (5m..59m | 1h..23h | hourly daily weekly | OnCalendar=…)
    NOTIFY=onchange            (always | onchange | onerror | threshold | never)
    MSG="NVMe health"          optional label; threshold alert text when NOTIFY=threshold
    RULE="> 60c"               threshold only: op + threshold (unit suffix fine: 60c, 80%)
    COMMAND=…                  literal rest of the line — pipes/quotes/sudo fine

NOTIFY policies:
  always     send the full output on every run
  onchange   send only when the output differs from the last run (first run sends)
  onerror    send only when the command fails (non-zero exit or empty output)
  threshold  compare the command's first numeric output with RULE; alert on
             false→true plus one recovery message
  never      run only — no notification (side-effect jobs)
Default: threshold if RULE is set, otherwise onchange.

Bare \`pos system schedule\` on a terminal (or \`pos system schedule menu\`)
opens an interactive menu wrapping these subcommands; arguments stay
scriptable — the systemd timers keep calling 'run <name>' directly.

Subcommands:
  run [name|all]      Execute job(s) now (the systemd timers call 'run <name>')
  list                Jobs + notify policy + interval + last run
  config              Interactive editor: add / edit / remove / enable / disable
  enable [name|all]   Install + start the job's user timer (default: all)
  disable [name|all]  Stop the job, keeping the job file (default: all)
  status              Per-job timer state + next run
  migrate             Convert legacy event.env rules into schedule.d jobs (threshold)

Options:
  --dry-run           Preview what would run / be written / be sent
  -h, --help          This help

Jobs dir:  $SCHEDULE_DIR  (chmod 600 per file)

Examples:
  pos system schedule list
  pos system schedule enable
  pos system schedule run nvme-health --dry-run
  pos system schedule migrate
EOF
    exit 0
}

# ── Interactive menu (opt-in front door, Pattern B via lib/menu-lib.sh) ──
# Every item maps onto an existing subcommand implementation. Run-now goes
# through the same sched_run the systemd timers invoke (`run <name>`),
# behind an explicit y/N confirm.

menu_pick_job() {   # $1 = prompt → picked job name on stdout · rc 1 = cancelled
    local -a jobs=()
    mapfile -t jobs < <(sched_list_jobs)
    if [ ${#jobs[@]} -eq 0 ]; then
        warn "no jobs in $SCHEDULE_DIR — add one with 'pos system schedule config'"
        return 1
    fi
    local idx
    idx="$(menu_pick "$1" "${jobs[@]}")" || return 1
    printf '%s\n' "${jobs[$((idx - 1))]}"
}

menu_job_action() {   # $1 = run|enable|disable — pick a job, call the verb
    local name
    name="$(menu_pick_job "${1} which job?")" || return 0
    case "$1" in
        run)
            confirm "Run job '$name' now (executes its COMMAND, applies its NOTIFY policy)?" n \
                || { log "Cancelled"; return 0; }
            sched_run "$name"
            ;;
        enable)  sched_enable "$name" ;;
        disable) sched_disable "$name" ;;
    esac
}

run_menu() {
    menu_guard || exit 1
    while true; do
        local choice
        choice="$(menu_run "Scheduled jobs ($SCHEDULE_DIR)" \
            "List jobs" \
            "Timer status (+ next run)" \
            "Run a job now" \
            "Enable a job" \
            "Disable a job" \
            "Open the interactive job editor")" || return 0
        case "$choice" in
            1) sched_list ;;
            2) sched_status ;;
            3) menu_job_action run ;;
            4) menu_job_action enable ;;
            5) menu_job_action disable ;;
            6) sched_config_editor ;;
        esac
    done
}

# Menu door: explicit verb, or zero args on a terminal. Everything below —
# including zero args without a terminal — stays byte-compatible with the
# pre-menu CLI; timer invocations (`run <name>`) never enter the menu.
if [ "${1:-}" = "menu" ]; then
    run_menu
    exit 0
fi
if [ $# -eq 0 ] && [ -t 0 ]; then
    run_menu
    exit 0
fi

case "${1:-}" in
    -h|--help|"") usage ;;
esac

DRY_RUN=0
args=()
for a in "$@"; do
    case "$a" in
        --dry-run) DRY_RUN=1 ;;
        *)         args+=("$a") ;;
    esac
done
set -- "${args[@]}"

[ -d "$SCHEDULE_DIR" ] || log "no jobs yet — add one with 'pos system schedule config'"

case "${1:-}" in
    run)      sched_run "${2:-all}" ;;
    list)     sched_list ;;
    config)   sched_config_editor ;;
    enable)   sched_enable "${2:-all}" ;;
    disable)  sched_disable "${2:-all}" ;;
    status)   sched_status ;;
    migrate)  sched_migrate ;;
    *)        err "unknown subcommand '${1:-}' (see --help)" ;;
esac
