#!/bin/bash
# ==============================================================================
# Guest Agent In-VM Setup Script
# ==============================================================================
# 功能:在虚拟机镜像内部执行 guest_agent 的安装和配置
# 调用方式:由 inject_guest_agent.sh 通过 virt-customize 的 run 指令调用
#
# 参数:
#   $1 - INSTALL_DIR        安装目录 (如 /opt/virtcca/guest_agent)
#   $2 - SSL_ENABLED        是否启用 SSL (true/false)
#   $3 - SSL_CERT_PATH      SSL 证书路径 (虚机内路径)
#   $4 - SSL_KEY_PATH       SSL 私钥路径 (虚机内路径)
#   $5 - SSL_CA_CERT_PATH   SSL CA 证书路径 (虚机内路径, 可选)
# ==============================================================================

set -euo pipefail

# ==============================================================================
# 全局变量
# ==============================================================================
INSTALL_DIR="${1:?Error: INSTALL_DIR is required}"
SSL_ENABLED="${2:-true}"
SSL_CERT_PATH="${3:-}"
SSL_KEY_PATH="${4:-}"
SSL_CA_CERT_PATH="${5:-}"

GA_USER="virtcca-ga"
GA_GROUP="virtcca-ga"
NETWORK_SCRIPTS_DIR="/etc/sysconfig/network-scripts"
MONITOR_LOG_DIR="/var/log/virtcca/monitor"
MONITOR_CACHE_DIR="/tmp/monitor_cache"
SSL_CERT_DIR="/etc/virtcca_deploy/cert"
IFCFG_TEMPLATE_DIR="/etc/virtcca_deploy"

SCRIPT_PID=$$
START_TIME=$(date +%s)
START_TIME_HUMAN=$(date '+%Y-%m-%d %H:%M:%S')
ERROR_COUNT=0
WARN_COUNT=0

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

# ==============================================================================
# 结构化日志函数
# ==============================================================================
log() {
    local level="$1"
    local module="$2"
    shift 2
    local msg="$*"
    local ts
    ts=$(date '+%Y-%m-%d %H:%M:%S')
    local log_line="[${ts}] [${level}] [${module}] [PID:${SCRIPT_PID}] ${msg}"

    case "$level" in
        INFO)  echo -e "${GREEN}${log_line}${NC}" ;;
        WARN)  echo -e "${YELLOW}${log_line}${NC}"; ((WARN_COUNT++)) || true ;;
        ERROR) echo -e "${RED}${log_line}${NC}"; ((ERROR_COUNT++)) || true ;;
        DEBUG) echo -e "${CYAN}${log_line}${NC}" ;;
        STEP)  echo -e "${BLUE}--- ${log_line} ---${NC}" ;;
    esac
}

log_info()  { log "INFO"  "$1" "$2"; }
log_warn()  { log "WARN"  "$1" "$2"; }
log_error() { log "ERROR" "$1" "$2"; }
log_debug() { log "DEBUG" "$1" "$2"; }
log_step()  { log "STEP"  "$1" "$2"; }

die() {
    local msg="${1:-Unknown error}"
    local module="${2:-SETUP}"
    log_error "$module" "$msg"
    log_error "$module" "Setup failed after $(( $(date +%s) - START_TIME ))s"
    exit 1
}

# ==============================================================================
# 步骤 1: 初始化
# ==============================================================================
step1_init() {
    log_step "INIT" "Step 1/9: Initializing"
    log_info "INIT" "=========================================="
    log_info "INIT" "Guest Agent In-VM Setup Starting"
    log_info "INIT" "=========================================="
    log_info "INIT" "Start time: $START_TIME_HUMAN"
    log_info "INIT" "Process ID: $SCRIPT_PID"
    log_info "INIT" "Parameters:"
    log_info "INIT" "  INSTALL_DIR=$INSTALL_DIR"
    log_info "INIT" "  SSL_ENABLED=$SSL_ENABLED"
    log_info "INIT" "  SSL_CERT_PATH=${SSL_CERT_PATH:-<not set>}"
    log_info "INIT" "  SSL_KEY_PATH=${SSL_KEY_PATH:-<not set>}"
    log_info "INIT" "  SSL_CA_CERT_PATH=${SSL_CA_CERT_PATH:-<not set>}"
    log_info "INIT" "  GA_USER=$GA_USER"
    log_info "INIT" "  GA_GROUP=$GA_GROUP"
}

# ==============================================================================
# 步骤 2: 安装系统依赖
# ==============================================================================
step2_install_dependencies() {
    log_step "DEPS" "Step 2/9: Installing system dependencies"

    local required_packages=("python3" "python3-devel" "python3-pip" "hostname" "sudo")

    log_info "DEPS" "Installing packages: ${required_packages[*]}"

    if yum install -y "${required_packages[@]}" 2>&1; then
        log_info "DEPS" "All dependencies installed successfully"
    else
        die "DEPS" "Failed to install packages: ${required_packages[*]}"
    fi
}

# ==============================================================================
# 步骤 3: 创建目录结构
# ==============================================================================
step3_create_directories() {
    log_step "DIRS" "Step 3/9: Creating directory structure"

    mkdir -p "$INSTALL_DIR"
    mkdir -p "$INSTALL_DIR/logs"
    mkdir -p "$INSTALL_DIR/virtcca_deploy"
    mkdir -p "$MONITOR_LOG_DIR"
    mkdir -p "$MONITOR_CACHE_DIR"
    mkdir -p "$SSL_CERT_DIR"
    mkdir -p "$IFCFG_TEMPLATE_DIR"

    log_info "DIRS" "  [OK] $INSTALL_DIR"
    log_info "DIRS" "  [OK] $INSTALL_DIR/logs"
    log_info "DIRS" "  [OK] $INSTALL_DIR/virtcca_deploy"
    log_info "DIRS" "  [OK] $MONITOR_LOG_DIR"
    log_info "DIRS" "  [OK] $MONITOR_CACHE_DIR"
    log_info "DIRS" "  [OK] $SSL_CERT_DIR"
    log_info "DIRS" "  [OK] $IFCFG_TEMPLATE_DIR"
}

# ==============================================================================
# 步骤 4: 复制整个 virtcca_deploy 到 $INSTALL_DIR/virtcca_deploy
# ==============================================================================
step4_copy_files() {
    log_step "COPY" "Step 4/9: Copying virtcca_deploy package"

    local source_dir="/tmp/ga_inject/virtcca_deploy/"

    if [ ! -d "$source_dir" ]; then
        die "COPY" "Source directory not found: $source_dir"
    fi

    cp -r "$source_dir"/* "$INSTALL_DIR/virtcca_deploy/"

    local file_count
    file_count=$(find "$INSTALL_DIR/virtcca_deploy" -type f | wc -l)
    log_info "COPY" "Copied $file_count files to $INSTALL_DIR/virtcca_deploy"

    log_debug "COPY" "Installed components:"
    for comp in guest_agent monitor common; do
        if [ -d "$INSTALL_DIR/virtcca_deploy/$comp" ]; then
            log_debug "COPY" "  [OK] $comp/"
        else
            log_warn "COPY" "  [MISSING] $comp/"
        fi
    done
}

# ==============================================================================
# 步骤 5: 创建 Python 虚拟环境并安装依赖
# ==============================================================================
step5_setup_python() {
    log_step "PYTHON" "Step 5/9: Setting up Python environment"

    local ga_dir="$INSTALL_DIR/virtcca_deploy/guest_agent"

    if [ ! -d "$ga_dir" ]; then
        die "PYTHON" "guest_agent directory not found in $INSTALL_DIR/virtcca_deploy"
    fi

    cd "$ga_dir"
    mkdir -p "$ga_dir/logs"

    if ! command -v python3 &>/dev/null; then
        die "PYTHON" "python3 not found after dependency installation"
    fi

    local python_version
    python_version=$(python3 --version 2>&1)
    log_info "PYTHON" "Python version: $python_version"

    if [ -d "venv" ]; then
        log_warn "PYTHON" "Virtual environment already exists, removing..."
        rm -rf venv
    fi

    log_info "PYTHON" "Creating virtual environment..."
    if python3 -m venv venv; then
        log_info "PYTHON" "Virtual environment created"
    else
        die "PYTHON" "Failed to create virtual environment"
    fi

    if [ ! -f "venv/bin/python" ]; then
        die "PYTHON" "Virtual environment python not found"
    fi

    local venv_python_version
    venv_python_version=$(venv/bin/python --version 2>&1)
    log_info "PYTHON" "Venv python: $venv_python_version"

    if [ ! -f "requirements.txt" ]; then
        die "PYTHON" "requirements.txt not found in $ga_dir"
    fi

    log_info "PYTHON" "Installing Python dependencies..."
    source venv/bin/activate

    if pip install -r requirements.txt \
        --index-url https://mirrors.aliyun.com/pypi/simple/ \
        --trusted-host mirrors.aliyun.com \
        2>&1; then
        log_info "PYTHON" "Dependencies installed successfully"
    else
        die "PYTHON" "Failed to install Python dependencies"
    fi

    local required_pip_packages=("Flask" "gunicorn" "psutil" "python-dotenv")
    for pkg in "${required_pip_packages[@]}"; do
        if pip show "$pkg" &>/dev/null; then
            local ver
            ver=$(pip show "$pkg" 2>/dev/null | grep Version | awk '{print $2}')
            log_info "PYTHON" "  [OK] $pkg==$ver"
        else
            log_warn "PYTHON" "  [MISSING] $pkg not found"
        fi
    done
}

# ==============================================================================
# 步骤 6: 生成配置文件
# ==============================================================================
step6_generate_config() {
    log_step "CONFIG" "Step 6/9: Generating configuration file"

    local ga_dir="$INSTALL_DIR/virtcca_deploy/guest_agent"

    echo "# Guest Agent Configuration" > "$ga_dir/.env"
    echo "# Generated by setup_vm.sh at $START_TIME_HUMAN" >> "$ga_dir/.env"
    echo "HOST=0.0.0.0" >> "$ga_dir/.env"
    echo "PORT=5003" >> "$ga_dir/.env"
    echo "FLASK_DEBUG=false" >> "$ga_dir/.env"
    echo "MONITOR_INTERFACE=eth0" >> "$ga_dir/.env"
    echo "SSL_ENABLED=$SSL_ENABLED" >> "$ga_dir/.env"

    if [ "$SSL_ENABLED" = "true" ] && [ -n "$SSL_CERT_PATH" ] && [ -n "$SSL_KEY_PATH" ]; then
        echo "SSL_CERT_FILE=$SSL_CERT_PATH" >> "$ga_dir/.env"
        echo "SSL_KEY_FILE=$SSL_KEY_PATH" >> "$ga_dir/.env"
        if [ -n "$SSL_CA_CERT_PATH" ]; then
            echo "SSL_CA_CERT_FILE=$SSL_CA_CERT_PATH" >> "$ga_dir/.env"
        fi
        log_info "CONFIG" "SSL configuration written"
    else
        log_info "CONFIG" "SSL disabled, basic configuration written"
    fi

    log_info "CONFIG" ".env contents:"
    while IFS= read -r line; do
        log_info "CONFIG" "  $line"
    done < "$ga_dir/.env"

    if [ ! -f "$ga_dir/.env" ]; then
        die "CONFIG" "Failed to create .env file"
    fi
}

# ==============================================================================
# 步骤 7: 安装 systemd 服务
# ==============================================================================
step7_install_service() {
    log_step "SERVICE" "Step 7/9: Installing systemd service"

    local service_file="$INSTALL_DIR/virtcca_deploy/guest_agent/virtcca-guest-agent.service"

    if [ ! -f "$service_file" ]; then
        log_warn "SERVICE" "Service file not found: $service_file"
        log_warn "SERVICE" "Skipping service installation"
        return 0
    fi

    cp "$service_file" /etc/systemd/system/

    if command -v systemctl &>/dev/null; then
        systemctl daemon-reload
        if systemctl enable virtcca-guest-agent.service 2>/dev/null; then
            log_info "SERVICE" "Service installed and enabled"
        else
            log_warn "SERVICE" "Service file copied but enable failed (may be in chroot)"
        fi
    else
        log_warn "SERVICE" "systemctl not available, service file copied but not enabled"
    fi

    if [ -f "/etc/systemd/system/virtcca-guest-agent.service" ]; then
        log_info "SERVICE" "Service file verified at /etc/systemd/system/"
    else
        log_warn "SERVICE" "Service file not found after copy"
    fi
}

# ==============================================================================
# 步骤 8: 创建专用用户和 sudoers 白名单
# ==============================================================================
step8_create_user_and_sudoers() {
    log_step "SUDOERS" "Step 8/9: Creating service user and sudoers whitelist"

    if id "$GA_USER" &>/dev/null; then
        log_info "SUDOERS" "User $GA_USER already exists, skipping creation"
    else
        useradd -r -s /sbin/nologin -d "$INSTALL_DIR" -c "VirtCCA Guest Agent" "$GA_USER"
        log_info "SUDOERS" "  [OK] User $GA_USER created (system account, no login shell)"
    fi

    local sudoers_file="/etc/sudoers.d/virtcca-guest-agent"
    cat > "$sudoers_file" <<EOF
# VirtCCA Guest Agent - 最小化 sudo 权限白名单
# 仅允许 guest_agent 执行网络配置相关操作

# 网络配置文件写入: 部署 ifcfg-* 文件
$GA_USER ALL=(root) NOPASSWD: /usr/bin/tee /etc/sysconfig/network-scripts/ifcfg-*

# 网络接口启停: ifdown/ifup 单个接口
$GA_USER ALL=(root) NOPASSWD: /usr/sbin/ifdown *
$GA_USER ALL=(root) NOPASSWD: /usr/sbin/ifup *

# 网络接口启停: ifdown/ifup --all
$GA_USER ALL=(root) NOPASSWD: /usr/sbin/ifdown --all
$GA_USER ALL=(root) NOPASSWD: /usr/sbin/ifup --all

# 网络服务重启: systemctl restart NetworkManager/network
$GA_USER ALL=(root) NOPASSWD: /usr/bin/systemctl restart NetworkManager
$GA_USER ALL=(root) NOPASSWD: /usr/bin/systemctl restart network

# 网络连接关闭: nmcli
$GA_USER ALL=(root) NOPASSWD: /usr/bin/nmcli network off
EOF

    chmod 440 "$sudoers_file"

    if visudo -c -f "$sudoers_file" &>/dev/null; then
        log_info "SUDOERS" "  [OK] sudoers file validated: $sudoers_file"
    else
        log_error "SUDOERS" "sudoers file validation failed, removing"
        rm -f "$sudoers_file"
        die "SUDOERS" "Failed to create valid sudoers configuration"
    fi

    log_info "SUDOERS" "Sudoers whitelist configured for $GA_USER"
    log_info "SUDOERS" "Allowed commands:"
    log_info "SUDOERS" "  - tee /etc/sysconfig/network-scripts/ifcfg-*"
    log_info "SUDOERS" "  - ifdown/ifup <interface>"
    log_info "SUDOERS" "  - ifdown/ifup --all"
    log_info "SUDOERS" "  - systemctl restart NetworkManager"
    log_info "SUDOERS" "  - systemctl restart network"
    log_info "SUDOERS" "  - nmcli network off"
}

# ==============================================================================
# 步骤 9: 配置文件权限和目录所有权
# ==============================================================================
step9_set_permissions() {
    log_step "PERM" "Step 9/9: Setting file permissions and ownership"

    local ga_dir="$INSTALL_DIR/virtcca_deploy/guest_agent"

    # --- 安装目录所有权 ---
    chown -R "$GA_USER:$GA_GROUP" "$INSTALL_DIR"
    log_info "PERM" "  [OK] $INSTALL_DIR ownership -> $GA_USER:$GA_GROUP"

    # --- guest_agent 日志目录 ---
    chown "$GA_USER:$GA_GROUP" "$ga_dir/logs"
    chmod 755 "$ga_dir/logs"
    log_info "PERM" "  [OK] $ga_dir/logs ownership -> $GA_USER:$GA_GROUP, mode 755"

    # --- .env 文件权限(仅所有者可读写,保护 SSL 配置) ---
    if [ -f "$ga_dir/.env" ]; then
        chown "$GA_USER:$GA_GROUP" "$ga_dir/.env"
        chmod 600 "$ga_dir/.env"
        log_info "PERM" "  [OK] .env ownership -> $GA_USER:$GA_GROUP, mode 600"
    fi

    # --- SSL 证书目录和文件权限 ---
    if [ "$SSL_ENABLED" = "true" ]; then
        chown "root:$GA_GROUP" "$SSL_CERT_DIR"
        chmod 750 "$SSL_CERT_DIR"
        log_info "PERM" "  [OK] $SSL_CERT_DIR ownership -> root:$GA_GROUP, mode 750"

        if [ -n "$SSL_CERT_PATH" ] && [ -f "$SSL_CERT_PATH" ]; then
            chown "root:$GA_GROUP" "$SSL_CERT_PATH"
            chmod 640 "$SSL_CERT_PATH"
            log_info "PERM" "  [OK] SSL cert ownership -> root:$GA_GROUP, mode 640"
        fi
        if [ -n "$SSL_KEY_PATH" ] && [ -f "$SSL_KEY_PATH" ]; then
            chown "root:$GA_GROUP" "$SSL_KEY_PATH"
            chmod 640 "$SSL_KEY_PATH"
            log_info "PERM" "  [OK] SSL key ownership -> root:$GA_GROUP, mode 640"
        fi
        if [ -n "$SSL_CA_CERT_PATH" ] && [ -f "$SSL_CA_CERT_PATH" ]; then
            chown "root:$GA_GROUP" "$SSL_CA_CERT_PATH"
            chmod 640 "$SSL_CA_CERT_PATH"
            log_info "PERM" "  [OK] SSL CA cert ownership -> root:$GA_GROUP, mode 640"
        fi
    fi

    # --- ifcfg-template 文件权限 ---
    if [ -f "$IFCFG_TEMPLATE_DIR/ifcfg-template" ]; then
        chown "$GA_USER:$GA_GROUP" "$IFCFG_TEMPLATE_DIR/ifcfg-template"
        chmod 640 "$IFCFG_TEMPLATE_DIR/ifcfg-template"
        log_info "PERM" "  [OK] ifcfg-template ownership -> $GA_USER:$GA_GROUP, mode 640"
    fi

    # --- /etc/virtcca_deploy 目录权限 ---
    chown "root:$GA_GROUP" "$IFCFG_TEMPLATE_DIR"
    chmod 750 "$IFCFG_TEMPLATE_DIR"
    log_info "PERM" "  [OK] $IFCFG_TEMPLATE_DIR ownership -> root:$GA_GROUP, mode 750"

    # --- 监控日志目录 ---
    chown "$GA_USER:$GA_GROUP" "$MONITOR_LOG_DIR"
    chmod 755 "$MONITOR_LOG_DIR"
    log_info "PERM" "  [OK] $MONITOR_LOG_DIR ownership -> $GA_USER:$GA_GROUP, mode 755"

    # --- 监控缓存目录 ---
    chown "$GA_USER:$GA_GROUP" "$MONITOR_CACHE_DIR"
    chmod 755 "$MONITOR_CACHE_DIR"
    log_info "PERM" "  [OK] $MONITOR_CACHE_DIR ownership -> $GA_USER:$GA_GROUP, mode 755"

    # --- 网络配置脚本目录(保持 root 所有,通过 sudo 写入) ---
    chown root:root "$NETWORK_SCRIPTS_DIR"
    chmod 755 "$NETWORK_SCRIPTS_DIR"
    log_info "PERM" "  [OK] $NETWORK_SCRIPTS_DIR ownership -> root:root, mode 755"

    # --- systemd 服务文件 ---
    if [ -f "/etc/systemd/system/virtcca-guest-agent.service" ]; then
        chown root:root "/etc/systemd/system/virtcca-guest-agent.service"
        chmod 644 "/etc/systemd/system/virtcca-guest-agent.service"
        log_info "PERM" "  [OK] service file ownership -> root:root, mode 644"
    fi

    log_info "PERM" "File permissions and ownership configured"
}

# ==============================================================================
# 安装结果验证
# ==============================================================================
verify_installation() {
    log_step "VERIFY" "Installation Verification"

    local verify_pass=true
    local ga_dir="$INSTALL_DIR/virtcca_deploy/guest_agent"

    if [ -d "$ga_dir" ]; then
        log_info "VERIFY" "  [PASS] guest_agent/ directory exists"
    else
        log_error "VERIFY" "  [FAIL] guest_agent/ directory missing"
        verify_pass=false
    fi

    if [ -d "$ga_dir/app" ]; then
        log_info "VERIFY" "  [PASS] app/ directory exists"
    else
        log_error "VERIFY" "  [FAIL] app/ directory missing"
        verify_pass=false
    fi

    if [ -f "$ga_dir/main.py" ]; then
        log_info "VERIFY" "  [PASS] main.py exists"
    else
        log_error "VERIFY" "  [FAIL] main.py missing"
        verify_pass=false
    fi

    if [ -f "$ga_dir/.env" ]; then
        local env_mode
        env_mode=$(stat -c '%a' "$ga_dir/.env")
        if [ "$env_mode" = "600" ]; then
            log_info "VERIFY" "  [PASS] .env exists with correct permissions (600)"
        else
            log_warn "VERIFY" "  [WARN] .env has unexpected permissions: $env_mode (expected 600)"
        fi
    else
        log_error "VERIFY" "  [FAIL] .env missing"
        verify_pass=false
    fi

    if [ -f "$ga_dir/requirements.txt" ]; then
        log_info "VERIFY" "  [PASS] requirements.txt exists"
    else
        log_error "VERIFY" "  [FAIL] requirements.txt missing"
        verify_pass=false
    fi

    if [ -f "$ga_dir/venv/bin/python" ]; then
        log_info "VERIFY" "  [PASS] Python venv exists"
    else
        log_error "VERIFY" "  [FAIL] Python venv missing"
        verify_pass=false
    fi

    if [ -d "$INSTALL_DIR/virtcca_deploy/monitor" ]; then
        log_info "VERIFY" "  [PASS] monitor/ directory exists"
    else
        log_error "VERIFY" "  [FAIL] monitor/ directory missing"
        verify_pass=false
    fi

    if [ -f "$INSTALL_DIR/virtcca_deploy/monitor/main.py" ]; then
        log_info "VERIFY" "  [PASS] monitor/main.py exists"
    else
        log_error "VERIFY" "  [FAIL] monitor/main.py missing"
        verify_pass=false
    fi

    if [ -f "/etc/systemd/system/virtcca-guest-agent.service" ]; then
        log_info "VERIFY" "  [PASS] systemd service file installed"
    else
        log_warn "VERIFY" "  [SKIP] systemd service file not installed"
    fi

    if [ -d "$ga_dir/logs" ]; then
        log_info "VERIFY" "  [PASS] logs directory exists"
    else
        log_error "VERIFY" "  [FAIL] logs directory missing"
        verify_pass=false
    fi

    if id "$GA_USER" &>/dev/null; then
        log_info "VERIFY" "  [PASS] service user $GA_USER exists"
    else
        log_error "VERIFY" "  [FAIL] service user $GA_USER not found"
        verify_pass=false
    fi

    if [ -f "/etc/sudoers.d/virtcca-guest-agent" ]; then
        log_info "VERIFY" "  [PASS] sudoers whitelist installed"
    else
        log_error "VERIFY" "  [FAIL] sudoers whitelist not found"
        verify_pass=false
    fi

    if [ -d "$MONITOR_LOG_DIR" ]; then
        log_info "VERIFY" "  [PASS] monitor log directory exists"
    else
        log_error "VERIFY" "  [FAIL] monitor log directory missing"
        verify_pass=false
    fi

    return $( [ "$verify_pass" = true ] && echo 0 || echo 1 )
}

# ==============================================================================
# 主函数
# ==============================================================================
main() {
    step1_init
    step2_install_dependencies
    step3_create_directories
    step4_copy_files
    step5_setup_python
    step6_generate_config
    step7_install_service
    step8_create_user_and_sudoers
    step9_set_permissions

    if verify_installation; then
        log_info "MAIN" "=========================================="
        log_info "MAIN" "Guest Agent Setup Completed Successfully"
        log_info "MAIN" "=========================================="
    else
        log_error "MAIN" "=========================================="
        log_error "MAIN" "Guest Agent Setup Completed with Errors"
        log_error "MAIN" "=========================================="
        exit 1
    fi

    local end_time
    end_time=$(date +%s)
    local total_time=$((end_time - START_TIME))
    log_info "MAIN" "Total duration: ${total_time}s"
    log_info "MAIN" "Warnings: $WARN_COUNT"
    log_info "MAIN" "Errors: $ERROR_COUNT"
}

main "$@"