#!/bin/bash

# OpenVPN 服务器一键安装脚本 (香港服务器优化版)
# 基于 Nyr 开源项目: https://github.com/Nyr/openvpn-install

# 脚本颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

# 错误处理函数
error_exit() {
    echo -e "${RED}[错误] $1${NC}" 1>&2
    exit 1
}

# 信息输出函数
info() {
    echo -e "${BLUE}[信息] $1${NC}"
}

success() {
    echo -e "${GREEN}[成功] $1${NC}"
}

warning() {
    echo -e "${YELLOW}[警告] $1${NC}"
}

# 检查root权限
check_root() {
    if [[ $EUID -ne 0 ]]; then
        error_exit "本脚本必须以root权限运行。请使用 'sudo bash $0'"
    fi
}

# 检查系统兼容性
check_os() {
    if [[ -f /etc/os-release ]]; then
        . /etc/os-release
        OS=$NAME
        VER=$VERSION_ID
    else
        error_exit "无法检测操作系统版本"
    fi

    # 支持的系统列表
    case $ID in
        ubuntu|debian|centos|fedora|arch)
            info "检测到操作系统: $OS $VER"
            ;;
        *)
            warning "未经全面测试的操作系统: $OS $VER，继续执行可能存在问题"
            read -p "是否继续? [y/N]: " -e CONTINUE
            if [[ $CONTINUE =~ ^[Yy]$ ]]; then
                info "继续安装..."
            else
                info "安装已取消"
                exit 0
            fi
            ;;
    esac
}

# 安装必要依赖
install_dependencies() {
    info "安装系统必要依赖包..."

    if command -v apt-get >/dev/null 2>&1; then
        # Debian/Ubuntu
        apt-get update || error_exit "apt-get update 失败"
        apt-get install -y curl openvpn easy-rsa || error_exit "安装依赖包失败"
    elif command -v yum >/dev/null 2>&1; then
        # CentOS/RHEL
        yum install -y curl openvpn easy-rsa || error_exit "安装依赖包失败"
    elif command -v dnf >/dev/null 2>&1; then
        # Fedora
        dnf install -y curl openvpn easy-rsa || error_exit "安装依赖包失败"
    elif command -v pacman >/dev/null 2>&1; then
        # Arch Linux
        pacman -Sy --noconfirm curl openvpn easy-rsa || error_exit "安装依赖包失败"
    else
        error_exit "不支持的包管理器"
    fi

    success "系统依赖包安装完成"
}

# 获取公网IP
get_public_ip() {
    info "正在检测服务器公网IP地址..."
    
    # 尝试多个IP检测服务
    IP_SERVERS=(
        "ifconfig.me"
        "ipinfo.io/ip"
        "icanhazip.com"
        "api.ipify.org"
    )
    
    for server in "${IP_SERVERS[@]}"; do
        PUBLIC_IP=$(curl -s --connect-timeout 5 $server)
        if [[ -n $PUBLIC_IP && $PUBLIC_IP =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
            success "检测到的服务器公网IP地址为: $PUBLIC_IP"
            return 0
        fi
    done
    
    warning "无法自动获取公网IP，请手动输入"
    read -p "请输入服务器公网IP地址或域名: " PUBLIC_IP
    if [[ -z $PUBLIC_IP ]]; then
        error_exit "必须提供公网IP地址或域名"
    fi
}

# 配置参数设置
configure_parameters() {
    echo
    info "开始配置OpenVPN服务器参数"
    
    # 选择协议
    echo
    echo "请选择OpenVPN使用的协议:"
    echo "  1) UDP (默认推荐，速度更快)"
    echo "  2) TCP (穿透性更好，适用于受限网络)"
    read -p "协议 [1]: " PROTO_CHOICE
    case $PROTO_CHOICE in
        2) 
            PROTOCOL="tcp"
            DEFAULT_PORT="443"
            ;;
        *) 
            PROTOCOL="udp" 
            DEFAULT_PORT="1194"
            ;;
    esac

    # 设置端口
    read -p "请输入监听端口 [$DEFAULT_PORT]: " PORT
    PORT=${PORT:-$DEFAULT_PORT}

    # 选择DNS
    echo
    echo "请为VPN客户端选择一个DNS服务器:"
    echo "  1) Cloudflare (1.1.1.1, 1.0.0.1) - 推荐"
    echo "  2) Google (8.8.8.8, 8.8.4.4)"
    echo "  3) OpenDNS (208.67.222.222, 208.67.220.220)"
    echo "  4) Quad9 (9.9.9.9, 149.112.112.112)"
    echo "  5) 系统本地DNS"
    read -p "DNS选择 [1]: " DNS_CHOICE
    case $DNS_CHOICE in
        2) DNS_SERVERS="8.8.8.8,8.8.4.4" ;;
        3) DNS_SERVERS="208.67.222.222,208.67.220.220" ;;
        4) DNS_SERVERS="9.9.9.9,149.112.112.112" ;;
        5) DNS_SERVERS="system" ;;
        *) DNS_SERVERS="1.1.1.1,1.0.0.1" ;;
    esac

    # 设置客户端名称
    read -p "请输入第一个客户端的名称 [client]: " CLIENT_NAME
    CLIENT_NAME=${CLIENT_NAME:-client}

    # 数据加密设置
    echo
    echo "选择数据加密算法:"
    echo "  1) AES-256-GCM (推荐，硬件加速)"
    echo "  2) AES-256-CBC"
    echo "  3) AES-128-GCM"
    read -p "加密算法 [1]: " ENCRYPT_CHOICE
    case $ENCRYPT_CHOICE in
        2) CIPHER="AES-256-CBC" ;;
        3) CIPHER="AES-128-GCM" ;;
        *) CIPHER="AES-256-GCM" ;;
    esac
}

# 显示配置摘要
show_config_summary() {
    echo
    echo "=================================================="
    echo "            OpenVPN 配置摘要"
    echo "=================================================="
    echo "服务器地址: $PUBLIC_IP"
    echo "网络协议: $PROTOCOL"
    echo "端口: $PORT"
    echo "DNS: $DNS_SERVERS"
    echo "加密算法: $CIPHER"
    echo "客户端配置: $CLIENT_NAME.ovpn"
    echo "=================================================="
    echo
    read -p "请确认配置是否正确? [Y/n]: " -e CONFIRM
    if [[ $CONFIRM =~ ^[Nn]$ ]]; then
        info "安装已取消"
        exit 0
    fi
}

# 下载并运行安装脚本
run_openvpn_install() {
    info "下载OpenVPN安装脚本..."
    
    # 下载官方安装脚本
    wget https://raw.githubusercontent.com/Nyr/openvpn-install/master/openvpn-install.sh -O /tmp/openvpn-install.sh || error_exit "下载安装脚本失败"
    
    chmod +x /tmp/openvpn-install.sh || error_exit "设置脚本执行权限失败"
    
    # 创建自动应答配置
    cat > /tmp/ovpn_answers << EOF
$PUBLIC_IP
$PORT
$PROTOCOL
$DNS_SERVERS
$CLIENT_NAME
EOF

    # 运行安装脚本（使用预配置的答案）
    info "开始安装OpenVPN服务器..."
    cat /tmp/ovpn_answers | /tmp/openvpn-install.sh || error_exit "OpenVPN安装失败"
}

# 配置优化
optimize_config() {
    info "优化OpenVPN服务器配置..."
    
    OVPN_CONFIG="/etc/openvpn/server.conf"
    
    if [[ -f $OVPN_CONFIG ]]; then
        # 备份原始配置
        cp $OVPN_CONFIG $OVPN_CONFIG.backup
        
        # 添加性能优化参数
        echo "" >> $OVPN_CONFIG
        echo "# 性能优化配置" >> $OVPN_CONFIG
        echo "cipher $CIPHER" >> $OVPN_CONFIG
        echo "auth SHA256" >> $OVPN_CONFIG
        echo "key-direction 0" >> $OVPN_CONFIG
        echo "tls-version-min 1.2" >> $OVPN_CONFIG
        
        # 针对香港服务器的优化
        echo "sndbuf 393216" >> $OVPN_CONFIG
        echo "rcvbuf 393216" >> $OVPN_CONFIG
        echo "push \"sndbuf 393216\"" >> $OVPN_CONFIG
        echo "push \"rcvbuf 393216\"" >> $OVPN_CONFIG
        
        success "OpenVPN配置优化完成"
    else
        warning "未找到OpenVPN配置文件，跳过优化步骤"
    fi
}

# 防火墙配置
configure_firewall() {
    info "配置防火墙规则..."
    
    if command -v ufw >/dev/null 2>&1; then
        # UFW防火墙
        ufw allow $PORT/$PROTOCOL || warning "UFW防火墙配置失败"
        success "UFW防火墙已配置允许 $PORT/$PROTOCOL"
    elif command -v firewall-cmd >/dev/null 2>&1; then
        # firewalld
        firewall-cmd --permanent --add-port=$PORT/$PROTOCOL || warning "firewalld配置失败"
        firewall-cmd --reload || warning "firewalld重载失败"
        success "firewalld已配置允许 $PORT/$PROTOCOL"
    elif command -v iptables >/dev/null 2>&1; then
        # iptables
        iptables -I INPUT -p $PROTOCOL --dport $PORT -j ACCEPT || warning "iptables配置失败"
        success "iptables已配置允许 $PORT/$PROTOCOL"
        
        # 尝试保存iptables规则
        if command -v iptables-save >/dev/null 2>&1; then
            iptables-save > /etc/iptables.rules 2>/dev/null || warning "iptables规则保存失败"
        fi
    else
        warning "未检测到支持的防火墙，请手动开放端口: $PORT/$PROTOCOL"
    fi
}

# 显示安装结果
show_installation_result() {
    echo
    echo "=================================================="
    success "        OpenVPN 服务器安装完成！"
    echo "=================================================="
    echo "服务器配置:"
    echo "  ▪ 服务器地址: $PUBLIC_IP"
    echo "  ▪ 连接端口: $PORT"
    echo "  ▪ 传输协议: $PROTOCOL"
    echo "  ▪ 加密算法: $CIPHER"
    echo ""
    echo "客户端配置:"
    echo "  ▪ 配置文件: /root/$CLIENT_NAME.ovpn"
    echo "  ▪ 客户端名称: $CLIENT_NAME"
    echo ""
    echo "管理命令:"
    echo "  ▪ 添加用户: openvpn-install.sh"
    echo "  ▪ 服务状态: systemctl status openvpn-server@server"
    echo "  ▪ 重启服务: systemctl restart openvpn-server@server"
    echo "=================================================="
    
    # 显示客户端文件路径
    CLIENT_FILE="/root/$CLIENT_NAME.ovpn"
    if [[ -f $CLIENT_FILE ]]; then
        echo
        info "客户端配置文件位置: $CLIENT_FILE"
        echo "请将此文件安全地下载到您的客户端设备。"
    fi
}

# 主执行函数
main() {
    clear
    echo "=================================================="
    echo "   OpenVPN 服务端一键安装脚本 (香港优化版)"
    echo "=================================================="
    echo ""
    
    # 执行安装步骤
    check_root
    check_os
    install_dependencies
    get_public_ip
    configure_parameters
    show_config_summary
    run_openvpn_install
    optimize_config
    configure_firewall
    show_installation_result
}

# 脚本入口点
main "$@"