#!/usr/bin/env bash
#
# decrypt-vault-strings-from-file.sh
#
# Zweck:
#   - Entschlüsselt entweder:
#       (A) eine komplett mit ansible-vault verschlüsselte Datei (ANSIBLE_VAULT Header)
#       (B) einzelne YAML "!vault |" Blöcke in einer Datei (z.B. group_vars/host_vars)
#       (C) einen einzelnen verschlüsselten String (Argument, Pipe oder interaktiv)
#
# Erwartet eine Vault-Passwortdatei unter: ~/.vault-pass
#

set -euo pipefail

########################################
# Hilfe anzeigen
########################################
show_help() {
  cat <<EOF
Usage:
  $(basename "$0") [OPTION] [INPUT]

Decrypt modes:

  1) Full vault-encrypted file (ANSIBLE_VAULT header):
     $(basename "$0") secrets.vault

  2) YAML file containing one or multiple "!vault |" blocks:
     $(basename "$0") group_vars/all.yml

  3) Encrypted vault string:
     $(basename "$0") 'secret: !vault | \$ANSIBLE_VAULT;1.1;AES256 ...'
     echo 'secret: !vault | ...' | $(basename "$0")

  4) Interactive mode (paste, then Ctrl-D):
     $(basename "$0")

Options:
  -h, --help   Show this help and exit

Notes:
  - This script prints decrypted values to stdout.
EOF
}

########################################
# Hauptfunktion
########################################
vdecr() {
  unset IFS

  # --- Help Flag innerhalb der Funktion (falls rekursiv aufgerufen) ---
  if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then
    show_help
    return 0
  fi

  # Prüfen ob ansible-vault existiert
  if ! command -v ansible-vault >/dev/null 2>&1; then
    echo "Error: ansible-vault not found in PATH." >&2
    return 1
  fi

  ########################################
  # Wenn ein Argument übergeben wurde
  ########################################
  if [[ -n "${1:-}" ]]; then

    # --- Fall 1: Argument ist eine Datei ---
    if [[ -f "$1" ]]; then

      # Wenn Datei eine "komplett verschlüsselte" Vault-Datei ist
      # (Header ist die erste Zeile)
      if [[ "$(head -n1 "$1")" == "\$ANSIBLE_VAULT;1.1;AES256" ]]; then
        # Vollständige Datei entschlüsseln und ausgeben
        ansible-vault decrypt "$1" 2>/dev/null
        return 0
      fi

      # --- Fall 2: Datei enthält einzelne "!vault" Blöcke (z.B. YAML) ---
      printf 'Reading vault values from file...\n\n'

      # parsing = 0 -> wir sind nicht im Vault-Block
      # parsing = 1 -> wir sammeln gerade Vault-Block-Zeilen
      local parsing=0
      local result=""
      local name=""

      # Farbausgabe (blau) für den jeweiligen Key/Name
      local blue
      local discard
      blue="$(tput setaf 4 || true)"
      discard="$(tput sgr0 || true)"

      # Originalscript hat "for line in \$(cat file)" verwendet,
      # was nach Whitespace tokenisiert. Um das Verhalten kontrollierter
      # beizubehalten, tokenisieren wir hier ebenfalls nach Whitespace:
      #
      # - Das hilft, wenn Vault-Blöcke eingerückt sind oder YAML Zeichen enthält,
      #   weil später ohnehin per sed weiter "normalisiert" wird.
      #
      # WICHTIG: Das ist nicht "echtes" YAML-Parsing, sondern best-effort.
      while IFS= read -r token; do

        # Start eines vault blocks erkennen (Token enthält "!vault")
        if [[ "$(echo "$token" | grep -c "\!vault")" -gt 0 ]] && [[ $parsing -eq 0 ]]; then
          parsing=1

        # Im Vault-Block: Token ohne ":" werden gesammelt (Ciphertext-Zeilen)
        elif [[ $parsing -eq 1 ]] && [[ "$(echo "$token" | grep -c ":")" -eq 0 ]]; then
          result="$(printf "%s\n%s" "$result" "$token")"

        # Sonst: Blockende / neuer Bereich
        else
          # Wenn wir einen gesammelten Block haben -> ausgeben und decrypten
          if [[ -n "$result" ]]; then
            printf "\n\n%s%s%s\n" "$blue" "$name" "$discard"
            # Rekursiver Aufruf: der gesammelte Block wird wie "Stringinput"
            # behandelt und im unteren Abschnitt entschlüsselt
            printf "%s" "$result" | vdecr
            name=""
            result=""
            parsing=0
          fi
        fi

        # Token mit ":" als "Name" merken (typischerweise YAML key:)
        if [[ "$(echo "$token" | grep -c ":")" -eq 1 ]]; then
          name="$token"
        fi

      # Tokenisierung nach Whitespace (ähnlich dem Original)
      done < <(tr -s '[:space:]' '\n' < "$1")

      return 0
    fi

    # --- Fall 3: Argument ist ein String ---
    local str="$1"

  # --- Fall 4: String kommt per Pipe (stdin ist kein TTY) ---
  elif [[ ! -t 0 ]]; then
    local str
    str="$(cat)"

  # --- Fall 5: Interaktiv ---
  else
    printf 'Interactive mode. Paste encrypted string and press Ctrl-D two times to confirm.\n'
    local str
    str="$(cat)"
    printf '\n'
  fi

  ########################################
  # String entschlüsseln
  #
  # Das Script erwartet, dass der Input evtl. als YAML-Fragment kommt,
  # und "normalisiert" ihn so, dass ansible-vault decrypt damit klarkommt:
  #
  # - ersetzt Spaces durch Newlines
  # - entfernt YAML-Deko wie "---", "key:", "!vault", "|", leere Zeilen
  # - piped den Rest in "ansible-vault decrypt"
  ########################################
  printf -- "%s" "$str" | \
    sed 's/ /\n/g' | \
    sed '/---\|^.*:\|\!vault\||\|^$/d' | \
    ansible-vault decrypt 2>/dev/null

  printf '\n'
}

########################################
# Main
########################################
if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then
  show_help
  exit 0
fi

vdecr "${1:-}"
