#!/usr/bin/env bash

set -euo pipefail

SCRIPT_NAME="$(basename "$0")"

RED="$(printf '\033[0;31m')"
GREEN="$(printf '\033[0;32m')"
YELLOW="$(printf '\033[1;33m')"
BLUE="$(printf '\033[0;34m')"
NC="$(printf '\033[0m')"

NAMESPACE="cubbit"
CERT_FILE=""
KEY_FILE=""
ORG_SLUG_NAME=""
TENANT_SLUG_NAME=""
STD_HOSTNAME=""

usage() {
  cat <<EOF
Compute the TLS secret name expected by a v3 "manual" tenant and print the
kubectl command to create it - it does not run kubectl itself.

Usage:
  ${SCRIPT_NAME} [options]

Options:
  --namespace <name>       Namespace the tenant/secret lives in (default: cubbit)
  --cert <path>            Path to the TLS certificate file (required, PEM format - .pem .crt .cert all accepted)
  --key <path>             Path to the TLS key file (required, PEM format - .pem .key all accepted)
  --org-slug-name <name>   organizationName (the org's slug), used with --tenant-slug-name/--std-hostname to derive the secret name (required)
  --tenant-slug-name <name> tenantName (the tenant's slug), used with --org-slug-name/--std-hostname to derive the secret name (required)
  --std-hostname <value>   stdHostname, used with --org-slug-name/--tenant-slug-name to derive the secret name (required)
  --help                   Show this help.

Examples:
  # With .crt/.key files (e.g. self-signed certs)
  ${SCRIPT_NAME} --namespace my-tenant-ns --cert tls.crt --key tls.key \\
      --org-slug-name my-org --tenant-slug-name mytenant --std-hostname s3.mytenant.myorg.com

  # With certbot .pem files
  ${SCRIPT_NAME} --cert /etc/letsencrypt/live/example/fullchain.pem \\
      --key /etc/letsencrypt/live/example/privkey.pem \\
      --org-slug-name my-org --tenant-slug-name mytenant --std-hostname mydomain.com

  # Interactive mode (prompts for each value)
  ${SCRIPT_NAME}
EOF
}

print_status() {
  printf '%b[INFO]%b %s\n' "${BLUE}" "${NC}" "$1"
}

print_success() {
  printf '%b[SUCCESS]%b %s\n' "${GREEN}" "${NC}" "$1"
}

print_warning() {
  printf '%b[WARNING]%b %s\n' "${YELLOW}" "${NC}" "$1" >&2
}

print_error() {
  printf '%b[ERROR]%b %s\n' "${RED}" "${NC}" "$1" >&2
}

fail() {
  print_error "$*"
  exit 1
}

# ensure that an option value is provided
require_option_value() {
  local option_name="$1"
  [[ $# -ge 2 && -n "${2-}" ]] || fail "missing value for ${option_name}"
}

parse_args() {
  while [[ $# -gt 0 ]]; do
    case "$1" in
      --namespace)
        require_option_value "$1" "${2-}"
        NAMESPACE="${2-}"
        shift 2
        ;;
      --cert)
        require_option_value "$1" "${2-}"
        CERT_FILE="${2-}"
        shift 2
        ;;
      --key)
        require_option_value "$1" "${2-}"
        KEY_FILE="${2-}"
        shift 2
        ;;
      --org-slug-name)
        require_option_value "$1" "${2-}"
        ORG_SLUG_NAME="${2-}"
        shift 2
        ;;
      --tenant-slug-name)
        require_option_value "$1" "${2-}"
        TENANT_SLUG_NAME="${2-}"
        shift 2
        ;;
      --std-hostname)
        require_option_value "$1" "${2-}"
        STD_HOSTNAME="${2-}"
        shift 2
        ;;
      --help)
        usage
        exit 0
        ;;
      *)
        fail "unknown argument: $1"
        ;;
    esac
  done
}

interactive_mode() {
  print_status "Interactive mode - press Enter to accept the default (shown in brackets)"
  echo

  # trim a value: read strips leading/trailing IFS whitespace by default
  trim() { read -r var <<< "$1"; printf '%s' "$var"; }

  local input
  read -r -p "  Namespace [${NAMESPACE}]: " input
  input="$(trim "$input")"
  [[ -n "$input" ]] && NAMESPACE="$input"

  read -r -p "  Path to TLS certificate file (PEM format): " input
  input="$(trim "$input")"
  while [[ -z "$input" ]]; do
    read -r -p "  Path to TLS certificate file (required): " input
    input="$(trim "$input")"
  done
  CERT_FILE="$input"

  read -r -p "  Path to TLS key file (PEM format): " input
  input="$(trim "$input")"
  while [[ -z "$input" ]]; do
    read -r -p "  Path to TLS key file (required): " input
    input="$(trim "$input")"
  done
  KEY_FILE="$input"

  read -r -p "  Organization slug name: " input
  input="$(trim "$input")"
  while [[ -z "$input" ]]; do
    read -r -p "  Organization slug name (required): " input
    input="$(trim "$input")"
  done
  ORG_SLUG_NAME="$input"

  read -r -p "  Tenant slug name: " input
  input="$(trim "$input")"
  while [[ -z "$input" ]]; do
    read -r -p "  Tenant slug name (required): " input
    input="$(trim "$input")"
  done
  TENANT_SLUG_NAME="$input"

  read -r -p "  stdHostname: " input
  input="$(trim "$input")"
  while [[ -z "$input" ]]; do
    read -r -p "  stdHostname (required): " input
    input="$(trim "$input")"
  done
  STD_HOSTNAME="$input"

  echo
}

validate_input() {
  [[ -n "$CERT_FILE" ]] || fail "--cert is required"
  [[ -n "$KEY_FILE" ]] || fail "--key is required"
  [[ -n "$ORG_SLUG_NAME" ]] || fail "--org-slug-name is required"
  [[ -n "$TENANT_SLUG_NAME" ]] || fail "--tenant-slug-name is required"
  [[ -n "$STD_HOSTNAME" ]] || fail "--std-hostname is required"
  [[ -f "$CERT_FILE" ]] || fail "cert file not found: $CERT_FILE"
  [[ -f "$KEY_FILE" ]] || fail "key file not found: $KEY_FILE"
}

compute_secret_name() {
  local hash=""

  if command -v sha256sum >/dev/null 2>&1; then
    hash="$(printf '%s' "$STD_HOSTNAME" | sha256sum | cut -c1-16)"
  else
    # macOS has no sha256sum by default
    hash="$(printf '%s' "$STD_HOSTNAME" | shasum -a 256 | cut -c1-16)"
  fi

  printf '%s.%s.%s' "$ORG_SLUG_NAME" "$TENANT_SLUG_NAME" "$hash"
}

main() {
  if [[ $# -eq 0 ]]; then
    interactive_mode
  else
    parse_args "$@"
  fi
  validate_input

  local secret_name=""
  secret_name="$(compute_secret_name)"

  print_status "Derived secret name: $secret_name (from organizationName=$ORG_SLUG_NAME tenantName=$TENANT_SLUG_NAME stdHostname=$STD_HOSTNAME)"

  print_success "Run this to create the TLS secret:"
  echo
  echo "  kubectl -n $NAMESPACE create secret tls $secret_name \\"
  echo "    --cert=$CERT_FILE \\"
  echo "    --key=$KEY_FILE"
}

main "$@"
