#!/bin/bash

# ============================================================
# OpenVPN client one-shot installer for CentOS 7
# Supported OS: CentOS 7 / RHEL 7 compatible hosts
# Published by: helper.sh
# Script note: curated by helper.sh
# ============================================================

set -euo pipefail

RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'

CONFIG_DIR="/etc/openvpn/client"
CONFIG_NAME="client"
SOURCE_CONF="./client.conf"
SOURCE_LOGIN="./login.txt"
SOURCE_DNS_HELPER="./update-resolv-conf"
DNS_HELPER_PATH="/etc/openvpn/update-resolv-conf"
EPEL_GPG_KEY_URL="https://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-7"
EPEL_RELEASE_URL="https://dl.fedoraproject.org/pub/archive/epel/7/x86_64/Packages/e/epel-release-7-14.noarch.rpm"
DNS_HELPER_INSTALLED=0

info()    { echo -e "${BLUE}[INFO]${NC}  $1"; }
success() { echo -e "${GREEN}[OK]${NC}    $1"; }
warning() { echo -e "${YELLOW}[WARN]${NC}  $1"; }
error()   { echo -e "${RED}[ERROR]${NC} $1"; exit 1; }

usage() {
  cat <<'EOF'
Usage: install_openvpn_client_centos7.sh [options]

Options:
  --config-dir PATH       Install destination (default: /etc/openvpn/client)
  --config-name NAME      Systemd instance name (default: client)
  --source-conf PATH      Source client.conf path (default: ./client.conf)
  --source-login PATH     Source login.txt path (default: ./login.txt)
  --source-dns-helper     Optional local update-resolv-conf path (default: ./update-resolv-conf)
  -h, --help              Show this help message

Required local files in the current directory by default:
  ./client.conf
  ./login.txt
EOF
}

while [ $# -gt 0 ]; do
  case "$1" in
    --config-dir)
      CONFIG_DIR="$2"
      shift 2
      ;;
    --config-name)
      CONFIG_NAME="$2"
      shift 2
      ;;
    --source-conf)
      SOURCE_CONF="$2"
      shift 2
      ;;
    --source-login)
      SOURCE_LOGIN="$2"
      shift 2
      ;;
    --source-dns-helper)
      SOURCE_DNS_HELPER="$2"
      shift 2
      ;;
    -h|--help)
      usage
      exit 0
      ;;
    *)
      error "Unknown argument: $1"
      ;;
  esac
done

if [ "${EUID}" -ne 0 ]; then
  error "Run this script with root privileges: sudo bash $0"
fi

if [ ! -f "${SOURCE_CONF}" ]; then
  error "Missing ${SOURCE_CONF}. Put client.conf in the current directory before running this script."
fi

if [ ! -f "${SOURCE_LOGIN}" ]; then
  error "Missing ${SOURCE_LOGIN}. Put login.txt in the current directory before running this script."
fi

info "Checking operating system..."
. /etc/os-release
if [ "${ID:-}" != "centos" ] && [[ "${ID_LIKE:-}" != *"rhel"* ]]; then
  warning "This script was prepared for CentOS 7 style hosts. Detected: ${ID:-unknown}"
fi

if [ "${VERSION_ID%%.*}" != "7" ]; then
  warning "This script was tested for CentOS 7. Continuing on ${PRETTY_NAME:-unknown}."
else
  success "Detected system: ${PRETTY_NAME:-CentOS 7}"
fi

info "Importing EPEL GPG key..."
rpm --import "${EPEL_GPG_KEY_URL}"
success "EPEL GPG key imported"

ensure_epel_repo() {
  if rpm -q epel-release >/dev/null 2>&1; then
    success "epel-release is already installed"
    return
  fi

  info "Installing epel-release from the EPEL 7 archive ..."
  yum install -y "${EPEL_RELEASE_URL}"
  success "epel-release installed"
}

info "Ensuring the EPEL repository is available..."
ensure_epel_repo

info "Refreshing yum metadata..."
yum clean all >/dev/null 2>&1 || true
yum makecache -y >/dev/null
success "yum metadata refreshed"

if ! yum list openvpn --disablerepo='*' --enablerepo='epel' >/dev/null 2>&1; then
  error "The openvpn package is still unavailable from the EPEL repository. Check 'yum repolist all | grep epel' and mirror reachability."
fi

info "Installing OpenVPN..."
yum install -y openvpn
success "OpenVPN installed"

info "Preparing ${CONFIG_DIR} ..."
mkdir -p "${CONFIG_DIR}"

TARGET_CONF="${CONFIG_DIR}/${CONFIG_NAME}.conf"
TARGET_LOGIN="${CONFIG_DIR}/login.txt"
BACKUP_SUFFIX="$(date +%Y%m%d%H%M%S)"

ensure_line() {
  local file="$1"
  local line="$2"
  if ! grep -Fxq "$line" "$file"; then
    printf '\n%s\n' "$line" >> "$file"
  fi
}

if [ -f "${TARGET_CONF}" ]; then
  cp -f "${TARGET_CONF}" "${TARGET_CONF}.bak.${BACKUP_SUFFIX}"
  warning "Backed up existing config to ${TARGET_CONF}.bak.${BACKUP_SUFFIX}"
fi

if [ -f "${TARGET_LOGIN}" ]; then
  cp -f "${TARGET_LOGIN}" "${TARGET_LOGIN}.bak.${BACKUP_SUFFIX}"
  warning "Backed up existing login file to ${TARGET_LOGIN}.bak.${BACKUP_SUFFIX}"
fi

cp -f "${SOURCE_CONF}" "${TARGET_CONF}"
cp -f "${SOURCE_LOGIN}" "${TARGET_LOGIN}"

sed -i 's/\r$//' "${TARGET_CONF}"
sed -i 's/\r$//' "${TARGET_LOGIN}"

chmod 600 "${TARGET_CONF}"
chmod 600 "${TARGET_LOGIN}"

if ! grep -q "auth-user-pass" "${TARGET_CONF}"; then
  warning "client.conf does not contain auth-user-pass. Username/password login may not be enabled."
fi

if grep -q "auth-user-pass login.txt" "${TARGET_CONF}"; then
  success "client.conf references login.txt in the target directory"
else
  warning "client.conf does not reference 'login.txt' exactly. Confirm the auth-user-pass path manually."
fi

if [ -f "${SOURCE_DNS_HELPER}" ]; then
  info "Using local DNS helper from ${SOURCE_DNS_HELPER} ..."
  cp -f "${SOURCE_DNS_HELPER}" "${DNS_HELPER_PATH}"
  sed -i 's/\r$//' "${DNS_HELPER_PATH}"
else
  info "No local DNS helper provided. Installing bundled CentOS DNS helper ..."
  cat > "${DNS_HELPER_PATH}" <<'EOF'
#!/bin/bash
# OpenVPN DNS switch helper for CentOS 7
set -euo pipefail

LOG_FILE="/var/log/openvpn-dns-update.log"
VPN_DNS_PRIMARY="${VPN_DNS_PRIMARY:-10.7.7.53}"
VPN_DNS_FALLBACK="${VPN_DNS_FALLBACK:-114.114.114.114}"
VPN_SEARCH_DOMAIN="${VPN_SEARCH_DOMAIN:-reshub.cn}"

mkdir -p "$(dirname "${LOG_FILE}")"
exec >> "${LOG_FILE}" 2>&1

timestamp() {
  date '+%Y-%m-%d %H:%M:%S'
}

case "${script_type:-}" in
  up)
    echo "[$(timestamp)] [INFO] VPN connected - Updating /etc/resolv.conf"
    cat > /etc/resolv.conf <<EODNS
# Generated by OpenVPN
nameserver ${VPN_DNS_PRIMARY}
nameserver ${VPN_DNS_FALLBACK}
search ${VPN_SEARCH_DOMAIN}
EODNS
    ;;
  down)
    echo "[$(timestamp)] [INFO] VPN disconnected - Restoring default DNS"
    cat > /etc/resolv.conf <<EODNS
# Restored default DNS
nameserver ${VPN_DNS_FALLBACK}
EODNS
    ;;
  *)
    echo "[$(timestamp)] [WARN] Unknown script type: ${script_type:-unset}"
    ;;
esac
EOF
fi

chmod +x "${DNS_HELPER_PATH}"
DNS_HELPER_INSTALLED=1
success "DNS helper installed to ${DNS_HELPER_PATH}"

info "Ensuring DNS helper hooks exist in ${TARGET_CONF} ..."
ensure_line "${TARGET_CONF}" "script-security 2"
ensure_line "${TARGET_CONF}" "up ${DNS_HELPER_PATH}"
ensure_line "${TARGET_CONF}" "down ${DNS_HELPER_PATH}"
success "OpenVPN DNS helper hooks updated"

SERVICE_NAME="openvpn-client@${CONFIG_NAME}"

info "Enabling ${SERVICE_NAME} ..."
systemctl enable "${SERVICE_NAME}" >/dev/null

info "Starting ${SERVICE_NAME} ..."
systemctl restart "${SERVICE_NAME}"
sleep 3

if systemctl is-active --quiet "${SERVICE_NAME}"; then
  success "${SERVICE_NAME} is active"
else
  warning "${SERVICE_NAME} is not active yet. Review: journalctl -u ${SERVICE_NAME} -n 100 --no-pager"
fi

echo ""
echo -e "${GREEN}============================================================${NC}"
echo -e "${GREEN} OpenVPN client installation completed                       ${NC}"
echo -e "${GREEN}============================================================${NC}"
echo ""
echo -e "  ${BLUE}Installed config:${NC} ${TARGET_CONF}"
echo -e "  ${BLUE}Credentials file:${NC} ${TARGET_LOGIN}"
echo -e "  ${BLUE}Service name:${NC}     ${SERVICE_NAME}"
if [ "${DNS_HELPER_INSTALLED}" -eq 1 ]; then
  echo -e "  ${BLUE}DNS helper:${NC}       ${DNS_HELPER_PATH}"
fi
echo ""
echo -e "  ${YELLOW}Useful commands:${NC}"
echo -e "    systemctl status ${SERVICE_NAME}"
echo -e "    journalctl -u ${SERVICE_NAME} -n 100 --no-pager"
echo -e "    ip addr show tun0"
echo -e "    curl ipinfo.im"
echo -e "    cat /etc/resolv.conf"
echo ""
echo -e "  ${YELLOW}Optional config notes:${NC}"
echo -e "    route-nopull"
echo -e "    route 10.7.0.0 255.255.0.0"
echo -e "    route 10.2.0.0 255.255.0.0"
echo -e "    route 192.168.1.0 255.255.255.0"
echo -e "    crontab: 0 5 * * * /usr/bin/systemctl restart ${SERVICE_NAME}"
echo ""
