#!/usr/bin/env bash
# A script for encrypting and decrypting files or directories with age and SSH keys

VERSION="1.0.0"

# Default ENV values
KEYS_FILE="${AGE_KEYSFILE:-$HOME/.ssh/keys.txt}"
KEYS_SOURCE="${AGE_KEYSSOURCE:-https://github.com/ivuorinen.keys}"
LOG_FILE="${AGE_LOGFILE:-$HOME/.cache/a.log}"

VERBOSE=false

# Parse flags for verbosity
for arg in "$@"; do
  if [[ "$arg" == "-v" || "$arg" == "--verbose" ]]; then
    VERBOSE=true
    break
  fi
done

# Ensure log directory and file exist with correct permissions
prepare_log_file()
{
  local log_dir
  log_dir=$(dirname "$LOG_FILE")

  # Create log directory if it does not exist
  if [[ ! -d "$log_dir" ]]; then
    mkdir -p "$log_dir"
  fi

  # Create log file if it does not exist
  if [[ ! -f "$LOG_FILE" ]]; then
    touch "$LOG_FILE"
  fi

  # Set permissions to 0600
  chmod 0600 "$LOG_FILE"
}

prepare_log_file

# Logging function
log_message()
{
  local message="$1"
  echo "$(date +'%Y-%m-%d %H:%M:%S') - $message" >> "$LOG_FILE"

  # Print to user if verbose flag is set
  if [[ "$VERBOSE" == true ]]; then
    echo "$message"
  fi
}

# Function to print usage
print_help()
{
  cat << EOF
Usage: a [command] [file_or_directory] [options]

Commands:
  e, enc, encrypt      Encrypt the specified file or directory
  d, dec, decrypt      Decrypt the specified file or directory
  help, --help         Show this help message
  version, --version   Show version information

Options:
  -v, --verbose        Print log messages to console in addition to writing to log file

Environment Variables:
  AGE_KEYSFILE         Path to the SSH keys file (default: $HOME/.ssh/keys.txt)
  AGE_KEYSSOURCE       URL to fetch SSH keys if keys file does not exist
  AGE_LOGFILE          Path to the log file (default: $HOME/.cache/a.log)

Examples:
  Encrypt a file:
    a e file.txt

  Encrypt a directory:
    a e /path/to/directory

  Decrypt a file:
    a d file.txt.age

  Specify a custom keys file:
    AGE_KEYSFILE=/path/to/keys.txt a e file.txt

  Specify a custom keys source and log file:
    AGE_KEYSSOURCE=https://example.com/keys.txt AGE_LOGFILE=/tmp/a.log a d file.txt.age
EOF
}

# Function to print version
print_version()
{
  echo "a version $VERSION"
  echo "Created by Ismo Vuorinen <https://github.com/ivuorinen>"
}

# Function to fetch keys if missing
fetch_keys_if_missing()
{
  if [[ ! -f "$KEYS_FILE" ]]; then
    log_message "Keys file '$KEYS_FILE' not found. Attempting to fetch from $KEYS_SOURCE..."
    mkdir -p "$(dirname "$KEYS_FILE")"
    curl -s "$KEYS_SOURCE" -o "$KEYS_FILE"

    if [[ $? -ne 0 || ! -s "$KEYS_FILE" ]]; then
      log_message "Error: Failed to fetch keys from $KEYS_SOURCE"
      exit 1
    fi

    chmod 0400 "$KEYS_FILE"
    log_message "Keys file fetched and permissions set to 0400."
  fi
}

# Function to encrypt files or directories
encrypt_file_or_directory()
{
  local file="$1"
  if [[ -d "$file" ]]; then
    for f in "$file"/*; do
      encrypt_file_or_directory "$f"
    done
  elif [[ -f "$file" ]]; then
    fetch_keys_if_missing
    local output_file="${file}.age"
    age -R "$KEYS_FILE" "$file" > "$output_file"
    if [[ $? -eq 0 ]]; then
      log_message "File encrypted successfully: $output_file"
    else
      log_message "Error: Failed to encrypt file '$file'."
      exit 1
    fi
  fi
}

# Function to decrypt files or directories
decrypt_file_or_directory()
{
  local file="$1"
  if [[ -d "$file" ]]; then
    for f in "$file"/*.age; do
      decrypt_file_or_directory "$f"
    done
  elif [[ -f "$file" ]]; then
    fetch_keys_if_missing
    local output_file="${file%.age}"
    age -d -i "$KEYS_FILE" "$file" > "$output_file"
    if [[ $? -eq 0 ]]; then
      log_message "File decrypted successfully: $output_file"
    else
      log_message "Error: Failed to decrypt file '$file'."
      exit 1
    fi
  fi
}

# Main logic
case "$1" in
  e | enc | encrypt)
    if [[ $# -lt 2 ]]; then
      log_message "Error: No file or directory specified for encryption."
      print_help
      exit 1
    fi
    encrypt_file_or_directory "$2"
    ;;
  d | dec | decrypt)
    if [[ $# -lt 2 ]]; then
      log_message "Error: No file or directory specified for decryption."
      print_help
      exit 1
    fi
    decrypt_file_or_directory "$2"
    ;;
  help | --help)
    print_help
    ;;
  version | --version)
    print_version
    ;;
  *)
    log_message "Error: Unknown command '$1'"
    print_help
    exit 1
    ;;
esac

# vim: ft=bash:syn=sh:ts=2:sw=2:et:ai:nowrap
