#!/usr/bin/env bash
# systab - A cron/at/batch-like interface for systemd
# Copyright (C) 2026 opennomad
# SPDX-License-Identifier: AGPL-3.0-or-later
set -euo pipefail

# Managed jobs are marked with: # SYSTAB_MANAGED

readonly SCRIPT_NAME="systab"
readonly SYSTEMD_USER_DIR="${HOME}/.config/systemd/user"
readonly MARKER="# SYSTAB_MANAGED"

# Global variables for options
opt_time=""
opt_command=""
opt_file=""
opt_notify=false
opt_email=""
opt_edit=false
opt_list=false
opt_print_crontab=false
opt_clean=false
opt_status=false
opt_disable=""
opt_enable=""
opt_delete=""
opt_restart=""
opt_filter=""
opt_output=""
opt_name=""
opt_jobid=""
opt_service=false

usage() {
    cat <<EOF
Usage: $SCRIPT_NAME [OPTIONS]

Create and manage systemd timer jobs with cron/at-like simplicity.

Job Creation Options:
  -t <time>         Time specification (see TIME FORMATS below)
  -s                Create a persistent service (no timer; mutually exclusive with -t/-i/-m/-o)
  -c <command>      Command string to execute
  -f <script>       Script file to execute
  -n <name>         Give the job a human-readable name (usable in place of hex ID)
  -i                Send desktop notification on completion (success/failure)
  -m <email>        Send email notification to address (via sendmail)
  -o [lines]        Include job output in notifications (default: 10 lines)

Management Options (accept hex ID or name):
  -D <id|name>      Disable a job
  -E <id|name>      Enable a disabled job
  -X <id|name>      Delete a job (stop, disable, and remove unit files)
  -R <id|name>      Restart a job (resets timer countdown / restarts service process)
  -e                Edit jobs in crontab-like format
  -l                Print jobs in crontab-like format to stdout
  -L [id|name] [filter]  List job logs (optionally for a specific job and/or filtered)
  -S [id|name]      Show status of all managed jobs (or a specific job)
  -C                Clean up completed one-time jobs

TIME FORMATS:
  Natural:   "every 5 minutes", "every day at 2am", "every monday at 9am"
  Relative:  "in 5 minutes", "in 2 hours", "tomorrow"
  Absolute:  "2025-01-21 14:30", "next tuesday at 9am"
  Systemd:   "daily", "weekly", "hourly", "*:0/15" (every 15 min)

EXAMPLES:
  # Run command every 5 minutes with a name
  $SCRIPT_NAME -t "every 5 minutes" -n healthcheck -c "echo Hello"

  # Run script every day at 2am with desktop notification
  $SCRIPT_NAME -t "every day at 2am" -n backup -f ~/backup.sh -i

  # Run command with email notification
  $SCRIPT_NAME -t "in 5 minutes" -c "echo Hello" -m user@example.com

  # Run command in 5 minutes (one-time)
  $SCRIPT_NAME -t "in 5 minutes" -c "echo Hello"

  # Read command from stdin
  echo "ls -la" | $SCRIPT_NAME -t "next monday at 9am"

  # Create a persistent service job
  $SCRIPT_NAME -s -n foobar -c "/usr/bin/foobar.sh"

  # Print jobs in crontab-like format (useful for scripting)
  $SCRIPT_NAME -l

  # Edit existing jobs (supports adding notifications via ID:flags syntax)
  $SCRIPT_NAME -e

  # Disable and enable a job (by hex ID or name)
  $SCRIPT_NAME -D <id>
  $SCRIPT_NAME -E backup

  # Delete a job permanently
  $SCRIPT_NAME -X <id>
  $SCRIPT_NAME -X backup

  # Restart a job
  $SCRIPT_NAME -R <id>
  $SCRIPT_NAME -R healthcheck_home

  # View logs for backup jobs
  $SCRIPT_NAME -L backup

  # Show status of all jobs
  $SCRIPT_NAME -S

  # Clean up completed jobs
  $SCRIPT_NAME -C

EOF
    exit "${1:-0}"
}

error() {
    echo "Error: $*" >&2
    exit 1
}

warn() {
    echo "Warning: $*" >&2
}

# Extract the command string from a service file's ExecStart line
getJobCommand() {
    sed -n "s/^ExecStart=.*-c '\\(.*\\)'$/\\1/p" "$1"
}

# Trim leading and trailing whitespace, result in _trimmed
trim() {
    _trimmed="$1"
    _trimmed="${_trimmed#"${_trimmed%%[![:space:]]*}"}"
    _trimmed="${_trimmed%"${_trimmed##*[![:space:]]}"}"
}

# Parse time specification into systemd OnCalendar format
parseTime() {
    local time_spec="$1"

    # Common systemd calendar formats (pass through)
    case "${time_spec,,}" in
        hourly|daily|weekly|monthly|yearly) echo "$time_spec"; return ;;
        *:*|*-*-*) echo "$time_spec"; return ;;  # Assume systemd time format
    esac

    # Natural language recurring patterns
    local lower="${time_spec,,}"
    if [[ "$lower" =~ ^every[[:space:]]+(.+) ]]; then
        local rest="${BASH_REMATCH[1]}"
        case "$rest" in
            # "every N minutes/hours/seconds"
            [0-9]*' minute'*) echo "*:0/${rest%% *}"; return ;;
            [0-9]*' hour'*)   echo "0/${rest%% *}:00"; return ;;
            [0-9]*' second'*) echo "*:*:0/${rest%% *}"; return ;;
            # "every minute/hour"
            'minute'*)          echo "*:*"; return ;;
            'hour'*)            echo "hourly"; return ;;
            # "every day at <time>"
            'day at '*)
                local at_time="${rest#day at }"
                local parsed
                if parsed=$(date -d "$at_time" '+%H:%M:%S' 2>/dev/null); then
                    echo "*-*-* $parsed"; return
                fi ;;
            # "every <weekday> [at <time>]"
            mon|monday|tue|tuesday|wed|wednesday|thu|thursday|fri|friday|sat|saturday|sun|sunday)
                local day="${rest:0:3}"; day="${day^}"
                echo "$day *-*-*"; return ;;
            mon' at '*|monday' at '*|tue' at '*|tuesday' at '*|wed' at '*|wednesday' at '*|thu' at '*|thursday' at '*|fri' at '*|friday' at '*|sat' at '*|saturday' at '*|sun' at '*|sunday' at '*)
                local day_part="${rest%% at *}" at_time="${rest#* at }"
                local day="${day_part:0:3}"; day="${day^}"
                local parsed
                if parsed=$(date -d "$at_time" '+%H:%M:%S' 2>/dev/null); then
                    echo "$day *-*-* $parsed"; return
                fi ;;
            # "every day/week/month/year"
            'day'*)   echo "daily"; return ;;
            'week'*)  echo "weekly"; return ;;
            'month'*) echo "monthly"; return ;;
            'year'*)  echo "yearly"; return ;;
        esac
    fi

    # Try to parse with date command (one-time specs)
    # Strip "in " prefix for natural phrasing ("in 5 minutes" → "5 minutes")
    # Strip " at " before times ("next tuesday at noon" → "next tuesday noon")
    local date_spec="$time_spec"
    [[ "${date_spec,,}" == in\ * ]] && date_spec="${date_spec:3}"
    date_spec="${date_spec// at / }"
    local parsed_date
    if parsed_date=$(date -d "$date_spec" '+%Y-%m-%d %H:%M:%S' 2>/dev/null); then
        echo "$parsed_date"
        return
    fi

    error "Unable to parse time specification: $time_spec"
}

# Check if time spec is recurring
# One-time specs are absolute timestamps (from date -d): "2026-02-14 09:33:10"
# Everything else (calendar specs with wildcards, keywords, intervals) is recurring
isRecurring() {
    local time_spec="$1"
    case "${time_spec,,}" in
        hourly|daily|weekly|monthly|yearly) return 0 ;;
        *'*'*|*/*) return 0 ;;  # Contains wildcard or interval
        *) return 1 ;;
    esac
}

# Generate a random 6-char hex ID
generateId() {
    od -An -tx1 -N3 /dev/urandom | tr -d ' \n'
}

# Extract short ID from job name (systab_<id> → <id>)
jobId() {
    echo "${1#"${SCRIPT_NAME}"_}"
}

# Check if a job's timer (or service) is enabled
isJobEnabled() {
    if isJobService "$1"; then
        systemctl --user is-enabled "${1}.service" &>/dev/null
    else
        systemctl --user is-enabled "${1}.timer" &>/dev/null
    fi
}

# Disable a job (stop + disable timer or service)
disableJob() {
    if isJobService "$1"; then
        systemctl --user stop "${1}.service" 2>/dev/null || true
        systemctl --user disable "${1}.service" 2>/dev/null || true
    else
        systemctl --user stop "${1}.timer" 2>/dev/null || true
        systemctl --user disable "${1}.timer" 2>/dev/null || true
    fi
}

# Enable a job (enable + start timer or service)
enableJob() {
    if isJobService "$1"; then
        systemctl --user enable "${1}.service" 2>/dev/null || true
        systemctl --user start "${1}.service" 2>/dev/null || true
    else
        systemctl --user enable "${1}.timer" 2>/dev/null || true
        systemctl --user start "${1}.timer" 2>/dev/null || true
    fi
}

# Resolve a job identifier (hex ID or name) to a 6-char hex ID
# Sets _resolved_id; errors if not found
resolveJobId() {
    local input="$1"
    # Try as hex ID first
    if [[ "$input" =~ ^[0-9a-f]{6}$ ]]; then
        local timer_file="$SYSTEMD_USER_DIR/${SCRIPT_NAME}_${input}.timer"
        local service_file="$SYSTEMD_USER_DIR/${SCRIPT_NAME}_${input}.service"
        if [[ -f "$timer_file" ]] || { [[ -f "$service_file" ]] && grep -q "^# SYSTAB_TYPE=service$" "$service_file" 2>/dev/null; }; then
            _resolved_id="$input"
            return
        fi
    fi
    # Try as name: grep service files for SYSTAB_NAME=<input>
    local file
    for file in "${SYSTEMD_USER_DIR}/${SCRIPT_NAME}"_*.service; do
        [[ -f "$file" ]] || continue
        if grep -q "^# SYSTAB_NAME=${input}$" "$file" 2>/dev/null; then
            local base
            base=$(basename "$file" .service)
            _resolved_id=$(jobId "$base")
            return
        fi
    done
    error "No job found with ID or name: $input"
}

# Get the human-readable name from a service file (empty string if none)
getJobName() {
    local service_file="$1"
    sed -n 's/^# SYSTAB_NAME=//p' "$service_file" 2>/dev/null || true
}

# Check if a job is a service-only job (not timer-backed)
isJobService() {
    grep -q "^# SYSTAB_TYPE=service$" "$SYSTEMD_USER_DIR/${1}.service" 2>/dev/null
}

# Get managed service-only units (no timer)
getManagedServiceJobs() {
    [[ -d "$SYSTEMD_USER_DIR" ]] || return
    local file
    for file in "${SYSTEMD_USER_DIR}/${SCRIPT_NAME}"_*.service; do
        [[ -f "$file" ]] || continue
        grep -q "^$MARKER" "$file" 2>/dev/null || continue
        grep -q "^# SYSTAB_TYPE=service$" "$file" 2>/dev/null && basename "$file" .service
    done
}

# Format a job identifier for display: "id (name)" or just "id"
formatJobId() {
    local id="$1" name="$2"
    if [[ -n "$name" ]]; then
        echo "$id ($name)"
    else
        echo "$id"
    fi
}

# Validate a short ID refers to a managed job, sets _job_name
validateJobId() {
    resolveJobId "$1"
    local id="$_resolved_id"
    _job_name="${SCRIPT_NAME}_${id}"
    local service_file="$SYSTEMD_USER_DIR/${_job_name}.service"
    [[ -f "$service_file" ]] || error "No job found with ID: $id"
    grep -q "^$MARKER" "$service_file" 2>/dev/null || error "Not a managed job: $id"
}

# Toggle a job's enabled state by short ID or name
# Usage: toggleJobById <id|name> <disable|enable>
toggleJobById() {
    local input="$1" action="$2"
    validateJobId "$input"
    local id="$_resolved_id"
    local name
    name=$(getJobName "$SYSTEMD_USER_DIR/${_job_name}.service")
    local label
    label=$(formatJobId "$id" "$name")
    if [[ "$action" == "disable" ]]; then
        if ! isJobEnabled "$_job_name"; then
            echo "Already disabled: $label"; return
        fi
        disableJob "$_job_name"
        echo "Disabled: $label"
    else
        if isJobEnabled "$_job_name"; then
            echo "Already enabled: $label"; return
        fi
        enableJob "$_job_name"
        echo "Enabled: $label"
    fi
}

# Delete a job (stop, disable, remove unit files) by hex ID or name
deleteJob() {
    local input="$1"
    validateJobId "$input"
    local id="$_resolved_id"
    local name
    name=$(getJobName "$SYSTEMD_USER_DIR/${_job_name}.service")
    local label
    label=$(formatJobId "$id" "$name")
    removeJob "$_job_name"
    systemctl --user daemon-reload
    echo "Deleted: $label"
}

# Restart a job by hex ID or name
restartJob() {
  local input="$1"
  validateJobId "$input"
  local id="$_resolved_id"
  local name
  name=$(getJobName "$SYSTEMD_USER_DIR/${_job_name}.service")
  local label
  label=$(formatJobId "$id" "$name")
  if ! isJobEnabled "$_job_name"; then
    error "Job is disabled, enable it first with -E: $label"
  fi
  if isJobService "$_job_name"; then
    systemctl --user restart "${_job_name}.service" 2>/dev/null || true
  else
    systemctl --user restart "${_job_name}.timer" 2>/dev/null || true
  fi
  echo "Restarted: $label"
}

# Get all managed unit files of a given type (service or timer)
getManagedUnits() {
    local ext="$1"
    [[ -d "$SYSTEMD_USER_DIR" ]] || return
    local file
    for file in "$SYSTEMD_USER_DIR"/*."$ext"; do
        [[ -f "$file" ]] || continue
        grep -q "^$MARKER" "$file" 2>/dev/null && basename "$file" ".$ext"
    done
}

# Build flags string from opt_service, opt_notify, opt_email, and opt_name
buildFlagsString() {
    local flags=""
    if $opt_service; then
        flags="s"
    fi
    if $opt_notify; then
        [[ -n "$flags" ]] && flags+=","
        flags+="i"
    fi
    if [[ -n "$opt_output" ]]; then
        [[ -n "$flags" ]] && flags+=","
        if [[ "$opt_output" == "10" ]]; then flags+="o"; else flags+="o=$opt_output"; fi
    fi
    if [[ -n "$opt_email" ]]; then
        [[ -n "$flags" ]] && flags+=","
        flags+="e=$opt_email"
    fi
    if [[ -n "$opt_name" ]]; then
        [[ -n "$flags" ]] && flags+=","
        flags+="n=$opt_name"
    fi
    echo "$flags"
}

# Parse flags string into _notify_flag (bool), _email_addr (string), _name (string)
parseFlags() {
    local flags="$1"
    _notify_flag=false
    _email_addr=""
    _output_lines=""
    _name=""
    _service_flag=false
    IFS=',' read -ra parts <<< "$flags"
    for part in "${parts[@]}"; do
        case "$part" in
            s) _service_flag=true ;;
            i) _notify_flag=true ;;
            o) _output_lines=10 ;;
            o=*) _output_lines="${part#o=}" ;;
            e=*) _email_addr="${part#e=}" ;;
            n=*) _name="${part#n=}" ;;
        esac
    done
}

# Write ExecStopPost notification lines to a service file
# Usage: writeNotifyLines <short_id> <notify_flag> <email_addr> <file> [output_lines] [job_name]
writeNotifyLines() {
    local short_id="$1" notify="$2" email="$3" file="$4"
    local output_lines="${5-}" job_name="${6-}"
    local out_cmd=""
    if [[ -n "$output_lines" && -n "$job_name" ]]; then
        out_cmd="out=\$(journalctl --user SYSLOG_IDENTIFIER=$job_name -n $output_lines --no-pager -o cat); "
    fi
    # Look up the job name from the service file at notification runtime so the label
    # reflects the current name even if it was added or changed after job creation.
    # shellcheck disable=SC2016
    local label_pre="svc=\"$file\"; name=\$(grep \"^# SYSTAB_NAME=\" \"\$svc\" 2>/dev/null | cut -d= -f2-); [ -n \"\$name\" ] && label=\"$short_id (\$name)\" || label=\"$short_id\"; "
    # Common status preamble shared by all notification lines (intentionally unexpanded)
    # shellcheck disable=SC2016
    local icon_pre='if [ "$SERVICE_RESULT" = success ]; then icon=dialog-information; s=completed; else icon=dialog-error; s="failed ($EXIT_STATUS)"; fi; '
    # shellcheck disable=SC2016
    local status_pre='if [ "$SERVICE_RESULT" = success ]; then s=completed; else s="failed ($EXIT_STATUS)"; fi; '
    if [[ "$notify" == true ]]; then
        local notify_cmd
        if [[ -n "$out_cmd" ]]; then
            notify_cmd="${label_pre}${out_cmd}body=\$(printf \"Job \$label: %%s\n%%s\" \"\$s\" \"\$out\"); notify-send -i \"\$icon\" \"systab\" \"\$body\" || true"
        else
            notify_cmd="${label_pre}notify-send -i \"\$icon\" \"systab\" \"Job \$label: \$s\" || true"
        fi
        echo "ExecStopPost=/bin/sh -c '${icon_pre}${notify_cmd}'" >> "$file"
    fi
    if [[ -n "$email" ]]; then
        local mailer
        mailer=$(command -v sendmail || command -v msmtp || true)
        [[ -n "$mailer" ]] || { warn "No sendmail or msmtp found, skipping email notification"; return; }
        local mail_cmd
        if [[ -n "$out_cmd" ]]; then
            mail_cmd="${label_pre}${out_cmd}printf \"Subject: systab: \$label %%s\\\\n\\\\n%%s at %%s\\\\n\\\\n%%s\\\\n\" \"\$s\" \"\$s\" \"\$(date)\" \"\$out\" | $mailer $email"
        else
            mail_cmd="${label_pre}printf \"Subject: systab: \$label %%s\\\\n\\\\n%%s at %%s\\\\n\" \"\$s\" \"\$s\" \"\$(date)\" | $mailer $email"
        fi
        echo "ExecStopPost=/bin/sh -c '${status_pre}${mail_cmd}'" >> "$file"
    fi
}

# Write service + timer unit files (or service-only), enable and start
# Usage: _writeUnitFiles <command> <schedule> [flags] [job_type]
#   job_type: "timer" (default) or "service"
# Sets _created_id to the short ID of the new job
_writeUnitFiles() {
    local command_to_run="$1" schedule="$2" flags="${3-}" job_type="${4-timer}"
    local job_name short_id

    job_name="${SCRIPT_NAME}_$(generateId)"
    short_id=$(jobId "$job_name")

    mkdir -p "$SYSTEMD_USER_DIR"

    local service_file="$SYSTEMD_USER_DIR/${job_name}.service"

    if [[ "$job_type" == "service" ]]; then
        # Service-only unit (persistent, no timer)
        cat > "$service_file" <<EOF
$MARKER
# SYSTAB_TYPE=service
[Unit]
Description=$SCRIPT_NAME service: $job_name

[Service]
Type=simple
ExecStart=${SHELL:-/bin/bash} -c '$command_to_run'
StandardOutput=journal
StandardError=journal
SyslogIdentifier=$job_name
Restart=on-failure
EOF
        if [[ -n "$flags" ]]; then
            echo "# SYSTAB_FLAGS=$flags" >> "$service_file"
            parseFlags "$flags"
            [[ -n "$_name" ]] && echo "# SYSTAB_NAME=$_name" >> "$service_file"
        fi
        cat >> "$service_file" <<EOF

[Install]
WantedBy=default.target
EOF
        systemctl --user daemon-reload
        systemctl --user enable "${job_name}.service"
        systemctl --user start "${job_name}.service"
    else
        # Timer-backed unit
        cat > "$service_file" <<EOF
$MARKER
[Unit]
Description=$SCRIPT_NAME job: $job_name

[Service]
Type=oneshot
ExecStart=${SHELL:-/bin/bash} -c '$command_to_run'
StandardOutput=journal
StandardError=journal
SyslogIdentifier=$job_name
EOF

        if [[ -n "$flags" ]]; then
            echo "# SYSTAB_FLAGS=$flags" >> "$service_file"
            parseFlags "$flags"
            [[ -n "$_name" ]] && echo "# SYSTAB_NAME=$_name" >> "$service_file"
            writeNotifyLines "$short_id" "$_notify_flag" "$_email_addr" "$service_file" "$_output_lines" "$job_name"
        fi

        # Timer file
        local timer_file="$SYSTEMD_USER_DIR/${job_name}.timer"
        cat > "$timer_file" <<EOF
$MARKER
[Unit]
Description=Timer for $SCRIPT_NAME job: $job_name

[Timer]
OnCalendar=$schedule
EOF

        if ! isRecurring "$schedule"; then
            cat >> "$timer_file" <<'ONETIME'
Persistent=false
RemainAfterElapse=no
ONETIME
        fi

        cat >> "$timer_file" <<EOF

[Install]
WantedBy=timers.target
EOF

        systemctl --user enable "$job_name.timer"
        systemctl --user start "$job_name.timer"
    fi

    _created_id="$short_id"
}

# Check that a job name is unique across all managed jobs
checkNameUnique() {
    local name="$1"
    [[ -d "$SYSTEMD_USER_DIR" ]] || return
    local file
    for file in "${SYSTEMD_USER_DIR}/${SCRIPT_NAME}"_*.service; do
        [[ -f "$file" ]] || continue
        if grep -q "^# SYSTAB_NAME=${name}$" "$file" 2>/dev/null; then
            error "Job name '$name' is already in use"
        fi
    done
}

# Create a job from CLI options
createJob() {
    local command_to_run

    if [[ -n "$opt_command" ]]; then
        command_to_run="$opt_command"
    elif [[ -n "$opt_file" ]]; then
        [[ -f "$opt_file" ]] || error "File not found: $opt_file"
        [[ -x "$opt_file" ]] || error "File not executable: $opt_file"
        command_to_run="$opt_file"
    else
        if [[ -t 0 ]]; then
            echo "Please enter a command, then press Ctrl+D when done:" >&2
        fi
        command_to_run=$(cat)
        [[ -n "$command_to_run" ]] || error "No command provided"
    fi

    # Validate name uniqueness
    if [[ -n "$opt_name" ]]; then
        checkNameUnique "$opt_name"
    fi

    local label job_name
    if $opt_service; then
        _writeUnitFiles "$command_to_run" "service" "$(buildFlagsString)" service
        job_name="${SCRIPT_NAME}_${_created_id}"
        label=$(formatJobId "$_created_id" "$opt_name")
        echo "Service created: $label"
        if systemctl --user is-active "${job_name}.service" &>/dev/null; then
            echo "Status: Active (running)"
        else
            echo "Status: Inactive (check: systemctl --user status ${job_name}.service)"
        fi
    else
        local time_spec
        time_spec=$(parseTime "$opt_time")
        _writeUnitFiles "$command_to_run" "$time_spec" "$(buildFlagsString)"
        systemctl --user daemon-reload
        job_name="${SCRIPT_NAME}_${_created_id}"
        label=$(formatJobId "$_created_id" "$opt_name")
        echo "Job created: $label"
        echo "Next run: $(systemctl --user show "$job_name.timer" -p NextElapseUSecRealtime --value 2>/dev/null)"
    fi
}

# Remove a managed job (stop, disable, delete unit files)
removeJob() {
    local job_name="$1"
    if isJobService "$job_name"; then
        systemctl --user stop "${job_name}.service" 2>/dev/null || true
        systemctl --user disable "${job_name}.service" 2>/dev/null || true
        rm -f "$SYSTEMD_USER_DIR/${job_name}.service"
    else
        systemctl --user stop "${job_name}.timer" 2>/dev/null || true
        systemctl --user disable "${job_name}.timer" 2>/dev/null || true
        rm -f "$SYSTEMD_USER_DIR/${job_name}.service" "$SYSTEMD_USER_DIR/${job_name}.timer"
    fi
}

# Create a job from edit mode (schedule + command + flags, prints short ID)
createJobFromEdit() {
    local sched="$1" cmd="$2" flags="${3-}"
    if [[ "$sched" == "service" ]]; then
        _writeUnitFiles "$cmd" "service" "$flags" service
    else
        local schedule
        schedule=$(parseTime "$sched")
        _writeUnitFiles "$cmd" "$schedule" "$flags"
    fi
    echo "$_created_id"
}

# Print aligned job lines to stdout (no header/footer)
printCrontabContent() {
    local -a id_fields schedules commands disabled
    local job

    while IFS= read -r job; do
        [[ -z "$job" ]] && continue
        local timer_file="$SYSTEMD_USER_DIR/${job}.timer"
        local service_file="$SYSTEMD_USER_DIR/${job}.service"
        if [[ -f "$timer_file" && -f "$service_file" ]]; then
            local id schedule command flags id_field
            id=$(jobId "$job")
            schedule=$(grep "^OnCalendar=" "$timer_file" | cut -d= -f2-)
            command=$(getJobCommand "$service_file")
            flags=$(grep "^# SYSTAB_FLAGS=" "$service_file" 2>/dev/null | sed 's/^# SYSTAB_FLAGS=//' || true)
            [[ -n "$flags" ]] && id_field="$id:$flags" || id_field="$id"
            id_fields+=("$id_field")
            schedules+=("$schedule")
            commands+=("$command")
            if isJobEnabled "$job"; then disabled+=(false); else disabled+=(true); fi
        fi
    done < <(getManagedUnits timer)

    while IFS= read -r job; do
        [[ -z "$job" ]] && continue
        local service_file="$SYSTEMD_USER_DIR/${job}.service"
        if [[ -f "$service_file" ]]; then
            local id command flags id_field
            id=$(jobId "$job")
            command=$(getJobCommand "$service_file")
            flags=$(grep "^# SYSTAB_FLAGS=" "$service_file" 2>/dev/null | sed 's/^# SYSTAB_FLAGS=//' || true)
            [[ -n "$flags" ]] && id_field="$id:$flags" || id_field="$id:s"
            id_fields+=("$id_field")
            schedules+=("service")
            commands+=("$command")
            if isJobEnabled "$job"; then disabled+=(false); else disabled+=(true); fi
        fi
    done < <(getManagedServiceJobs)

    # Compute column widths; disabled lines account for the "# " prefix
    local max_id=0 max_sched=0 i len
    for i in "${!id_fields[@]}"; do
        len=${#id_fields[$i]}
        ${disabled[$i]} && len=$((len + 2))
        [[ $len -gt $max_id ]] && max_id=$len
        len=${#schedules[$i]}
        [[ $len -gt $max_sched ]] && max_sched=$len
    done

    # Print aligned lines
    for i in "${!id_fields[@]}"; do
        if ${disabled[$i]}; then
            printf '# %-*s | %-*s | %s\n' $((max_id - 2)) "${id_fields[$i]}" "$max_sched" "${schedules[$i]}" "${commands[$i]}"
        else
            printf '%-*s | %-*s | %s\n' "$max_id" "${id_fields[$i]}" "$max_sched" "${schedules[$i]}" "${commands[$i]}"
        fi
    done
}

# List jobs in crontab-like format to stdout
listCrontab() {
    printCrontabContent
}

# Edit jobs in crontab-like format
editJobs() {
    local temp_file orig_file
    temp_file="${TMPDIR:-/dev/shm}/systab_edit_$$"
    orig_file="${TMPDIR:-/dev/shm}/systab_orig_$$"
    # shellcheck disable=SC2064
    trap "rm -f '$temp_file' '$orig_file'" EXIT

    # Build crontab content: jobs first, condensed hint at bottom
    {
        printCrontabContent
        cat <<'HINT'
### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #
### format:  ID[:FLAGS] | SCHEDULE | COMMAND  #
### add:     new | daily | cmd                #
### flags:   n=name / i / e=addr / o[=N] / s  #
### comment out = disable / delete = remove   #
HINT
    } > "$temp_file"

    # Save original for diffing
    cp "$temp_file" "$orig_file"

    # Validate all time specs in a crontab file, returns 0 if valid
    # Prints error messages for each bad schedule
    validateCrontabSchedules() {
        local file="$1" errors=0 line
        while IFS= read -r line; do
            [[ -z "$line" ]] && continue
            local is_comment=false
            # Strip comment prefix for disabled jobs
            if [[ "$line" =~ ^#[[:space:]]+(.*) ]]; then
                line="${BASH_REMATCH[1]}"
                is_comment=true
            fi
            [[ "$line" == *"|"* ]] || continue
            # Extract and trim ID field
            local id_field="${line%%|*}"
            trim "$id_field"; id_field="$_trimmed"
            # Strip :flags suffix
            local id_bare="${id_field%%:*}"
            # Only validate lines with a valid job ID (6-char hex or "new")
            if $is_comment; then
                [[ "$id_bare" =~ ^[0-9a-f]{6}$ ]] || continue
            else
                [[ "$id_bare" =~ ^[0-9a-f]{6}$ || "$id_bare" == "new" ]] || continue
            fi
            local sched="${line#*|}"
            sched="${sched%%|*}"
            trim "$sched"; sched="$_trimmed"
            [[ -z "$sched" ]] && continue
            [[ "$sched" == "service" ]] && continue
            if ! (parseTime "$sched") &>/dev/null; then
                echo "Bad schedule: \"$sched\"" >&2
                errors=$((errors + 1))
            fi
        done < "$file"
        return "$errors"
    }

    # Edit loop: open editor, validate, re-edit on errors (like crontab -e)
    while true; do
        if ! "${EDITOR:-vi}" "$temp_file"; then
            echo "Editor exited with error, aborting."
            return 1
        fi

        # Check for no changes
        if diff -q "$orig_file" "$temp_file" &>/dev/null; then
            echo "No changes."
            return
        fi

        # Validate schedules before applying
        if validateCrontabSchedules "$temp_file"; then
            break
        fi

        echo "Errors in systab file, can't install." >&2
        read -p "Do you want to retry the same edit? (y/n) " -n 1 -r </dev/tty
        echo
        if [[ ! $REPLY =~ ^[Yy]$ ]]; then
            echo "Aborted."
            return 1
        fi
    done

    # Parse files into associative arrays: id -> "schedule\tcmd"
    # "new" lines are collected separately since there can be multiple
    # commented_ids tracks disabled (commented-out) job lines
    declare -A orig_jobs edited_jobs orig_commented edited_commented
    declare -a new_jobs=()

    # Parse a crontab line into id, flags, sched, cmd (split on first two | delimiters)
    # _parsed_id gets the bare ID, _parsed_flags gets any flags after ':'
    parseCrontabLine() {
        local line="$1"
        _parsed_id="" _parsed_flags="" _parsed_sched="" _parsed_cmd=""
        if [[ "$line" == *"|"* ]]; then
            local id_field="${line%%|*}"
            local rest="${line#*|}"
            _parsed_sched="${rest%%|*}"
            _parsed_cmd="${rest#*|}"
            # Trim leading/trailing whitespace
            trim "$id_field"; id_field="$_trimmed"
            trim "$_parsed_sched"; _parsed_sched="$_trimmed"
            trim "$_parsed_cmd"; _parsed_cmd="$_trimmed"
            # Split id_field on ':' into ID and flags
            if [[ "$id_field" == *:* ]]; then
                _parsed_id="${id_field%%:*}"
                _parsed_flags="${id_field#*:}"
            else
                _parsed_id="$id_field"
            fi
        fi
    }

    # Parse a file, populating jobs and commented arrays
    # Values stored as "flags<TAB>schedule|cmd"
    # Usage: parseCrontabFile <file> <jobs_var> <commented_var> [new_jobs_var]
    parseCrontabFile() {
        local file="$1" new_ref="${4-}"
        local -n _pcf_jobs="$2" _pcf_commented="$3"
        local line tab=$'\t'
        while IFS= read -r line; do
            [[ -z "$line" ]] && continue
            # Check for commented job line: "# <id> <sched> <cmd>"
            if [[ "$line" =~ ^#[[:space:]]+(.*) ]]; then
                local uncommented="${BASH_REMATCH[1]}"
                parseCrontabLine "$uncommented"
                # Only treat as disabled job if ID looks like a hex short ID (with optional :flags)
                if [[ -n "$_parsed_id" && -n "$_parsed_sched" && "$_parsed_id" =~ ^[0-9a-f]{6}$ ]]; then
                    _pcf_commented["$_parsed_id"]="${_parsed_flags}${tab}${_parsed_sched}|${_parsed_cmd}"
                fi
                continue
            fi
            parseCrontabLine "$line"
            [[ -n "$_parsed_id" && -n "$_parsed_sched" ]] || continue
            local val="${_parsed_flags}${tab}${_parsed_sched}|${_parsed_cmd}"
            if [[ "$_parsed_id" == "new" && -n "$new_ref" ]]; then
                eval "${new_ref}+=(\"$val\")"
            else
                _pcf_jobs["$_parsed_id"]="$val"
            fi
        done < "$file"
    }

    parseCrontabFile "$orig_file" orig_jobs orig_commented
    parseCrontabFile "$temp_file" edited_jobs edited_commented new_jobs

    # Collect all known IDs (from both active and commented in original)
    declare -A all_orig_ids
    for id in "${!orig_jobs[@]}"; do all_orig_ids["$id"]=1; done
    for id in "${!orig_commented[@]}"; do all_orig_ids["$id"]=1; done

    local created=0 deleted=0 updated=0 enabled=0 n_disabled=0 needs_reload=false

    # Deletions: IDs in original (active or commented) but absent from edited entirely
    for id in "${!all_orig_ids[@]}"; do
        if [[ -z "${edited_jobs[$id]+x}" && -z "${edited_commented[$id]+x}" ]]; then
            removeJob "${SCRIPT_NAME}_${id}"
            echo "Deleted: $id"
            deleted=$((deleted + 1))
            needs_reload=true
        fi
    done

    # Creations: "new" lines from edited file
    for entry in "${new_jobs[@]}"; do
        local new_flags new_rest sched cmd
        new_flags="${entry%%	*}"
        new_rest="${entry#*	}"
        sched="${new_rest%%|*}"
        cmd="${new_rest#*|}"
        local result
        result=$(createJobFromEdit "$sched" "$cmd" "$new_flags")
        echo "Created: $result"
        created=$((created + 1))
        needs_reload=true
    done

    # Handle unknown IDs (in edited but not in original and not "new")
    for id in "${!edited_jobs[@]}"; do
        if [[ -z "${all_orig_ids[$id]+x}" ]]; then
            warn "Ignoring unknown ID '$id' — use 'new' to create jobs"
        fi
    done
    for id in "${!edited_commented[@]}"; do
        if [[ -z "${all_orig_ids[$id]+x}" ]]; then
            warn "Ignoring unknown commented ID '$id'"
        fi
    done

    # Enable/disable transitions and updates
    for id in "${!all_orig_ids[@]}"; do
        local jname="${SCRIPT_NAME}_${id}"
        local was_commented=false now_commented=false
        [[ -n "${orig_commented[$id]+x}" ]] && was_commented=true
        [[ -n "${edited_commented[$id]+x}" ]] && now_commented=true

        # Skip if deleted
        [[ -z "${edited_jobs[$id]+x}" && -z "${edited_commented[$id]+x}" ]] && continue

        # Get old and new values (format: "flags\tsched|cmd")
        local old_entry="" new_entry=""
        if $was_commented; then
            old_entry="${orig_commented[$id]}"
        elif [[ -n "${orig_jobs[$id]+x}" ]]; then
            old_entry="${orig_jobs[$id]}"
        fi
        if $now_commented; then
            new_entry="${edited_commented[$id]}"
        elif [[ -n "${edited_jobs[$id]+x}" ]]; then
            new_entry="${edited_jobs[$id]}"
        fi

        # Split into flags and sched|cmd parts
        local old_flags old_rest new_flags new_rest
        old_flags="${old_entry%%	*}"
        old_rest="${old_entry#*	}"
        new_flags="${new_entry%%	*}"
        new_rest="${new_entry#*	}"

        # Handle enable/disable transitions
        if ! $was_commented && $now_commented; then
            disableJob "$jname"
            echo "Disabled: $id"
            n_disabled=$((n_disabled + 1))
            needs_reload=true
        elif $was_commented && ! $now_commented; then
            enableJob "$jname"
            echo "Enabled: $id"
            enabled=$((enabled + 1))
            needs_reload=true
        fi

        # Handle schedule/command/flags changes (whether active or commented)
        if [[ "$old_entry" != "$new_entry" ]]; then
            local old_sched new_sched old_cmd new_cmd
            old_sched="${old_rest%%|*}"
            new_sched="${new_rest%%|*}"
            old_cmd="${old_rest#*|}"
            new_cmd="${new_rest#*|}"

            local timer_file="$SYSTEMD_USER_DIR/${jname}.timer"
            local service_file="$SYSTEMD_USER_DIR/${jname}.service"

            if [[ "$old_sched" != "$new_sched" && -f "$timer_file" ]]; then
                new_sched=$(parseTime "$new_sched")
                sed -i "s|^OnCalendar=.*|OnCalendar=$new_sched|" "$timer_file"

                # Update one-time vs recurring settings
                if isRecurring "$new_sched"; then
                    sed -i '/^Persistent=false$/d; /^RemainAfterElapse=no$/d' "$timer_file"
                else
                    if ! grep -q "^Persistent=false" "$timer_file"; then
                        sed -i "/^OnCalendar=/a Persistent=false\nRemainAfterElapse=no" "$timer_file"
                    fi
                fi
            fi

            if [[ "$old_cmd" != "$new_cmd" && -f "$service_file" ]]; then
                sed -i "s|^ExecStart=.*|ExecStart=${SHELL:-/bin/bash} -c '$new_cmd'|" "$service_file"
            fi

            # Handle flags changes
            if [[ "$old_flags" != "$new_flags" && -f "$service_file" ]]; then
                # Remove existing notification lines, flags comment, and name comment
                sed -i '/^ExecStopPost=/d; /^# SYSTAB_FLAGS=/d; /^# SYSTAB_NAME=/d' "$service_file"
                # Add new flags and notification lines
                if [[ -n "$new_flags" ]]; then
                    echo "# SYSTAB_FLAGS=$new_flags" >> "$service_file"
                    parseFlags "$new_flags"
                    [[ -n "$_name" ]] && echo "# SYSTAB_NAME=$_name" >> "$service_file"
                    writeNotifyLines "$id" "$_notify_flag" "$_email_addr" "$service_file" "$_output_lines" "$jname"
                fi
            fi

            # Only restart if the job is active (not being disabled)
            if ! $now_commented; then
                if isJobService "$jname"; then
                    systemctl --user restart "${jname}.service" 2>/dev/null || true
                else
                    systemctl --user restart "${jname}.timer" 2>/dev/null || true
                fi
            fi

            echo "Updated: $id"
            updated=$((updated + 1))
            needs_reload=true
        fi
    done

    if $needs_reload; then
        systemctl --user daemon-reload
    fi

    echo ""
    echo "Summary: $created created, $updated updated, $deleted deleted, $enabled enabled, $n_disabled disabled"
}

# Build a job list from opt_jobid (single job) or getManagedUnits (all jobs)
# Usage: buildJobList <unit_type>
# Sets _job_list array; returns 1 if empty
buildJobList() {
    _job_list=()
    if [[ -n "$opt_jobid" ]]; then
        resolveJobId "$opt_jobid"
        _job_list+=("${SCRIPT_NAME}_${_resolved_id}")
    else
        local job
        while IFS= read -r job; do
            [[ -z "$job" ]] && continue
            _job_list+=("$job")
        done < <(getManagedUnits "$1")
    fi
    if [[ ${#_job_list[@]} -eq 0 ]]; then
        echo "No managed jobs found."
        return 1
    fi
}

# Show status of all managed jobs (or a single job if opt_jobid is set)
showStatus() {
    # Build combined list: timer jobs + service-only jobs
    _job_list=()
    if [[ -n "$opt_jobid" ]]; then
        resolveJobId "$opt_jobid"
        _job_list+=("${SCRIPT_NAME}_${_resolved_id}")
    else
        local job
        while IFS= read -r job; do
            [[ -z "$job" ]] && continue
            _job_list+=("$job")
        done < <(getManagedUnits timer; getManagedServiceJobs)
    fi
    if [[ ${#_job_list[@]} -eq 0 ]]; then
        echo "No managed jobs found."
        return
    fi

    local count=${#_job_list[@]}
    echo "Managed Jobs Status - $count total"
    echo "=========================================="
    echo ""

    for job in "${_job_list[@]}"; do
        local timer_file="$SYSTEMD_USER_DIR/${job}.timer"
        local service_file="$SYSTEMD_USER_DIR/${job}.service"

        local id name label
        id=$(jobId "$job")
        name=$(getJobName "$SYSTEMD_USER_DIR/${job}.service")
        label=$(formatJobId "$id" "$name")
        echo "Job: $label"

        if isJobService "$job"; then
            # Service-only job display
            echo "  Type: Service"
            if [[ -f "$service_file" ]]; then
                local command
                command=$(getJobCommand "$service_file")
                echo "  Command: $command"
            fi
            if ! isJobEnabled "$job"; then
                echo "  Service: Disabled"
            else
                local svc_active svc_sub
                svc_active=$(systemctl --user show "${job}.service" -p ActiveState --value 2>/dev/null)
                svc_sub=$(systemctl --user show "${job}.service" -p SubState --value 2>/dev/null)
                echo "  Service: ${svc_active} (${svc_sub})"
            fi
        else
            # Timer-backed job display
            if [[ -f "$timer_file" ]]; then
                local schedule
                schedule=$(grep "^OnCalendar=" "$timer_file" | cut -d= -f2-)
                echo "  Schedule: $schedule"
                if grep -q "^Persistent=false" "$timer_file"; then
                    echo "  Type: One-time"
                else
                    echo "  Type: Recurring"
                fi
            fi

            if [[ -f "$service_file" ]]; then
                local command
                command=$(getJobCommand "$service_file")
                echo "  Command: $command"
            fi

            if ! isJobEnabled "$job"; then
                echo "  Timer: Disabled"
            elif systemctl --user is-active "${job}.timer" &>/dev/null; then
                echo "  Timer: Active"
                local next_run last_run
                next_run=$(systemctl --user show "${job}.timer" -p NextElapseUSecRealtime --value 2>/dev/null)
                last_run=$(systemctl --user show "${job}.timer" -p LastTriggerUSec --value 2>/dev/null)
                [[ -n "$next_run" ]] && echo "  Next run: $next_run"
                [[ -n "$last_run" ]] && echo "  Last run: $last_run"
            else
                echo "  Timer: Inactive/Completed"
            fi

            if systemctl --user is-failed "${job}.service" &>/dev/null; then
                echo "  Service: Failed"
            elif systemctl --user is-active "${job}.service" &>/dev/null; then
                echo "  Service: Running"
            else
                local exit_status
                exit_status=$(systemctl --user show "${job}.service" -p ExecMainStatus --value 2>/dev/null)
                if [[ -n "$exit_status" && "$exit_status" != "0" ]]; then
                    echo "  Service: Completed with exit code $exit_status"
                else
                    echo "  Service: Completed"
                fi
            fi
        fi

        echo ""
    done

    # Show systemctl list-timers summary
    echo "Active Timers:"
    echo "--------------"
    systemctl --user list-timers "systab_*" --no-pager 2>/dev/null || echo "none active"
}

# List logs (or logs for a single job if opt_jobid is set)
listLogs() {
    buildJobList service || return

    echo "Found ${#_job_list[@]} managed jobs"
    echo ""

    local grep_args=()
    [[ -n "$opt_filter" ]] && grep_args=(--grep "$opt_filter")

    for job in "${_job_list[@]}"; do
        local id name label
        id=$(jobId "$job")
        name=$(getJobName "$SYSTEMD_USER_DIR/${job}.service")
        label=$(formatJobId "$id" "$name")
        echo "=== Logs for $label ==="

        if isJobService "$job"; then
            local svc_active svc_sub
            svc_active=$(systemctl --user show "${job}.service" -p ActiveState --value 2>/dev/null)
            svc_sub=$(systemctl --user show "${job}.service" -p SubState --value 2>/dev/null)
            echo "Status: ${svc_active} (${svc_sub})"
            systemctl --user status "${job}.service" --no-pager -l 2>/dev/null | head -n 3 || true
        elif systemctl --user is-active "${job}.timer" &>/dev/null; then
            echo "Status: Active"
            systemctl --user status "${job}.timer" --no-pager -l | head -n 3
        else
            echo "Status: Inactive"
        fi
        echo ""

        journalctl --user USER_UNIT="${job}.service" + SYSLOG_IDENTIFIER="$job" \
            --no-pager "${grep_args[@]}" 2>/dev/null || echo "no logs yet"
        echo ""
    done
}

# Clean up completed jobs
cleanJobs() {
    local job cleaned=0
    
    while IFS= read -r job; do
        [[ -z "$job" ]] && continue
        
        local timer_file="$SYSTEMD_USER_DIR/${job}.timer"
        
        # Check if it's a one-time job (has Persistent=false)
        if grep -q "^Persistent=false" "$timer_file" 2>/dev/null; then
            # Check if timer is in "elapsed" state (completed one-time timer)
            local timer_state
            timer_state=$(systemctl --user show "${job}.timer" -p SubState --value 2>/dev/null)
            
            # One-time timers that have fired will be in "elapsed" or "dead" state
            if [[ "$timer_state" == "elapsed" || "$timer_state" == "dead" ]]; then
                # Get the command for display
                local command
                command=$(getJobCommand "$SYSTEMD_USER_DIR/${job}.service" 2>/dev/null || echo "unknown")
                
                read -p "Remove completed job '$job' (command: $command)? [y/N] " -n 1 -r </dev/tty
                echo
                if [[ $REPLY =~ ^[Yy]$ ]]; then
                    removeJob "$job"
                    echo "Removed: $job"
                    cleaned=$((cleaned + 1))
                fi
            fi
        fi
    done < <(getManagedUnits timer)
    
    if [[ $cleaned -gt 0 ]]; then
        systemctl --user daemon-reload
        echo "Cleaned up $cleaned jobs."
    else
        echo "No completed one-time jobs to clean up."
    fi
}

# Parse command-line options
parseOptions() {
    while getopts "t:sc:f:n:im:oD:E:X:R:elLSCh" opt; do
        case $opt in
            t) opt_time="$OPTARG" ;;
            s) opt_service=true ;;
            c) opt_command="$OPTARG" ;;
            f) opt_file="$OPTARG" ;;
            n) opt_name="$OPTARG" ;;
            i) opt_notify=true ;;
            m) opt_email="$OPTARG" ;;
            o) # Optional argument: peek at next arg for a number
                if [[ $OPTIND -le $# ]]; then
                    local next="${!OPTIND}"
                    if [[ "$next" =~ ^[0-9]+$ ]]; then
                        opt_output="$next"
                        OPTIND=$((OPTIND + 1))
                    else
                        opt_output=10
                    fi
                else
                    opt_output=10
                fi ;;
            D) opt_disable="$OPTARG" ;;
            E) opt_enable="$OPTARG" ;;
            X) opt_delete="$OPTARG" ;;
            R) opt_restart="$OPTARG" ;;
            e) opt_edit=true ;;
            l) opt_print_crontab=true ;;
            L) opt_list=true ;;
            S) opt_status=true ;;
            C) opt_clean=true ;;
            h) usage 0 ;;
            *) usage 1 ;;
        esac
    done
    
    # Check for trailing arguments after -S or -L
    if ($opt_list || $opt_status) && [[ $OPTIND -le $# ]]; then
        local trailing="${!OPTIND}"
        # Try to resolve as job ID or name (run in subshell to catch error exit)
        if (resolveJobId "$trailing") 2>/dev/null; then
            opt_jobid="$trailing"
            # For -L, check for a second trailing arg as text filter
            if $opt_list; then
                local next_idx=$((OPTIND + 1))
                if [[ $next_idx -le $# ]]; then
                    opt_filter="${!next_idx}"
                fi
            fi
        elif $opt_list; then
            # Not a job ID or name — treat as text filter for backward compatibility
            opt_filter="$trailing"
        else
            error "No job found with ID or name: $trailing"
        fi
    fi
    
    # Validate name format
    if [[ -n "$opt_name" ]]; then
        if [[ "$opt_name" =~ [[:space:]|:] ]]; then
            error "Job name must not contain whitespace, pipes, or colons"
        fi
    fi

    # Validate mutually exclusive options
    local manage_count=0
    [[ -n "$opt_disable" ]] && manage_count=$((manage_count + 1))
    [[ -n "$opt_enable" ]] && manage_count=$((manage_count + 1))
    [[ -n "$opt_delete" ]] && manage_count=$((manage_count + 1))
    [[ -n "$opt_restart" ]] && manage_count=$((manage_count + 1))
    $opt_edit && manage_count=$((manage_count + 1))
    $opt_print_crontab && manage_count=$((manage_count + 1))
    $opt_list && manage_count=$((manage_count + 1))
    $opt_status && manage_count=$((manage_count + 1))
    $opt_clean && manage_count=$((manage_count + 1))

    if [[ $manage_count -gt 1 ]]; then
        error "Options -D, -E, -X, -R, -e, -l, -L, -S, and -C are mutually exclusive"
    fi

    if [[ $manage_count -gt 0 ]] && { [[ -n "$opt_time$opt_command$opt_file" ]] || $opt_service; }; then
        error "Management options -D, -E, -X, -R, -e, -l, -L, -S, and -C cannot be used with job creation options"
    fi
    
    if [[ -n "$opt_command" && -n "$opt_file" ]]; then
        error "Options -c and -f are mutually exclusive"
    fi
    
    # Validate create mode requirements
    if [[ $manage_count -eq 0 ]]; then
        if $opt_service; then
            [[ -z "$opt_time" ]] || error "Options -s and -t are mutually exclusive"
            $opt_notify && error "Option -i is not supported for service jobs"
            [[ -z "$opt_email" ]] || error "Option -m is not supported for service jobs"
            [[ -z "$opt_output" ]] || error "Option -o is not supported for service jobs"
        else
            [[ -n "$opt_time" ]] || error "Option -t or -s is required for job creation"
        fi
    fi
}

main() {
    [[ $# -eq 0 ]] && usage 0
    parseOptions "$@"
    
    # Determine mode based on options
    if [[ -n "$opt_disable" ]]; then
        toggleJobById "$opt_disable" disable
    elif [[ -n "$opt_enable" ]]; then
        toggleJobById "$opt_enable" enable
    elif [[ -n "$opt_delete" ]]; then
        deleteJob "$opt_delete"
    elif [[ -n "$opt_restart" ]]; then
        restartJob "$opt_restart"
    elif $opt_edit; then
        editJobs
    elif $opt_print_crontab; then
        listCrontab
    elif $opt_list; then
        listLogs
    elif $opt_status; then
        showStatus
    elif $opt_clean; then
        cleanJobs
    else
        createJob
    fi
}

main "$@"
