#!/usr/bin/env bash
# ==============================================================================
# Elastic Stack Certificate Exchange Command Proposer & Wrapper
# ==============================================================================
# Universal shell script that parses configuration files for Elasticsearch and
# Kibana, extracts SSL certificate target paths, SANs, and endpoints, and proposes
# the exact command to run scripts/update-certs.sh.
# ==============================================================================

set -euo pipefail

# Color & formatting definitions
BOLD_CYAN='\033[1;36m'
BOLD_BLUE='\033[1;34m'
BOLD_GREEN='\033[1;32m'
BOLD_YELLOW='\033[1;33m'
BOLD_RED='\033[1;31m'
CYAN='\033[0;36m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
DIM='\033[2m'
BOLD='\033[1m'
RESET='\033[0m'

# Default paths
ES_CONFIG_PATH="/etc/elasticsearch/elasticsearch.yml"
KIBANA_CONFIG_PATH="/etc/kibana/kibana.yml"
EXECUTE_CMD=false

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PYTHON_SCRIPT="$SCRIPT_DIR/propose-cert-exchange.py"

if command -v python3 >/dev/null 2>&1 && [ -f "$PYTHON_SCRIPT" ]; then
  exec python3 "$PYTHON_SCRIPT" "$@"
fi
UPDATE_SCRIPT="$SCRIPT_DIR/update-certs.sh"

# Usage information
show_usage() {
  cat << EOF
Usage: $(basename "$0") [OPTIONS]

Options:
  --es-config PATH       Path to elasticsearch.yml (default: /etc/elasticsearch/elasticsearch.yml)
  --kibana-config PATH   Path to kibana.yml (default: /etc/kibana/kibana.yml)
  --script-path PATH     Path to update-certs.sh (default: $UPDATE_SCRIPT)
  -e, --execute          Run the proposed certificate update command with sudo
  -h, --help             Show this help message

EOF
  exit 0
}

# Parse command line arguments
while [[ $# -gt 0 ]]; do
  case "$1" in
    --es-config)
      ES_CONFIG_PATH="$2"
      shift 2
      ;;
    --kibana-config)
      KIBANA_CONFIG_PATH="$2"
      shift 2
      ;;
    --script-path)
      UPDATE_SCRIPT="$2"
      shift 2
      ;;
    -e|--execute)
      EXECUTE_CMD=true
      shift
      ;;
    -h|--help)
      show_usage
      ;;
    *)
      echo -e "${BOLD_RED}Unknown option: $1${RESET}" >&2
      show_usage
      ;;
  esac
done

# YAML helper: extracts key value ignoring comments and quotes
parse_yaml_key() {
  local file="$1"
  local key="$2"
  local default_val="$3"

  if [ ! -f "$file" ]; then
    echo "$default_val"
    return
  fi

  local val
  val=$(grep -E "^\s*${key}:" "$file" 2>/dev/null | head -n 1 | sed -e 's/^\s*[^:]*:[[:space:]]*//' -e 's/[[:space:]]*$//' -e 's/^["'\'']//' -e 's/["'\'']$//' -e 's/[\[\]]//g' || true)
  if [ -n "$val" ]; then
    echo "$val"
  else
    echo "$default_val"
  fi
}

# Network SAN discovery
discover_sans() {
  local dns_list=("localhost")
  local ip_list=("127.0.0.1")

  if command -v hostname &>/dev/null; then
    local h
    h=$(hostname 2>/dev/null || true)
    [ -n "$h" ] && dns_list+=("$h")
    local fqdn
    fqdn=$(hostname -f 2>/dev/null || true)
    [ -n "$fqdn" ] && dns_list+=("$fqdn")
  fi

  if command -v hostname &>/dev/null && hostname -I &>/dev/null; then
    for ip in $(hostname -I 2>/dev/null); do
      [[ "$ip" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]] && ip_list+=("$ip")
    done
  elif command -v ip &>/dev/null; then
    for ip in $(ip -4 addr show 2>/dev/null | grep -oP 'inet \K[\d.]+'); do
      ip_list+=("$ip")
    done
  fi

  # Baseline fallbacks matching update-certs.sh defaults
  dns_list+=("cmsrv2024" "siem2024")
  ip_list+=("10.1.10.3" "192.168.196.95")

  # Deduplicate SAN lists
  UNIQUE_DNS=$(printf "%s\n" "${dns_list[@]}" | sort -u | tr '\n' ' ' | xargs)
  UNIQUE_IPS=$(printf "%s\n" "${ip_list[@]}" | sort -u | tr '\n' ' ' | xargs)
}

# Extraction logic
ES_FOUND=false
[ -f "$ES_CONFIG_PATH" ] && ES_FOUND=true

KIBANA_FOUND=false
[ -f "$KIBANA_CONFIG_PATH" ] && KIBANA_FOUND=true

ES_HTTP_P12=$(parse_yaml_key "$ES_CONFIG_PATH" "xpack.security.http.ssl.keystore.path" "/etc/elasticsearch/certs/http.p12")
ES_TRANSPORT_P12=$(parse_yaml_key "$ES_CONFIG_PATH" "xpack.security.transport.ssl.keystore.path" "/etc/elasticsearch/certs/transport.p12")
ES_HTTP_CA=$(parse_yaml_key "$ES_CONFIG_PATH" "xpack.security.http.ssl.certificate_authorities" "/etc/elasticsearch/certs/http_ca.crt")

KIBANA_CRT=$(parse_yaml_key "$KIBANA_CONFIG_PATH" "server.ssl.certificate" "/etc/kibana/certs/kibana.crt")
KIBANA_KEY=$(parse_yaml_key "$KIBANA_CONFIG_PATH" "server.ssl.key" "/etc/kibana/certs/kibana.key")
KIBANA_CA=$(parse_yaml_key "$KIBANA_CONFIG_PATH" "elasticsearch.ssl.certificateAuthorities" "/var/lib/kibana/ca_1721297493415.crt")

FLEET_ES_URL=$(parse_yaml_key "$KIBANA_CONFIG_PATH" "elasticsearch.hosts" "https://10.1.10.3:9200")
FLEET_SERVER_URL=$(parse_yaml_key "$KIBANA_CONFIG_PATH" "fleet.agent.fleet_server.hosts" "https://10.1.10.3:8220")

discover_sans

# Build environment overrides string
ENV_EXPORTS=""
[ "$ES_HTTP_P12" != "/etc/elasticsearch/certs/http.p12" ] && ENV_EXPORTS+="ES_HTTP_P12_TARGET=\"$ES_HTTP_P12\" "
[ "$ES_TRANSPORT_P12" != "/etc/elasticsearch/certs/transport.p12" ] && ENV_EXPORTS+="ES_TRANSPORT_P12_TARGET=\"$ES_TRANSPORT_P12\" "
[ "$ES_HTTP_CA" != "/etc/elasticsearch/certs/http_ca.crt" ] && ENV_EXPORTS+="ES_HTTP_CA_TARGET=\"$ES_HTTP_CA\" "

[ "$KIBANA_CRT" != "/etc/kibana/certs/kibana.crt" ] && ENV_EXPORTS+="KIBANA_CRT_TARGET=\"$KIBANA_CRT\" "
[ "$KIBANA_KEY" != "/etc/kibana/certs/kibana.key" ] && ENV_EXPORTS+="KIBANA_KEY_TARGET=\"$KIBANA_KEY\" "
[ "$KIBANA_CA" != "/var/lib/kibana/ca_1721297493415.crt" ] && ENV_EXPORTS+="KIBANA_CA_TARGET=\"$KIBANA_CA\" "

ENV_EXPORTS+="FLEET_SERVER_ES_URL=\"$FLEET_ES_URL\" "
ENV_EXPORTS+="FLEET_SERVER_URL=\"$FLEET_SERVER_URL\" "
ENV_EXPORTS+="SAN_DNS=\"$UNIQUE_DNS\" "
ENV_EXPORTS+="SAN_IPS=\"$UNIQUE_IPS\" "

PROPOSED_COMMAND="sudo $ENV_EXPORTS$UPDATE_SCRIPT"

# Header
echo -e "\n${BOLD_CYAN}====================================================${RESET}"
echo -e " ${BOLD_BLUE}Elastic Stack Certificate Exchange Proposer${RESET}"
echo -e "${BOLD_CYAN}====================================================${RESET}\n"

echo -e "${BOLD_CYAN}[1] Config File Discovery:${RESET}"
if [ "$ES_FOUND" = true ]; then
  echo -e "    ${CYAN}↳${RESET} Elasticsearch: ${BOLD_GREEN}Found${RESET} ($ES_CONFIG_PATH)"
else
  echo -e "    ${CYAN}↳${RESET} Elasticsearch: ${YELLOW}Not found${RESET} ($ES_CONFIG_PATH) - using default paths"
fi

if [ "$KIBANA_FOUND" = true ]; then
  echo -e "    ${CYAN}↳${RESET} Kibana:        ${BOLD_GREEN}Found${RESET} ($KIBANA_CONFIG_PATH)"
else
  echo -e "    ${CYAN}↳${RESET} Kibana:        ${YELLOW}Not found${RESET} ($KIBANA_CONFIG_PATH) - using default paths"
fi

echo -e "\n${BOLD_CYAN}[2] Discovered SSL Targets & Endpoints:${RESET}"
echo -e "    ${CYAN}↳${RESET} Elasticsearch HTTP P12:      ${BOLD}$ES_HTTP_P12${RESET}"
echo -e "    ${CYAN}↳${RESET} Elasticsearch Transport P12: ${BOLD}$ES_TRANSPORT_P12${RESET}"
echo -e "    ${CYAN}↳${RESET} Elasticsearch HTTP CA:       ${BOLD}$ES_HTTP_CA${RESET}"
echo -e "    ${CYAN}↳${RESET} Kibana Certificate:          ${BOLD}$KIBANA_CRT${RESET}"
echo -e "    ${CYAN}↳${RESET} Kibana Private Key:          ${BOLD}$KIBANA_KEY${RESET}"
echo -e "    ${CYAN}↳${RESET} Kibana CA Target:            ${BOLD}$KIBANA_CA${RESET}"
echo -e "    ${CYAN}↳${RESET} Fleet Elasticsearch URL:     ${BOLD}$FLEET_ES_URL${RESET}"
echo -e "    ${CYAN}↳${RESET} Fleet Server URL:            ${BOLD}$FLEET_SERVER_URL${RESET}"

echo -e "\n${BOLD_CYAN}[3] Discovered SAN Entries:${RESET}"
echo -e "    ${CYAN}↳${RESET} DNS Names: ${GREEN}$UNIQUE_DNS${RESET}"
echo -e "    ${CYAN}↳${RESET} IP Addrs:  ${GREEN}$UNIQUE_IPS${RESET}"

echo -e "\n${BOLD_CYAN}====================================================${RESET}"
echo -e " ${BOLD_GREEN}PROPOSED COMMAND TO EXCHANGE CERTIFICATES:${RESET}"
echo -e "${BOLD_CYAN}====================================================${RESET}"
echo -e "\n  ${BOLD_YELLOW}$PROPOSED_COMMAND${RESET}\n"

if [ "$EXECUTE_CMD" = true ]; then
  if [ ! -f "$UPDATE_SCRIPT" ]; then
    echo -e "${BOLD_RED}Error: Update script $UPDATE_SCRIPT does not exist.${RESET}" >&2
    exit 1
  fi
  echo -e "${BOLD_GREEN}Executing proposed command with sudo...${RESET}\n"
  eval "$PROPOSED_COMMAND"
fi
