#!/usr/bin/env bash
set -uo pipefail

CHARSET='A-Za-z0-9._+\-:@^~'
DEFAULT_LENGTH=32

usage() {
    cat <<'EOF'
Usage: gen-secret [OPTIONS] [LENGTH]

Generate a cryptographically random string safe for bash, YAML, and JSON.

Arguments:
  LENGTH    Number of characters (default: 32)

Options:
  -n, --dryrun    Preview what would happen
  -h, --help      Show this help
EOF
}

dryrun=false
length=""

while [[ $# -gt 0 ]]; do
    case "$1" in
        -h|--help)
            usage
            exit 0
            ;;
        -n|--dryrun)
            dryrun=true
            shift
            ;;
        -*)
            echo "Error: Unknown option: $1" >&2
            exit 1
            ;;
        *)
            if [[ -n "$length" ]]; then
                echo "Error: Too many arguments" >&2
                exit 1
            fi
            length="$1"
            shift
            ;;
    esac
done

length="${length:-$DEFAULT_LENGTH}"

if ! [[ "$length" =~ ^[0-9]+$ ]] || [[ "$length" -le 0 ]]; then
    echo "Error: Length must be a positive integer" >&2
    exit 1
fi

if $dryrun; then
    echo "[dryrun] Would generate a ${length}-character secret from charset: [${CHARSET}]"
    exit 0
fi

tr -dc "$CHARSET" < /dev/urandom | head -c "$length"
echo
