#!/usr/bin/env bash
# =============================================================================
# onx-gpg-key-gen — Generate a GPG key in a per-user keyring
#
# Input (stdin JSON):
#   {
#     "username":   "onx_xxxx",
#     "real_name":  "John Doe",
#     "email":      "john@example.com",
#     "comment":    "main key",          // optional
#     "key_size":   2048,                // 2048 or 4096
#     "expires":    "0" | "1y" | "365d", // 0 = never
#     "passphrase": ""                   // optional; empty = unprotected
#   }
#
# Behaviour:
#   - Keyring lives at /home/$USERNAME/.gnupg (mode 700, owned by user).
#   - Idempotency: if a key for the same name+email already exists, returns it
#     instead of generating a new one (so accidental retries don't pile up keys).
#
# Output:
#   {
#     "fingerprint": "AABBCC...40hex",
#     "key_id":      "1F2E3D4C5B6A7890",
#     "public_key":  "-----BEGIN PGP PUBLIC KEY BLOCK-----...",
#     "created":     true | false   // false if reused existing key
#   }
#
# Exit codes: 0=ok 1=invalid-input 2=preflight-fail 3=execution-fail
# Deployed to: /usr/local/onoxsoft/bin/onx-gpg-key-gen
# =============================================================================

set -euo pipefail

SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
source "${SCRIPT_DIR}/_lib/common.sh"

require_cmd jq
require_cmd gpg

INPUT=$(cat)
onx_require_json "${INPUT}"

USERNAME=$(onx_json_get "${INPUT}" "username")
REAL_NAME=$(onx_json_get "${INPUT}" "real_name")
EMAIL=$(onx_json_get    "${INPUT}" "email")
COMMENT=$(onx_json_get  "${INPUT}" "comment" "")
KEY_SIZE=$(onx_json_get "${INPUT}" "key_size" "2048")
EXPIRES=$(onx_json_get  "${INPUT}" "expires" "0")
PASSPHRASE=$(onx_json_get "${INPUT}" "passphrase" "")

onx_validate_username "${USERNAME}"

[[ -n "${REAL_NAME}" ]] || onx_die 1 "real_name is required"
[[ -n "${EMAIL}"     ]] || onx_die 1 "email is required"

case "${KEY_SIZE}" in
    2048|3072|4096) : ;;
    *) onx_die 1 "key_size must be 2048, 3072, or 4096" ;;
esac

id "${USERNAME}" &>/dev/null || onx_die 2 "Linux user does not exist: ${USERNAME}"

GNUPGHOME="/home/${USERNAME}/.gnupg"
mkdir -p "${GNUPGHOME}"
chmod 700 "${GNUPGHOME}"
chown -R "${USERNAME}:${USERNAME}" "${GNUPGHOME}"

# ── Idempotency check ───────────────────────────────────────────────────────
# If a usable secret key matches name<email>, return it unchanged.
EXISTING_FPR=$(su -s /bin/bash "${USERNAME}" -c \
    "gpg --homedir '${GNUPGHOME}' --list-secret-keys --with-colons --with-fingerprint 2>/dev/null" \
    | awk -F: -v want="${EMAIL}" '
        /^sec/ { in_block=1; fpr=""; next }
        /^fpr/ && in_block && fpr=="" { fpr=$10; next }
        /^uid/ && in_block {
            uid=$10
            if (index(uid, "<"want">") > 0 && fpr != "") { print fpr; exit }
        }
    ' || echo "")

if [[ -n "${EXISTING_FPR}" ]]; then
    PUB_KEY=$(su -s /bin/bash "${USERNAME}" -c \
        "gpg --homedir '${GNUPGHOME}' --armor --export '${EXISTING_FPR}'" 2>/dev/null || echo "")
    KEY_ID="${EXISTING_FPR:24:16}"
    PUB_J=$(printf '%s' "${PUB_KEY}" | jq -Rs '.')
    onx_log "gpg-key-gen: idempotent reuse ${EXISTING_FPR} for ${EMAIL}"
    printf '{"fingerprint":"%s","key_id":"%s","public_key":%s,"created":false}\n' \
        "${EXISTING_FPR}" "${KEY_ID}" "${PUB_J}"
    exit 0
fi

# ── Build gpg batch file ────────────────────────────────────────────────────
BATCH=$(mktemp -t onx-gpg-batch.XXXXXX)
chmod 600 "${BATCH}"
chown "${USERNAME}:${USERNAME}" "${BATCH}"
trap 'shred -u "${BATCH}" 2>/dev/null || rm -f "${BATCH}" 2>/dev/null || true' EXIT

{
    echo "Key-Type: RSA"
    echo "Key-Length: ${KEY_SIZE}"
    echo "Subkey-Type: RSA"
    echo "Subkey-Length: ${KEY_SIZE}"
    echo "Name-Real: ${REAL_NAME}"
    [[ -n "${COMMENT}" ]] && echo "Name-Comment: ${COMMENT}"
    echo "Name-Email: ${EMAIL}"
    echo "Expire-Date: ${EXPIRES}"
    if [[ -n "${PASSPHRASE}" ]]; then
        echo "Passphrase: ${PASSPHRASE}"
    else
        echo "%no-protection"
    fi
    echo "%commit"
} > "${BATCH}"

onx_log "gpg-key-gen: generating ${KEY_SIZE}-bit key for ${USERNAME} (${EMAIL})"

# ── Run the generator (entropy can be slow on headless boxes; allow a minute) ─
su -s /bin/bash "${USERNAME}" -c \
    "gpg --homedir '${GNUPGHOME}' --batch --pinentry-mode loopback --gen-key '${BATCH}'" \
    >/dev/null 2>&1 || onx_die 3 "gpg --gen-key failed"

# ── Read the fresh fingerprint (most recent sec line) ────────────────────────
FPR=$(su -s /bin/bash "${USERNAME}" -c \
    "gpg --homedir '${GNUPGHOME}' --list-secret-keys --with-colons --with-fingerprint" \
    | awk -F: -v want="${EMAIL}" '
        /^sec/ { in_block=1; fpr=""; next }
        /^fpr/ && in_block && fpr=="" { fpr=$10; next }
        /^uid/ && in_block {
            if (index($10, "<"want">") > 0 && fpr != "") { print fpr; exit }
        }
    ' || true)

[[ -n "${FPR}" ]] || onx_die 3 "could not determine fingerprint after generation"

PUB_KEY=$(su -s /bin/bash "${USERNAME}" -c \
    "gpg --homedir '${GNUPGHOME}' --armor --export '${FPR}'" 2>/dev/null || true)
KEY_ID="${FPR:24:16}"
PUB_J=$(printf '%s' "${PUB_KEY}" | jq -Rs '.')

onx_log "gpg-key-gen: created ${FPR} for ${USERNAME} (${EMAIL})"

printf '{"fingerprint":"%s","key_id":"%s","public_key":%s,"created":true}\n' \
    "${FPR}" "${KEY_ID}" "${PUB_J}"
