#!/usr/bin/env bash

set -euo pipefail

usage() {
    cat <<'EOF'
Usage: journalwindow [OPTIONS]

Query the system journal and render entries without folding message lines.

Options:
  -u, --unit UNIT          Limit the query to UNIT (repeatable)
  -p, --severity LEVEL     Pass LEVEL to journalctl --priority
  -b, --boot ID            Limit the query to boot ID or offset
  -S, --since TIME         Start at TIME
  -U, --until TIME         Stop at TIME
      --redact TOKEN       Replace literal TOKEN in rendered fields (repeatable)
  -h, --help               Show this help
EOF
}

die() {
    printf 'journalwindow: %s\n' "$*" >&2
    exit 2
}

require_value() {
    local option=$1
    local value=${2-}
    [[ -n "$value" ]] || die "$option requires a non-empty value"
}

units=()
redactions=()
severity=''
boot=''
since=''
until=''

while (($#)); do
    case $1 in
        -u|--unit)
            require_value "$1" "${2-}"
            units+=("$2")
            shift 2
            ;;
        --unit=*)
            require_value --unit "${1#*=}"
            units+=("${1#*=}")
            shift
            ;;
        -p|--severity)
            require_value "$1" "${2-}"
            severity=$2
            shift 2
            ;;
        --severity=*)
            require_value --severity "${1#*=}"
            severity=${1#*=}
            shift
            ;;
        -b|--boot)
            require_value "$1" "${2-}"
            boot=$2
            shift 2
            ;;
        --boot=*)
            require_value --boot "${1#*=}"
            boot=${1#*=}
            shift
            ;;
        -S|--since)
            require_value "$1" "${2-}"
            since=$2
            shift 2
            ;;
        --since=*)
            require_value --since "${1#*=}"
            since=${1#*=}
            shift
            ;;
        -U|--until)
            require_value "$1" "${2-}"
            until=$2
            shift 2
            ;;
        --until=*)
            require_value --until "${1#*=}"
            until=${1#*=}
            shift
            ;;
        --redact)
            require_value "$1" "${2-}"
            redactions+=("$2")
            shift 2
            ;;
        --redact=*)
            require_value --redact "${1#*=}"
            redactions+=("${1#*=}")
            shift
            ;;
        -h|--help)
            usage
            exit 0
            ;;
        --)
            shift
            (($# == 0)) || die "unexpected positional argument: $1"
            ;;
        -*)
            die "unknown option: $1"
            ;;
        *)
            die "unexpected positional argument: $1"
            ;;
    esac
done

journalctl_bin=${JOURNALWINDOW_JOURNALCTL:-journalctl}
python_bin=${JOURNALWINDOW_PYTHON:-python3}
script_dir=$(CDPATH= cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)

query=("$journalctl_bin" --no-pager --output=json)
for unit in "${units[@]}"; do
    query+=(--unit "$unit")
done
[[ -z "$severity" ]] || query+=(--priority "$severity")
[[ -z "$boot" ]] || query+=(--boot "$boot")
[[ -z "$since" ]] || query+=(--since "$since")
[[ -z "$until" ]] || query+=(--until "$until")

reproduction=''
for argument in "${query[@]}"; do
    printf -v quoted '%q' "$argument"
    if [[ -n "$reproduction" ]]; then
        reproduction+=' '
    fi
    reproduction+=$quoted
done
export JOURNALWINDOW_REPRODUCTION=$reproduction

formatter_args=()
for token in "${redactions[@]}"; do
    formatter_args+=(--redact "$token")
done

"${query[@]}" | "$python_bin" "$script_dir/lib/journalwindow.py" "${formatter_args[@]}"
