#!/usr/bin/env bash
# =============================================================================
# onx-ssh-key-list — Parse a user's authorized_keys file into JSON.
#
# Input (stdin JSON):
#   {"username":"onx_acme01"}
#
# Output (stdout JSON):
#   {
#     "username": "onx_acme01",
#     "count": 2,
#     "keys": [
#       {
#         "type":        "ssh-rsa",
#         "fingerprint": "SHA256:abc...",
#         "comment":     "my-laptop",
#         "bits":        3072,
#         "line_no":     1
#       },
#       ...
#     ]
#   }
#
# Notes:
#   - Comment-only lines (starting with #) are skipped.
#   - Blank lines are skipped.
#   - Each non-blank, non-comment line is run through ssh-keygen -l. Lines that
#     ssh-keygen rejects are dropped silently (we audit them in syslog).
#
# Exit codes: 0=ok 1=invalid 2=preflight
# =============================================================================

set -euo pipefail

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

require_root
require_cmd ssh-keygen

onx_json_input

USERNAME=$(onx_json_field "username")
onx_validate_username "${USERNAME}"

HOME_DIR="/home/${USERNAME}"
AK_FILE="${HOME_DIR}/.ssh/authorized_keys"

# Build JSON via jq from an array we accumulate.
KEYS_JSON='[]'
COUNT=0
LINE_NO=0
INVALID_LINES=0

if [[ -f "${AK_FILE}" ]]; then
    while IFS= read -r line || [[ -n "${line}" ]]; do
        LINE_NO=$((LINE_NO + 1))
        case "${line}" in
            ''|\#*) continue ;;
        esac

        TMP_FP="$(mktemp -t onx-list.XXXXXX)"
        chmod 600 "${TMP_FP}"
        printf '%s\n' "${line}" > "${TMP_FP}"

        # ssh-keygen -l outputs: "<bits> SHA256:<hash> <comment> (<type>)"
        # — comment may contain spaces; type is the last paren-quoted field.
        OUT="$(ssh-keygen -l -f "${TMP_FP}" 2>/dev/null || true)"
        rm -f "${TMP_FP}"

        if [[ -z "${OUT}" ]]; then
            INVALID_LINES=$((INVALID_LINES + 1))
            continue
        fi

        BITS="$(printf '%s' "${OUT}" | awk '{print $1}')"
        FP="$(printf '%s'   "${OUT}" | awk '{print $2}')"
        # Type is the last whitespace-separated token, wrapped in parens
        TYPE_RAW="$(printf '%s' "${OUT}" | awk '{print $NF}')"
        TYPE="${TYPE_RAW#(}"; TYPE="${TYPE%)}"
        # Comment is everything between $2 and $(NF) — may be empty
        COMMENT="$(printf '%s' "${OUT}" | awk '{ for(i=3;i<NF;i++) printf "%s%s", $i, (i<NF-1?" ":"") }')"

        # Bits must be numeric; comment becomes a JSON string field
        if [[ ! "${BITS}" =~ ^[0-9]+$ ]]; then
            BITS=0
        fi

        KEYS_JSON="$(printf '%s' "${KEYS_JSON}" | jq \
            --arg type "${TYPE}" \
            --arg fp "${FP}" \
            --arg comment "${COMMENT}" \
            --argjson bits "${BITS}" \
            --argjson line "${LINE_NO}" \
            '. + [{ "type":$type, "fingerprint":$fp, "comment":$comment, "bits":$bits, "line_no":$line }]')"
        COUNT=$((COUNT + 1))
    done < "${AK_FILE}"
fi

if [[ "${INVALID_LINES}" -gt 0 ]]; then
    onx_audit "onx-ssh" "list user=${USERNAME} count=${COUNT} invalid_lines=${INVALID_LINES}"
fi

# Emit final JSON (nested objects → cannot use onx_json_out flat helper)
jq -n \
    --arg username "${USERNAME}" \
    --argjson count "${COUNT}" \
    --argjson keys  "${KEYS_JSON}" \
    '{username:$username, count:$count, keys:$keys}'
