#!/bin/bash

. ./ajax_agent_common

# Ȩ޼ - ȷֻйԱԲ
action_check

# ȷĿ¼
if [ ! -d "$AGENT_CONF_DIR" ]; then
    mkdir -p "$AGENT_CONF_DIR"
    chown -R nobody: "$AGENT_CONF_DIR"
fi

if [ ! -d "$AGENT_CONF_BACKUP_DIR" ]; then
    mkdir -p "$AGENT_CONF_BACKUP_DIR"
    chown -R nobody: "$AGENT_CONF_BACKUP_DIR"
fi

if [ ! -d "$RAM_TMP_DIR" ]; then
    mkdir -p "$RAM_TMP_DIR"
    chown -R nobody: "$RAM_TMP_DIR"
fi

# ֤

# ǷΪЧIPv4ַ
is_valid_ipv4() {
    local ip="$1"
    echo "$ip" | grep -qE '^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$'
}

# ǷΪЧIPv6ַ֧ѹʽ
is_valid_ipv6() {
    local ip="$1"
    # Ƴţڣ
    ip=$(echo "$ip" | sed 's/^\[\|\]$//g')

    # ʹ grep  IPv6 ʽ֧ѹʽ
    echo "$ip" | grep -qE '^([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$|^([0-9a-fA-F]{1,4}:){1,7}:$|^([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}$|^([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}$|^([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}$|^([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}$|^([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}$|^[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})$|^:((:[0-9a-fA-F]{1,4}){1,7}|:)$|^::$|^::1$|^::[0-9a-fA-F]{1,4}$'
}

# ǷΪЧlocalhost
is_valid_domain() {
    local host="$1"

    # localhost Ч
    if [ "$host" = "localhost" ]; then
        return 0
    fi

    # ǷΪIPַ
    if is_valid_ipv4 "$host" || is_valid_ipv6 "$host"; then
        return 1
    fi

    # ʽ飺ΪգԵ㿪ͷβЧַ
    if [ -z "$host" ] || echo "$host" | grep -qE '^\.|\.$|\.\.'; then
        return 1
    fi

    # ʽ
    echo "$host" | grep -qE '^[a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?)*$'
}

# ӷַȡ
extract_host_from_address() {
    local addr="$1"

    # IPv6 ʽ: [2001:da8::1]:443
    if echo "$addr" | grep -qE '^\[[^\]]+\]:[0-9]+$'; then
        echo "$addr" | sed 's/^\[\([^\]]*\)\]:[0-9]*$/\1/'
        return 0
    fi

    # IPv4 ʽ: 192.168.1.1:443  example.com:443
    if echo "$addr" | grep -q ':'; then
        echo "$addr" | sed 's/:[0-9]*$//'
        return 0
    fi

    return 1
}

# ֤˿ں
is_valid_port() {
    local port="$1"

    # ǷΪ
    if ! echo "$port" | grep -qE '^[0-9]+$'; then
        return 1
    fi

    # 鷶Χ
    if [ "$port" -lt 1 ] || [ "$port" -gt 65535 ]; then
        return 1
    fi

    return 0
}

# ַ֤ʽϸϢ
validate_server_address_detailed() {
    local addr="$1"

    if [ -z "$addr" ]; then
        echo "ַΪ"
        return 1
    fi

    # IPv6 ʽ: [2001:da8::1]:443
    if echo "$addr" | grep -qE '^\[[^\]]+\]:[0-9]+$'; then
        local ipv6=$(echo "$addr" | sed 's/^\[\([^\]]*\)\]:[0-9]*$/\1/')
        local port=$(echo "$addr" | sed 's/^.*:\([0-9]*\)$/\1/')

        if ! is_valid_ipv6 "$ipv6"; then
            echo "IPv6ַʽЧ: $ipv6"
            return 1
        fi

        if ! is_valid_port "$port"; then
            echo "˿ںű1-65535Χڣǰֵ: $port"
            return 1
        fi

        return 0
    fi

    # IPv4 ʽ: 192.168.1.1:443  example.com:443
    if echo "$addr" | grep -q ':'; then
        local host=$(echo "$addr" | sed 's/:[0-9]*$//')
        local port=$(echo "$addr" | sed 's/^.*:\([0-9]*\)$/\1/')

        if ! is_valid_port "$port"; then
            echo "˿ںű1-65535Χڣǰֵ: $port"
            return 1
        fi

        if ! is_valid_ipv4 "$host" && ! is_valid_domain "$host"; then
            echo "ַʽЧ: $host"
            return 1
        fi

        return 0
    fi

    echo "ַʽЧֵ֧ĸʽ: :˿, IPv4ַ:˿, [IPv6ַ]:˿"
    return 1
}

# YAML
parse_yaml_config() {
    local config_file="$1"
    
    if [ ! -f "$config_file" ]; then
        echo "CONFIG_FILE_NOT_FOUND"
        return 1
    fi
    
    awk '
    BEGIN { section=""; subsection="" }
    
    # עͺͿ
    /^#/ || /^$/ { next }
    
    # ڵ
    /^[a-zA-Z][a-zA-Z0-9-]*:/ {
        section = $1
        gsub(":", "", section)
        subsection = ""
        next
    }
    
    # ӽڵ
    /^  [a-zA-Z][a-zA-Z0-9-]*:/ {
        if (section != "") {
            subsection = $1
            gsub(":", "", subsection)
            gsub("^  ", "", subsection)
            
            # ֱֵ
            if (NF > 1) {
                value = $2
                for (i = 3; i <= NF; i++) value = value " " $i
                gsub("\"", "", value)
                gsub("#.*", "", value)  # Ƴע
                gsub(/[ \t]+$/, "", value)  # Ƴβո
                print section "_" subsection "=" value
            }
        }
        next
    }
    
    # 
    /^    - / {
        if (section != "" && subsection != "") {
            value = $2
            for (i = 3; i <= NF; i++) value = value " " $i
            gsub("\"", "", value)
            gsub("#.*", "", value)  # Ƴע
            gsub(/[ \t]+$/, "", value)  # Ƴβո
            print section "_" subsection "_item=" value
        }
        next
    }
    
    # ڵ
    /^    [a-zA-Z][a-zA-Z0-9-]*:/ {
        if (section != "" && subsection != "") {
            key = $1
            gsub(":", "", key)
            gsub("^    ", "", key)
            
            if (NF > 1) {
                value = $2
                for (i = 3; i <= NF; i++) value = value " " $i
                gsub("\"", "", value)
                gsub("#.*", "", value)  # Ƴע
                gsub(/[ \t]+$/, "", value)  # Ƴβո
                print section "_" subsection "_" key "=" value
            }
        }
        next
    }
    ' "$config_file"
}

# ú
agent_load_config() {
    local recovery_status=""

    # ļڣȳԴӱݻָ
    if [ ! -f "$AGENT_CONF_FILE" ]; then
        WEB_LOGGER "CONFIG_LOAD" "ļڣԴӱݻָ"

        # Ƿڱļ
        local latest_backup=""
        for backup_file in "$AGENT_CONF_BACKUP_DIR"/config_*.yaml; do
            if [ -f "$backup_file" ]; then
                if [ -z "$latest_backup" ] || [ "$backup_file" -nt "$latest_backup" ]; then
                    latest_backup="$backup_file"
                fi
            fi
        done

        if [ -n "$latest_backup" ]; then
            # ±ݻָ
            cp "$latest_backup" "$AGENT_CONF_FILE"
            chown nobody: "$AGENT_CONF_FILE"
            recovery_status="Ѵӱݻָ: $(basename "$latest_backup")"
            WEB_LOGGER "CONFIG_RECOVERY" "$recovery_status"
        else
            # ûбļĬ
            recovery_status="ѴĬ"
            WEB_LOGGER "CONFIG_LOAD" "ޱļĬ"
            agent_create_default_config
        fi
    fi

    # ֤ļʽ
    local validation_error=$(validate_yaml_format "$AGENT_CONF_FILE")
    if [ $? -ne 0 ]; then
        WEB_LOGGER "CONFIG_ERROR" "ļʽ: $validation_error"

        # Իָļ
        local recovery_msg=$(recover_config_file)
        WEB_LOGGER "CONFIG_RECOVERY" "$recovery_msg"

        # ָ֤ļ
        validation_error=$(validate_yaml_format "$AGENT_CONF_FILE")
        if [ $? -ne 0 ]; then
            printf '{"error": "ļʽһָʧ: %s"}' "$validation_error"
            return 1
        fi
    fi

    # ļ
    local parsed_config=$(parse_yaml_config "$AGENT_CONF_FILE")

    if [ "$parsed_config" = "CONFIG_FILE_NOT_FOUND" ]; then
        printf '{"error": "ļ"}'
        return 1
    fi

    # ʼ
    local customer_id=""
    local client_id=""
    local mode=""
    local server_addrs=""
    local tls_enabled="true"
    local tls_sni=""
    local tls_skip_verify="false"
    local heartbeat_interval="10"
    local stats_report_interval="60"
    local conn_monitor_interval="5"
    local keepalive_time="60"
    local keepalive_timeout="20"
    local log_level="INFO"
    local log_format="json"
    local log_max_size="256"
    local log_max_age="90"
    local log_max_backups="50"
    local log_compress="true"
    local update_server_url=""
    local update_channel="stable"
    local update_auto_update="true"
    local update_check_window_start="01:00"
    local update_check_window_end="05:00"
    local update_download_timeout="600"

    # ʱļڴ洢
    local temp_file="$RAM_TMP_DIR/parsed_config.$$"
    echo "$parsed_config" > "$temp_file"

    # 
    while IFS='=' read -r key value; do
        case "$key" in
            "client_customer-id") customer_id="$value" ;;
            "client_client-id") client_id="$value" ;;
            "client_mode") mode="$value" ;;
            "comms_addrs_item")
                if [ -z "$server_addrs" ]; then
                    server_addrs="$value"
                else
                    server_addrs="$server_addrs,$value"
                fi
                ;;
            "comms_tls_enabled") tls_enabled="$value" ;;
            "comms_tls_sni") tls_sni="$value" ;;
            "comms_tls_skip-verify") tls_skip_verify="$value" ;;
            "comms_keepalive-time") keepalive_time="$value" ;;
            "comms_keepalive-timeout") keepalive_timeout="$value" ;;
            "timing_heartbeat-interval") heartbeat_interval="$value" ;;
            "timing_stats-report-interval") stats_report_interval="$value" ;;
            "timing_conn-status-monitor-interval") conn_monitor_interval="$value" ;;
            "logging_level") log_level="$value" ;;
            "logging_format") log_format="$value" ;;
            "update_server-url") update_server_url="$value" ;;
            "update_channel") update_channel="$value" ;;
            "update_auto-update") update_auto_update="$value" ;;
            "update_check-window-start") update_check_window_start="$value" ;;
            "update_check-window-end") update_check_window_end="$value" ;;
            "update_download-timeout") update_download_timeout="$value" ;;
        esac
    done < "$temp_file"
    
    # ־ãҪ⴦
    local log_outputs=$(awk '
    # ÿһУɾעͣȻɾǰβĿո
    {
        sub(/#.*/, "")
        gsub(/[ \t]+$/, "")
    }

    # ΪУ
    /^\s*$/ { next }

    /^logging:/ { in_logging=1; next }
    /^[a-zA-Z]/ && in_logging { in_logging=0 }

    in_logging && /^  outputs:/ { in_outputs=1; next }
    in_logging && /^  [a-zA-Z]/ && in_outputs { in_outputs=0 }

    in_outputs && /^    - type: "file"/ { in_file=1; next }
    in_outputs && /^    - type: "console"/ {
        # Console output is not supported in daemon mode, ignoring
        in_file=0;
        next
    }

    in_outputs && in_file && /file:/ {
        # ־ļ·ظǰ
        next
    }

    in_outputs && in_file && /max-size:/ { print "log_max_size=" $2; next }
    in_outputs && in_file && /max-age:/ { print "log_max_age=" $2; next }
    in_outputs && in_file && /max-backups:/ { print "log_max_backups=" $2; next }
    in_outputs && in_file && /compress:/ { print "log_compress=" $2; next }
    ' "$AGENT_CONF_FILE")

    # Ӧ־õʱļ
    local log_temp_file="$RAM_TMP_DIR/log_config.$$"
    echo "$log_outputs" > "$log_temp_file"

    while IFS='=' read -r key value; do
        case "$key" in
            "log_max_size") log_max_size="$value" ;;
            "log_max_age") log_max_age="$value" ;;
            "log_max_backups") log_max_backups="$value" ;;
            "log_compress") log_compress="$value" ;;
        esac
    done < "$log_temp_file"

    # ʱļ
    rm -f "$temp_file" "$log_temp_file"
    
    # JSONӦ
    printf '{'
    printf '"customer_id": "%s",' "$customer_id"
    printf '"client_id": "%s",' "$client_id"
    printf '"mode": "%s",' "$mode"
    printf '"server_addrs": "%s",' "$server_addrs"
    printf '"tls_enabled": %s,' "$tls_enabled"
    printf '"tls_sni": "%s",' "$tls_sni"
    printf '"tls_skip_verify": %s,' "$tls_skip_verify"
    printf '"heartbeat_interval": "%s",' "$heartbeat_interval"
    printf '"stats_report_interval": "%s",' "$stats_report_interval"
    printf '"conn_monitor_interval": "%s",' "$conn_monitor_interval"
    printf '"keepalive_time": "%s",' "$keepalive_time"
    printf '"keepalive_timeout": "%s",' "$keepalive_timeout"
    printf '"log_level": "%s",' "$log_level"
    printf '"log_format": "%s",' "$log_format"
    printf '"log_max_size": "%s",' "$log_max_size"
    printf '"log_max_age": "%s",' "$log_max_age"
    printf '"log_max_backups": "%s",' "$log_max_backups"
    printf '"log_compress": %s,' "$log_compress"
    printf '"update_server_url": "%s",' "$update_server_url"
    printf '"update_channel": "%s",' "$update_channel"
    printf '"update_auto_update": %s,' "$update_auto_update"
    printf '"update_check_window_start": "%s",' "$update_check_window_start"
    printf '"update_check_window_end": "%s",' "$update_check_window_end"
    printf '"update_download_timeout": "%s",' "$update_download_timeout"

    # ӻָ״̬Ϣ
    if [ -n "$recovery_status" ]; then
        printf '"recovery_status": "%s"' "$recovery_status"
    else
        printf '"recovery_status": ""'
    fi
    printf '}'
}

# ־СMBΪλ־Ŀ¼ÿռ䣩
calculate_max_size() {
    local log_dir="$1"

    # ȷĿ¼
    if [ ! -d "$log_dir" ]; then
        mkdir -p "$log_dir" 2>/dev/null || {
            echo "64"  # Default fallback
            return 0
        }
    fi

    # ȡļϵͳͺͿÿռ
    # df -T output: Filesystem Type 1K-blocks Used Available Use% Mounted
    # Ҫ $2 (Type)  $5 (Available)
    local fs_info=$(df -T "$log_dir" 2>/dev/null | awk 'NR==2 {print $2, $5}')
    local fs_type=$(echo "$fs_info" | awk '{print $1}')
    local available_kb=$(echo "$fs_info" | awk '{print $2}')
    
    # ĬΪ 64MB ޷ȡϢ
    if [ -z "$available_kb" ] || ! echo "$available_kb" | grep -qE '^[0-9]+$'; then
        echo "64"
        return 0
    fi

    # ʹÿÿռΪ
    local base_kb=$available_kb

    #  tmpfsҲڴ沢ʹýСֵ
    if [ "$fs_type" = "tmpfs" ]; then
        local free_mem_kb=$(free 2>/dev/null | awk '/^Mem:/ {print $4}')
        if [ -n "$free_mem_kb" ] && echo "$free_mem_kb" | grep -qE '^[0-9]+$'; then
            if [ "$free_mem_kb" -lt "$base_kb" ]; then
                base_kb=$free_mem_kb
            fi
        fi
    fi

    # ÿռ 20%
    local log_max_kb=$((base_kb / 5))
    local log_max_mb=$((log_max_kb / 1024))

    # ȷֵ
    if [ $log_max_mb -ge 128 ]; then
        echo "128"
    elif [ $log_max_mb -ge 64 ]; then
        echo "64"
    else
        echo "32"
    fi
    return 0
}

# 󱸷ڿÿռ䣩
calculate_max_backups() {
    local archive_dir="$1"
    local max_size="$2"

    # ȷĿ¼
    if [ ! -d "$archive_dir" ]; then
        mkdir -p "$archive_dir" 2>/dev/null || {
            echo "10"  # Default fallback
            return 0
        }
    fi

    # ȡÿռ䣨KBΪλ
    local available_kb=$(df "$archive_dir" 2>/dev/null | awk 'NR==2 {print $4}')

    # ĬΪ 10 ޷ȡϢ
    if [ -z "$available_kb" ] || ! echo "$available_kb" | grep -qE '^[0-9]+$'; then
        echo "10"
        return 0
    fi

    #  max_size ѹС
    local compressed_mb
    case "$max_size" in
        128) compressed_mb=4 ;;
        64)  compressed_mb=2 ;;
        32)  compressed_mb=1 ;;
        *)   compressed_mb=2 ;;  # Default
    esac

    # ־ռ䣨20%Ŀÿռ䣩
    local total_log_kb=$((available_kb / 5))
    local total_log_mb=$((total_log_kb / 1024))
    local available_for_backups=$((total_log_mb - max_size))

    # ռ䲻㣬Сֵ
    if [ $available_for_backups -le 0 ]; then
        echo "1"
        return 0
    fi

    #  max-backups: (total - max_size) / compressed_size
    local max_backups=$(( (total_log_mb - max_size) / compressed_mb ))

    # ӦԼ
    if [ $max_backups -gt 50 ]; then
        echo "50"
    elif [ $max_backups -ge 10 ]; then
        # ֵ >= 10뵽 10
        echo $(( (max_backups / 10) * 10 ))
    elif [ $max_backups -lt 1 ]; then
        echo "1"
    else
        echo "$max_backups"
    fi
    return 0
}

# Ĭú
agent_create_default_config() {
    # ʹ÷汾ļΪĬģ
    local release_config="${APP_ROOT_DIR}/config/config.yaml"

    # 汾ļڣʹΪģ
    if [ -f "$release_config" ]; then
        cp "$release_config" "$AGENT_CONF_FILE"
        chown nobody: "$AGENT_CONF_FILE"
        return $?
    fi

    # 汾ļڣʹĬã̬־
    # ̬־ϵͳԴ
    local max_size_mb=$(calculate_max_size "${AGENT_DEFAULT_LOG_DIR}")
    local max_backups_count=$(calculate_max_backups "${AGENT_ARCHIVE_LOG_DIR}" "$max_size_mb")

    WEB_LOGGER "CONFIG_CREATE" "Ĭ: max-size=${max_size_mb}MB, max-backups=${max_backups_count}"

    cat > "$AGENT_CONF_FILE" << EOF
version: "5.0"                   # Configuration format version

client:
  customer-id: 0                 # Customer ID
  client-id: 0                   # Client ID
  mode: ""                       # Agent working mode (set by activation code)

comms:
  addrs:                         # List of server addresses
    - "uc.gsase.com:8443"
  tls:                           # TLS encryption configuration
    enabled: true                # Whether to enable TLS encryption (default: true, for production environments)
    sni: ""                      # Server Name Indication for TLS (empty = auto-detect from first domain in addrs)
    skip-verify: false           # Skip server certificate verification (default: false, for production environments)
    ca-cert: "${AGENT_CA_CERT_FILE}" # Custom CA certificate file
  keepalive-time: 60             # Connection keepalive time in seconds (default: 60, range: 30-120)
  keepalive-timeout: 20          # Connection keepalive timeout in seconds (default: 20, range: 10-60)

update:
  server-url: "https://update.gsase.com"                # Update server URL (empty = update disabled)
  channel: "stable"                                     # Update channel (stable or dev)
  auto-update: true                                     # Whether to enable automatic updates
  check-window-start: "01:00"                           # Auto-check time window start (HH:MM format)
  check-window-end: "05:00"                             # Auto-check time window end (HH:MM format)
  download-timeout: 600                                 # Download timeout in seconds

timing:
  heartbeat-interval: 10                                # Heartbeat interval in seconds (default: 10, range: 1-60)
  stats-report-interval: 60                             # Statistics reporting interval in seconds (default: 60, range: 10-300)
  conn-status-monitor-interval: 5                       # Connectivity status monitoring interval in seconds (default: 5, range: 2-30)

logging:
  level: "INFO"                                         # Logging level (default: INFO, for production environments)
  format: "json"                                        # Log format (e.g., json, text)
  outputs:                                              # Log output configuration
    - type: "file"                                      # File output type
      file: "${AGENT_DEFAULT_LOG_FILE}"                 # Log file path
      max-size: ${max_size_mb}                          # Maximum size of a single log file in MB (dynamically calculated)
      max-age: 90                                       # Maximum number of days to retain old log files
      max-backups: ${max_backups_count}                 # Maximum number of old log files to retain (dynamically calculated)
      compress: true                                    # Whether to compress rotated log files
      archive:                                          # Log archiving configuration
        enabled: true                                   # Enable log archiving
        dir: "${AGENT_ARCHIVE_LOG_DIR}"                 # Archive directory (archiving runs daily at 00:00)
EOF

    # ļߺ
    chown nobody: "$AGENT_CONF_FILE"
}

# ֤
validate_customer_id() {
    local customer_id="$1"

    # ǷΪ
    if [ -z "$customer_id" ]; then
        echo "ͻIDΪ"
        return 1
    fi

    # ǷΪ
    if ! echo "$customer_id" | grep -q "^[0-9]\+$"; then
        echo "ͻID"
        return 1
    fi

    # ٵǷΪ0Ϊͳһ֤м

    return 0
}

validate_client_id() {
    local client_id="$1"

    # ǷΪ
    if [ -z "$client_id" ]; then
        echo "վIDΪ"
        return 1
    fi

    # ǷΪ
    if ! echo "$client_id" | grep -q "^[0-9]\+$"; then
        echo "վID"
        return 1
    fi

    # ٵǷΪ0Ϊͳһ֤м

    return 0
}

# ͳһ֤ͻIDվID
validate_customer_client_ids() {
    local customer_id="$1"
    local client_id="$2"

    # ȵõ֤
    local customer_error=$(validate_customer_id "$customer_id")
    if [ $? -ne 0 ]; then
        echo "$customer_error"
        return 1
    fi

    local client_error=$(validate_client_id "$client_id")
    if [ $? -ne 0 ]; then
        echo "$client_error"
        return 1
    fi

    # ǷͬʱΪ0
    if [ "$customer_id" -eq 0 ] && [ "$client_id" -eq 0 ]; then
        echo "ͻIDվIDͬʱΪ0"
        return 1
    fi

    return 0
}



validate_file_path() {
    local path="$1"

    # ΪգʹĬֵ
    if [ -z "$path" ]; then
        return 0
    fi

    # ǷΪ·
    if ! echo "$path" | grep -q "^/"; then
        echo "ʹþ·"
        return 1
    fi

    return 0
}

validate_numeric_value() {
    local value="$1"
    local name="$2"

    # ΪգʹĬֵ
    if [ -z "$value" ]; then
        return 0
    fi

    # ǷΪ
    if ! echo "$value" | grep -q "^[0-9]\+$"; then
        echo "${name}"
        return 1
    fi

    # Ƿ0
    if [ "$value" -le 0 ]; then
        echo "${name}0"
        return 1
    fi

    return 0
}

# ֤YAMLļʽ
validate_yaml_format() {
    local config_file="$1"

    if [ ! -f "$config_file" ]; then
        echo "ļ"
        return 1
    fi

    # YAMLʽ
    local errors=""

    # Ķڵ
    if ! grep -q "^client:" "$config_file"; then
        errors="${errors}ȱclientڵ; "
    fi

    if ! grep -q "^comms:" "$config_file"; then
        errors="${errors}ȱcommsڵ; "
    fi

    if ! grep -q "^logging:" "$config_file"; then
        errors="${errors}ȱloggingڵ; "
    fi

    # վ
    if ! grep -q "customer-id:" "$config_file"; then
        errors="${errors}ȱcustomer-id; "
    fi

    if ! grep -q "client-id:" "$config_file"; then
        errors="${errors}ȱclient-id; "
    fi

    # ַ
    if ! grep -q "addrs:" "$config_file"; then
        errors="${errors}ȱٷַ; "
    fi

    # YAML﷨󣨼򵥼飩
    local line_num=0
    while IFS= read -r line; do
        line_num=$((line_num + 1))

        # кע
        if echo "$line" | grep -q "^[[:space:]]*$" || echo "$line" | grep -q "^[[:space:]]*#"; then
            continue
        fi

        # һԣ򵥼飩
        if echo "$line" | grep -q "^[[:space:]]*[a-zA-Z].*:"; then
            # һֵУʽ
            if ! echo "$line" | grep -q ":"; then
                errors="${errors}${line_num}иʽ; "
            fi
        fi
    done < "$config_file"

    if [ -n "$errors" ]; then
        echo "$errors"
        return 1
    fi

    return 0
}

# Validate update server URL
validate_update_server_url() {
    local url="$1"

    # Empty URL is allowed (disables update)
    if [ -z "$url" ]; then
        return 0
    fi

    # Check HTTP/HTTPS format
    if ! echo "$url" | grep -qE '^https?://'; then
        echo "·ַЧ HTTP  HTTPS URL"
        return 1
    fi

    return 0
}

# Validate download timeout
validate_download_timeout() {
    local timeout="$1"

    # Check if numeric
    if ! echo "$timeout" | grep -qE '^[0-9]+$'; then
        echo "سʱʱ"
        return 1
    fi

    # Check range
    if [ "$timeout" -lt 60 ] || [ "$timeout" -gt 3600 ]; then
        echo "سʱʱ 60-3600 ֮"
        return 1
    fi

    return 0
}

# Validate time window
validate_time_window() {
    local start_time="$1"
    local end_time="$2"

    # Check format HH:MM
    if ! echo "$start_time" | grep -qE '^([0-1][0-9]|2[0-3]):([0-5][0-9])$'; then
        echo "ʼʱʽ󣬱 HH:MM ʽ"
        return 1
    fi

    if ! echo "$end_time" | grep -qE '^([0-1][0-9]|2[0-3]):([0-5][0-9])$'; then
        echo "ʱʽ󣬱 HH:MM ʽ"
        return 1
    fi

    # Compare times
    local start_hour=$(echo "$start_time" | cut -d: -f1)
    local start_min=$(echo "$start_time" | cut -d: -f2)
    local end_hour=$(echo "$end_time" | cut -d: -f1)
    local end_min=$(echo "$end_time" | cut -d: -f2)

    local start_minutes=$((10#$start_hour * 60 + 10#$start_min))
    local end_minutes=$((10#$end_hour * 60 + 10#$end_min))

    if [ "$end_minutes" -le "$start_minutes" ]; then
        echo "ʱڿʼʱ"
        return 1
    fi

    return 0
}

# ļָ
recover_config_file() {
    local backup_pattern="$AGENT_CONF_BACKUP_DIR/config_*.yaml"
    local latest_backup=""

    # µıļ
    for backup_file in $backup_pattern; do
        if [ -f "$backup_file" ]; then
            if [ -z "$latest_backup" ] || [ "$backup_file" -nt "$latest_backup" ]; then
                latest_backup="$backup_file"
            fi
        fi
    done

    if [ -n "$latest_backup" ]; then
        # ָ±
        cp "$latest_backup" "$AGENT_CONF_FILE"
        chown nobody: "$AGENT_CONF_FILE"
        echo "Ѵӱݻָļ: $latest_backup"
        return 0
    else
        # Ĭ
        agent_create_default_config
        echo "ѴĬļ"
        return 0
    fi
}

# YAMLɺ
generate_yaml_config() {
    local output_file="$1"
    local customer_id="$2"
    local client_id="$3"
    local server_addrs="$4"
    local tls_enabled="$5"
    local tls_sni="$6"
    local tls_skip_verify="$7"
    local heartbeat_interval="$8"
    local stats_report_interval="$9"
    local conn_monitor_interval="${10}"
    local keepalive_time="${11}"
    local keepalive_timeout="${12}"
    local log_level="${13}"
    local log_format="${14}"
    local log_max_size="${15}"
    local log_max_age="${16}"
    local log_max_backups="${17}"
    local log_compress="${18}"
    local update_server_url="${19}"
    local update_channel="${20}"
    local update_auto_update="${21}"
    local update_check_window_start="${22}"
    local update_check_window_end="${23}"
    local update_download_timeout="${24}"
    local mode="${25}"

    cat > "$output_file" << EOF
version: "5.0" # Configuration format version

client:
  customer-id: ${customer_id} # Customer ID
  client-id: ${client_id} # Client ID
  mode: "${mode}" # Agent working mode: "fully-controlled" or "semi-controlled"

comms:
  addrs: # List of server addresses
EOF

    # ӷַб
    echo "$server_addrs" | tr ',' '\n' | while read addr; do
        [ -n "$addr" ] && echo "    - \"$addr\"" >> "$output_file"
    done

    cat >> "$output_file" << EOF
  tls: # TLS encryption configuration
    enabled: ${tls_enabled} # Whether to enable TLS encryption (default: true, for security)
    sni: "${tls_sni}" # Server Name Indication for TLS (empty = auto-detect from first domain in addrs)
    skip-verify: ${tls_skip_verify} # Skip server certificate verification (default: false, for production environments)
    ca-cert: "${AGENT_CA_CERT_FILE}" # Custom CA certificate file
  keepalive-time: ${keepalive_time} # Connection keepalive time in seconds (default: 60, range: 30-120)
  keepalive-timeout: ${keepalive_timeout} # Connection keepalive timeout in seconds (default: 20, range: 10-60)

update:
  server-url: "${update_server_url}" # Update server URL (empty = update disabled)
  channel: "${update_channel}" # Update channel (stable or dev)
  auto-update: ${update_auto_update} # Whether to enable automatic updates
  check-window-start: "${update_check_window_start}" # Auto-check time window start (HH:MM format)
  check-window-end: "${update_check_window_end}" # Auto-check time window end (HH:MM format)
  download-timeout: ${update_download_timeout} # Download timeout in seconds

timing:
  heartbeat-interval: ${heartbeat_interval} # Heartbeat interval in seconds (default: 10, range: 1-60)
  stats-report-interval: ${stats_report_interval} # Statistics reporting interval in seconds (default: 60, range: 10-300)
  conn-status-monitor-interval: ${conn_monitor_interval} # Connectivity status monitoring interval in seconds (default: 5, range: 2-30)

logging:
  level: "${log_level}" # Logging level (e.g., DEBUG, INFO, WARN, ERROR)
  format: "${log_format}" # Log format (e.g., json, text)
  outputs: # Log output configuration
    - type: "file" # File output type
      file: "${AGENT_DEFAULT_LOG_FILE}" # Log file path (auto-managed)
      max-size: ${log_max_size} # Maximum size of a single log file in MB
      max-age: ${log_max_age} # Maximum number of days to retain old log files
      max-backups: ${log_max_backups} # Maximum number of old log files to retain
      compress: ${log_compress} # Whether to compress rotated log files
      archive: # Log archiving configuration
        enabled: true # Enable log archiving
        dir: "${AGENT_ARCHIVE_LOG_DIR}" # Archive directory (archiving runs daily at 00:00)
EOF

    # ļߺ
    chown nobody: "$output_file"
}

# ļ
backup_config() {
    if [ -f "$AGENT_CONF_FILE" ]; then
        local backup_file="$AGENT_CONF_BACKUP_DIR/config_$(date +%Y%m%d_%H%M%S).yaml"
        cp "$AGENT_CONF_FILE" "$backup_file"
        chown nobody: "$backup_file"

        # ݺԶڱ
        cleanup_old_backups

        echo "$backup_file"
    fi
}

# ú
agent_save_config() {
    # customer-id, client-id, mode, addrs ɼʼմļȡ
    local customer_id=""
    local client_id=""
    local mode=""
    local server_addrs=""

    if [ -f "$AGENT_CONF_FILE" ]; then
        local existing_config=$(parse_yaml_config "$AGENT_CONF_FILE")
        local existing_temp="$RAM_TMP_DIR/existing_config.$$"
        echo "$existing_config" > "$existing_temp"

        while IFS='=' read -r key value; do
            case "$key" in
                "client_customer-id") customer_id="$value" ;;
                "client_client-id") client_id="$value" ;;
                "client_mode") mode="$value" ;;
                "comms_addrs_item")
                    if [ -z "$server_addrs" ]; then
                        server_addrs="$value"
                    else
                        server_addrs="$server_addrs,$value"
                    fi
                    ;;
            esac
        done < "$existing_temp"
        rm -f "$existing_temp"
    fi

    # ȡ
    local tls_enabled="${CGI_tls_enabled:-true}"
    local tls_sni="${CGI_tls_sni:-}"
    local tls_skip_verify="${CGI_tls_skip_verify:-false}"
    local heartbeat_interval="${CGI_heartbeat_interval:-10}"
    local stats_report_interval="${CGI_stats_report_interval:-60}"
    local conn_monitor_interval="${CGI_conn_monitor_interval:-5}"
    local keepalive_time="${CGI_keepalive_time:-60}"
    local keepalive_timeout="${CGI_keepalive_timeout:-20}"
    local log_level="${CGI_log_level:-INFO}"
    local log_format="${CGI_log_format:-json}"
    local log_max_size="${CGI_log_max_size}"
    local log_max_age="${CGI_log_max_age}"
    local log_max_backups="${CGI_log_max_backups}"
    local log_compress="${CGI_log_compress:-true}"
    local update_server_url="${CGI_update_server_url:-}"
    local update_channel="${CGI_update_channel:-stable}"
    local update_auto_update="${CGI_update_auto_update:-true}"
    local update_check_window_start="${CGI_update_check_window_start}"
    local update_check_window_end="${CGI_update_check_window_end}"
    local update_download_timeout="${CGI_update_download_timeout}"

    # ֤customer_id, client_id, server_addrs ɼ֤
    local error_msg=""

    # SNI֤TLSSNIΪգδַ֤֤֤Ƿ
    if [ "$tls_enabled" = "true" ] && [ -z "$tls_sni" ] && [ "$tls_skip_verify" = "false" ]; then
        echo "$server_addrs" | tr ',' '\n' | while read addr; do
            if [ -n "$addr" ]; then
                addr=$(echo "$addr" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
                local host=$(extract_host_from_address "$addr")
                if [ -n "$host" ] && is_valid_domain "$host"; then
                    echo "domain_found"
                    exit 0
                fi
            fi
        done | grep -q "domain_found"

        if [ $? -ne 0 ]; then
            retjson 1 "SNIΪδ֤֤ʱַббһʽĵַ"
            return 1
        fi
    fi

    # ֵֶ֤ΣεãЧ
    error_msg=$(validate_numeric_value "$log_max_size" "־ļС")
    if [ $? -ne 0 ]; then
        retjson 1 "$error_msg"
        return 1
    fi

    error_msg=$(validate_numeric_value "$log_max_age" "־")
    if [ $? -ne 0 ]; then
        retjson 1 "$error_msg"
        return 1
    fi

    error_msg=$(validate_numeric_value "$log_max_backups" "ļ")
    if [ $? -ne 0 ]; then
        retjson 1 "$error_msg"
        return 1
    fi

    # ֤Զ
    error_msg=$(validate_update_server_url "$update_server_url")
    if [ $? -ne 0 ]; then
        retjson 1 "$error_msg"
        return 1
    fi

    error_msg=$(validate_download_timeout "$update_download_timeout")
    if [ $? -ne 0 ]; then
        retjson 1 "$error_msg"
        return 1
    fi

    # Զ£֤ʱ䴰
    if [ "$update_auto_update" = "true" ]; then
        error_msg=$(validate_time_window "$update_check_window_start" "$update_check_window_end")
        if [ $? -ne 0 ]; then
            retjson 1 "$error_msg"
            return 1
        fi
    fi

    # ֤
    # ֤ (1-60)
    if [ -z "$heartbeat_interval" ] || ! [[ "$heartbeat_interval" =~ ^[0-9]+$ ]] || [ "$heartbeat_interval" -lt 1 ] || [ "$heartbeat_interval" -gt 60 ]; then
        retjson 1 " 1-60 ֮"
        return 1
    fi

    # ֤ͳϱ (10-300룬ұ10)
    if [ -z "$stats_report_interval" ] || ! [[ "$stats_report_interval" =~ ^[0-9]+$ ]] || [ "$stats_report_interval" -lt 10 ] || [ "$stats_report_interval" -gt 300 ]; then
        retjson 1 "ͳϱ 10-300 ֮"
        return 1
    fi

    if [ $((stats_report_interval % 10)) -ne 0 ]; then
        retjson 1 "ͳϱ10102030...300"
        return 1
    fi

    # ֤·״̬ؼ (2-30)
    if [ -z "$conn_monitor_interval" ] || ! [[ "$conn_monitor_interval" =~ ^[0-9]+$ ]] || [ "$conn_monitor_interval" -lt 2 ] || [ "$conn_monitor_interval" -gt 30 ]; then
        retjson 1 "·״̬ؼ 2-30 ֮"
        return 1
    fi

    # ֤keepaliveʱ (30-120)
    if [ -z "$keepalive_time" ] || ! [[ "$keepalive_time" =~ ^[0-9]+$ ]] || [ "$keepalive_time" -lt 30 ] || [ "$keepalive_time" -gt 120 ]; then
        retjson 1 "Keepaliveʱ 30-120 ֮"
        return 1
    fi

    # ֤keepaliveʱ (10-60)
    if [ -z "$keepalive_timeout" ] || ! [[ "$keepalive_timeout" =~ ^[0-9]+$ ]] || [ "$keepalive_timeout" -lt 10 ] || [ "$keepalive_timeout" -gt 60 ]; then
        retjson 1 "Keepaliveʱ 10-60 ֮"
        return 1
    fi

    # ֤keepaliveʱСkeepaliveʱ
    if [ "$keepalive_timeout" -ge "$keepalive_time" ]; then
        retjson 1 "KeepaliveʱСKeepaliveʱ"
        return 1
    fi

    # ־ļ·ϵͳԶ֤

    # ݵǰ
    local backup_file=$(backup_config)

    # ļ
    local temp_file="$RAM_TMP_DIR/config_new.$$"

    if generate_yaml_config "$temp_file" "$customer_id" "$client_id" "$server_addrs" \
        "$tls_enabled" "$tls_sni" "$tls_skip_verify" \
        "$heartbeat_interval" "$stats_report_interval" "$conn_monitor_interval" \
        "$keepalive_time" "$keepalive_timeout" \
        "$log_level" "$log_format" "$log_max_size" "$log_max_age" "$log_max_backups" "$log_compress" \
        "$update_server_url" "$update_channel" "$update_auto_update" \
        "$update_check_window_start" "$update_check_window_end" "$update_download_timeout" \
        "$mode"; then

        # ֤ɵļʽ
        if [ -f "$temp_file" ]; then
            local validation_error=$(validate_yaml_format "$temp_file")
            if [ $? -eq 0 ]; then
                # ļʽȷƶʽλ
                mv "$temp_file" "$AGENT_CONF_FILE"
                chown nobody: "$AGENT_CONF_FILE"

                # ¼־
                WEB_LOGGER "CONFIG_SAVE" "ñɹ"

                retjson 0 "ñɹ"
            else
                # ļʽʱļ
                rm -f "$temp_file"

                # ¼־
                WEB_LOGGER "CONFIG_ERROR" "ļʽ֤ʧ: $validation_error"

                retjson 1 "ļʽ֤ʧ: $validation_error"
                return 1
            fi
        else
            retjson 1 "ļʧ"
            return 1
        fi
    else
        # ܴڵʱļ
        rm -f "$temp_file"

        # ¼־
        WEB_LOGGER "CONFIG_ERROR" "ļʧ"

        retjson 1 "ļʧ"
        return 1
    fi
}

# ú
agent_reset_config() {
    # ݵǰ
    local backup_file=$(backup_config)

    # Ĭ
    if agent_create_default_config; then
        WEB_LOGGER "CONFIG_RESET" "ΪĬֵ"
        retjson 0 "ΪĬֵ"
    else
        WEB_LOGGER "CONFIG_ERROR" "ʧ"
        retjson 1 "ʧ"
    fi
}

# ־ú
agent_reset_log_config() {
    # ļǷ
    if [ ! -f "$AGENT_CONF_FILE" ]; then
        WEB_LOGGER "CONFIG_ERROR" "ļڣ޷־"
        retjson 1 "ļ"
        return 1
    fi

    # ʹеĽȡǰ
    local parsed_config=$(parse_yaml_config "$AGENT_CONF_FILE")

    if [ "$parsed_config" = "CONFIG_FILE_NOT_FOUND" ]; then
        WEB_LOGGER "CONFIG_ERROR" "ļʧ"
        retjson 1 "ļʧ"
        return 1
    fi

    # ʼ agent_get_config ߼
    local customer_id=""
    local client_id=""
    local mode=""
    local server_addrs=""
    local tls_enabled="true"
    local tls_sni=""
    local tls_skip_verify="false"
    local heartbeat_interval="10"
    local stats_report_interval="60"
    local conn_monitor_interval="5"
    local keepalive_time="60"
    local keepalive_timeout="20"
    local update_server_url=""
    local update_channel="stable"
    local update_auto_update="true"
    local update_check_window_start="01:00"
    local update_check_window_end="05:00"
    local update_download_timeout="600"

    # ʱļڴ洢
    local temp_file="$RAM_TMP_DIR/parsed_config.$$"
    echo "$parsed_config" > "$temp_file"

    # ־ã
    while IFS='=' read -r key value; do
        case "$key" in
            "client_customer-id") customer_id="$value" ;;
            "client_client-id") client_id="$value" ;;
            "client_mode") mode="$value" ;;
            "comms_addrs_item")
                if [ -z "$server_addrs" ]; then
                    server_addrs="$value"
                else
                    server_addrs="$server_addrs,$value"
                fi
                ;;
            "comms_tls_enabled") tls_enabled="$value" ;;
            "comms_tls_sni") tls_sni="$value" ;;
            "comms_tls_skip-verify") tls_skip_verify="$value" ;;
            "comms_keepalive-time") keepalive_time="$value" ;;
            "comms_keepalive-timeout") keepalive_timeout="$value" ;;
            "timing_heartbeat-interval") heartbeat_interval="$value" ;;
            "timing_stats-report-interval") stats_report_interval="$value" ;;
            "timing_conn-status-monitor-interval") conn_monitor_interval="$value" ;;
            "update_server-url") update_server_url="$value" ;;
            "update_channel") update_channel="$value" ;;
            "update_auto-update") update_auto_update="$value" ;;
            "update_check-window-start") update_check_window_start="$value" ;;
            "update_check-window-end") update_check_window_end="$value" ;;
            "update_download-timeout") update_download_timeout="$value" ;;
        esac
    done < "$temp_file"

    # ʱļ
    rm -f "$temp_file"

    # ݵǰãڽɺִУ
    local backup_file=$(backup_config)

    # ̬־ĬֵϵͳԴ
    local log_level="INFO"
    local log_format="json"
    local log_max_size=$(calculate_max_size "${AGENT_DEFAULT_LOG_DIR}")
    local log_max_age="90"
    local log_max_backups=$(calculate_max_backups "${AGENT_ARCHIVE_LOG_DIR}" "$log_max_size")
    local log_compress="true"

    WEB_LOGGER "CONFIG_LOG_RESET" "־: max-size=${log_max_size}MB, max-backups=${log_max_backups}"

    # ļԭãֻ־֣
    local temp_new_file="$RAM_TMP_DIR/config_log_reset.$$"

    if generate_yaml_config "$temp_new_file" "$customer_id" "$client_id" "$server_addrs" \
        "$tls_enabled" "$tls_sni" "$tls_skip_verify" \
        "$heartbeat_interval" "$stats_report_interval" "$conn_monitor_interval" \
        "$keepalive_time" "$keepalive_timeout" \
        "$log_level" "$log_format" "$log_max_size" "$log_max_age" "$log_max_backups" "$log_compress" \
        "$update_server_url" "$update_channel" "$update_auto_update" \
        "$update_check_window_start" "$update_check_window_end" "$update_download_timeout" \
        "$mode"; then

        # ֤ɵļʽ
        if [ -f "$temp_new_file" ]; then
            local validation_error=$(validate_yaml_format "$temp_new_file")
            if [ $? -eq 0 ]; then
                # ļʽȷƶʽλ
                mv "$temp_new_file" "$AGENT_CONF_FILE"
                chown nobody: "$AGENT_CONF_FILE"
                WEB_LOGGER "CONFIG_LOG_RESET" "־ΪϵͳԴŻֵ"
                retjson 0 "־ΪĬֵ"
            else
                # ļʽ󣬻ָ
                if [ -n "$backup_file" ] && [ -f "$backup_file" ]; then
                    cp "$backup_file" "$AGENT_CONF_FILE"
                    chown nobody: "$AGENT_CONF_FILE"
                fi
                rm -f "$temp_new_file"
                WEB_LOGGER "CONFIG_ERROR" "ɵ־øʽ: $validation_error"
                retjson 1 "øʽ֤ʧ: $validation_error"
            fi
        else
            WEB_LOGGER "CONFIG_ERROR" "־ʧܣ޷ļ"
            retjson 1 "ļʧ"
        fi
    else
        WEB_LOGGER "CONFIG_ERROR" "־ʧܣYAMLʧ"
        retjson 1 "ʧ"
    fi
}

# ָú
agent_recover_config() {
    local backup_filename="${CGI_backup_filename}"

    if [ -n "$backup_filename" ]; then
        # ָָıļ
        local backup_file="$AGENT_CONF_BACKUP_DIR/$backup_filename"

        if [ -f "$backup_file" ]; then
            # ֤ļʽ
            local validation_error=$(validate_yaml_format "$backup_file")
            if [ $? -eq 0 ]; then
                # ݵǰ
                backup_config

                # ָָ
                cp "$backup_file" "$AGENT_CONF_FILE"
                chown nobody: "$AGENT_CONF_FILE"

                WEB_LOGGER "CONFIG_RECOVERY" "ָݻָóɹ: $backup_filename"
                retjson 0 "ӱ $backup_filename ָóɹ"
            else
                WEB_LOGGER "CONFIG_ERROR" "ļʽ: $validation_error"
                retjson 1 "ļʽ: $validation_error"
            fi
        else
            retjson 1 "ָıļ: $backup_filename"
        fi
    else
        # ָ±ݣԭ߼
        local recovery_msg=$(recover_config_file)

        # ָ֤ļ
        local validation_error=$(validate_yaml_format "$AGENT_CONF_FILE")
        if [ $? -eq 0 ]; then
            WEB_LOGGER "CONFIG_RECOVERY" "ûָɹ: $recovery_msg"
            retjson 0 "ûָɹ: $recovery_msg"
        else
            WEB_LOGGER "CONFIG_ERROR" "ûָʧ: $validation_error"
            retjson 1 "ûָʧ: $validation_error"
        fi
    fi
}

# ȡб
agent_list_backups() {
    local backup_list=""
    local dot=""
    local count=0

    # ڱ
    cleanup_old_backups

    # ʹlsʱ䵹бļµǰ
    local sorted_files=$(ls -t "$AGENT_CONF_BACKUP_DIR"/config_*.yaml 2>/dev/null)

    for backup_file in $sorted_files; do
        if [ -f "$backup_file" ]; then
            local filename=$(basename "$backup_file")
            local timestamp=$(echo "$filename" | sed 's/config_\(.*\)\.yaml/\1/')

            # ʱתΪѺøʽYYYY-MM-DD HH:MM:SS
            local date_part=$(echo "$timestamp" | cut -d'_' -f1)
            local time_part=$(echo "$timestamp" | cut -d'_' -f2)

            # ʱʽǷȷ
            if [ ${#date_part} -eq 8 ] && [ ${#time_part} -eq 6 ]; then
                local formatted_time="${date_part:0:4}-${date_part:4:2}-${date_part:6:2} ${time_part:0:2}:${time_part:2:2}:${time_part:4:2}"
            else
                # ʽȷʹԭʼʽ
                local formatted_time=$(echo "$timestamp" | sed 's/_/ /')
            fi

            local file_size=$(stat -c %s "$backup_file" 2>/dev/null || echo 0)

            backup_list="${backup_list}${dot}{\"filename\":\"$filename\",\"timestamp\":\"$formatted_time\",\"size\":$file_size}"
            dot=","
            count=$((count + 1))
        fi
    done

    printf '{"total":%d,"backups":[%s]}' "$count" "$backup_list"
}

# ɾָļ
agent_delete_backup() {
    local backup_filename="${CGI_backup_filename}"

    if [ -z "$backup_filename" ]; then
        retjson 1 "δָҪɾıļ"
        return 1
    fi

    # ֤ļʽֹ·
    if ! echo "$backup_filename" | grep -q "^config_[0-9]\{8\}_[0-9]\{6\}\.yaml$"; then
        retjson 1 "Чıļʽ"
        return 1
    fi

    local backup_file="$AGENT_CONF_BACKUP_DIR/$backup_filename"

    if [ -f "$backup_file" ]; then
        if rm "$backup_file"; then
            WEB_LOGGER "BACKUP_DELETE" "ɾļɹ: $backup_filename"
            retjson 0 "ļɾɹ"
        else
            WEB_LOGGER "BACKUP_ERROR" "ɾļʧ: $backup_filename"
            retjson 1 "ɾļʧ"
        fi
    else
        retjson 1 "ָıļ"
    fi
}

# ڱļ
cleanup_old_backups() {
    local max_backups=10  # Ĭϱ10
    local backup_count=0
    local backup_files=""

    # ȡбļʱµǰ
    for backup_file in "$AGENT_CONF_BACKUP_DIR"/config_*.yaml; do
        if [ -f "$backup_file" ]; then
            backup_files="$backup_files $backup_file"
            backup_count=$((backup_count + 1))
        fi
    done

    # ƣɾɵı
    if [ $backup_count -gt $max_backups ]; then
        local files_to_delete=$((backup_count - max_backups))

        # ޸ʱɾɵļ
        echo "$backup_files" | tr ' ' '\n' | while read backup_file; do
            if [ -f "$backup_file" ] && [ $files_to_delete -gt 0 ]; then
                rm "$backup_file"
                WEB_LOGGER "BACKUP_CLEANUP" "Զڱ: $(basename "$backup_file")"
                files_to_delete=$((files_to_delete - 1))
            fi
        done
    fi
}

# Agentƺ
agent_start() {
    local appctl_path=${RAM_APP_CTRL}

    if [ ! -f "$appctl_path" ] || [ ! -x "$appctl_path" ]; then
        retjson 1 "AgentƽűڻִȨ"
        return 1
    fi

    local output=$("$appctl_path" start agent 2>&1)
    local exit_code=$?

    if [ $exit_code -eq 0 ]; then
        WEB_LOGGER "AGENT_CONTROL" "Agentɹ"
        retjson 0 "Agentɹ"
    else
        WEB_LOGGER "AGENT_ERROR" "Agentʧ: $output"
        retjson 1 "Agentʧ: $output"
    fi
}

agent_stop() {
    local appctl_path=${RAM_APP_CTRL}

    if [ ! -f "$appctl_path" ] || [ ! -x "$appctl_path" ]; then
        retjson 1 "AgentƽűڻִȨ"
        return 1
    fi

    local output=$("$appctl_path" stop agent 2>&1)
    local exit_code=$?

    if [ $exit_code -eq 0 ]; then
        WEB_LOGGER "AGENT_CONTROL" "Agentֹͣɹ"
        retjson 0 "Agentֹͣɹ"
    else
        WEB_LOGGER "AGENT_ERROR" "Agentֹͣʧ: $output"
        retjson 1 "Agentֹͣʧ: $output"
    fi
}

agent_restart() {
    local appctl_path=${RAM_APP_CTRL}

    if [ ! -f "$appctl_path" ] || [ ! -x "$appctl_path" ]; then
        retjson 1 "AgentƽűڻִȨ"
        return 1
    fi

    local output=$("$appctl_path" restart agent 2>&1)
    local exit_code=$?

    if [ $exit_code -eq 0 ]; then
        WEB_LOGGER "AGENT_CONTROL" "Agentɹ"
        retjson 0 "Agentɹ"
    else
        WEB_LOGGER "AGENT_ERROR" "Agentʧ: $output"
        retjson 1 "Agentʧ: $output"
    fi
}

# ־ļع
agent_download_log() {
    # Get log file path from common function
    local log_file=$(get_log_file_path)

    # ־ļǷ
    if [ ! -f "$log_file" ]; then
        retjson 1 "־ļ: $log_file"
        return 1
    fi

    # ȡ־Ŀ¼ʱĿ¼
    local log_dir
    log_dir=$(dirname "$log_file")
    local tmp_dir="${log_dir}/tmp"

    # ɵʱѹļ1Сʱģ
    if [ -d "$tmp_dir" ]; then
        find "$tmp_dir" -name "agent-*.log.gz" -mmin +60 -delete 2>/dev/null
    fi

    # ʱĿ¼
    if [ ! -d "$tmp_dir" ]; then
        mkdir -p "$tmp_dir"
        chown -R nobody: "$tmp_dir"
    fi

    # ɴʱѹļʽagent-YYYY-MM-DDTHH-MM-SS.mmm.log.gz
    local timestamp
    timestamp=$(date +%Y-%m-%dT%H-%M-%S.%3N)
    local archive_file="${tmp_dir}/agent-${timestamp}.log.gz"
    local temp_log_file="${tmp_dir}/agent-${timestamp}.log"

    # ִѹȸƲȻʹ gzip ѹ
    local compress_result

    # ȸƲ
    cp "$log_file" "$temp_log_file" 2>/dev/null
    compress_result=$?

    if [ "$compress_result" -eq 0 ]; then
        # ѹļ
        gzip "$temp_log_file" 2>/dev/null
        compress_result=$?
    fi

    # ѹǷɹ
    if [ "$compress_result" -ne 0 ] || [ ! -f "$archive_file" ]; then
        rm -f "$archive_file" "$temp_log_file" 2>/dev/null
        retjson 1 "־ļѹʧ"
        return 1
    fi

    # ѹļС
    local archive_size
    archive_size=$(stat -c %s "$archive_file" 2>/dev/null || echo 0)
    if [ "$archive_size" -eq 0 ]; then
        rm -f "$archive_file" "$temp_log_file" 2>/dev/null
        retjson 1 "ѹļΪ"
        return 1
    fi

    # ѹļСƣ256MB
    local max_size=$((256 * 1024 * 1024))
    local archive_size_mb=$((archive_size / 1024 / 1024))
    if [ "$archive_size" -gt "$max_size" ]; then
        rm -f "$archive_file" "$temp_log_file" 2>/dev/null
        retjson 1 "ѹļ޷أС: ${archive_size_mb}MB: 256MB"
        return 1
    fi

    # HTTPͷϢļ
    local archive_filename="agent-${timestamp}.log.gz"
    echo "Content-Type: application/gzip"
    echo "Content-Disposition: attachment; filename=\"${archive_filename}\""
    echo "Content-Length: $archive_size"
    echo ""

    # ѹļ
    cat "$archive_file"

    # ̨ӳ60ɾʱļ
    # ѹļ256MB60㹻ɶȡ
    (sleep 60 && rm -f "$archive_file" 2>/dev/null) &

    local archive_size_kb=$((archive_size / 1024))
    WEB_LOGGER "LOG_DOWNLOAD" "־ļ: $archive_filename (size: ${archive_size_kb}KB)"
}

# List archive log files
# Returns JSON array of archive log files with filename, mtime, and size
agent_list_archive_logs() {
    # Get archive directory from common function
    local archive_dir=$(get_archive_log_dir)

    # Check if archive directory exists
    if [ ! -d "$archive_dir" ]; then
        printf '{\n'
        printf '    "archives": []\n'
        printf '}\n'
        return 0
    fi

    # Find all agent-*.log.gz files (exclude agent.log snapshot)
    local archives_json=""
    local first=1

    # Use find to get files sorted by modification time (newest first)
    while IFS= read -r file; do
        [ -z "$file" ] && continue

        local filename=$(basename "$file")

        # Get file modification time
        local mtime=$(stat -c '%Y' "$file" 2>/dev/null || echo 0)
        local mtime_formatted=$(date -d "@$mtime" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || echo "δ֪")

        # Get file size in MB
        local size_bytes=$(stat -c %s "$file" 2>/dev/null || echo 0)
        local size_mb=$((size_bytes / 1024 / 1024))
        local size_kb=$((size_bytes / 1024))
        local size_formatted

        if [ $size_mb -gt 0 ]; then
            size_formatted="${size_mb} MB"
        elif [ $size_kb -gt 0 ]; then
            size_formatted="${size_kb} KB"
        else
            size_formatted="${size_bytes} B"
        fi

        # Build JSON object
        if [ $first -eq 1 ]; then
            first=0
        else
            archives_json="${archives_json},"
        fi

        archives_json="${archives_json}
        {
            \"filename\": \"$filename\",
            \"mtime\": \"$mtime_formatted\",
            \"size\": \"$size_formatted\"
        }"
    # Use -H to follow symbolic links on command line only (more secure than -L)
    done < <(find -H "$archive_dir" -maxdepth 1 -type f -name 'agent-*.log.gz' -printf '%T@ %p\n' 2>/dev/null | sort -rn | cut -d' ' -f2-)

    # Build final JSON response
    printf '{\n'
    printf '    "archives": [%s\n    ]\n' "$archives_json"
    printf '}\n'
}

# Download archive log file
# Parameters: filename (from CGI_filename)
agent_download_archive_log() {
    local filename="$CGI_filename"

    # Validate filename parameter
    if [ -z "$filename" ]; then
        retjson 1 "ȱļ"
        return 1
    fi

    # Security: validate filename format (only allow agent-*.log.gz)
    if ! echo "$filename" | grep -qE '^agent-[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}-[0-9]{2}-[0-9]{2}\.[0-9]{3}\.log\.gz$'; then
        retjson 1 "Ƿļʽ"
        return 1
    fi

    # Get archive directory from common function
    local archive_dir=$(get_archive_log_dir)

    # Build full file path
    local file_path="${archive_dir}/${filename}"

    # Check if file exists
    if [ ! -f "$file_path" ]; then
        retjson 1 "ʷ־ļ: $filename"
        return 1
    fi

    # Get file size
    local file_size=$(stat -c %s "$file_path" 2>/dev/null || echo 0)

    if [ "$file_size" -eq 0 ]; then
        retjson 1 "ʷ־ļΪ"
        return 1
    fi

    # Set HTTP headers for file download
    echo "Content-Type: application/gzip"
    echo "Content-Disposition: attachment; filename=\"${filename}\""
    echo "Content-Length: $file_size"
    echo ""

    # Output file content
    cat "$file_path"

    local file_size_kb=$((file_size / 1024))
    WEB_LOGGER "ARCHIVE_LOG_DOWNLOAD" "ʷ־: $filename (size: ${file_size_kb}KB)"
}

# Delete archive log file
# Parameters: filename (from CGI_filename)
agent_delete_archive_log() {
    local filename="$CGI_filename"

    # Validate filename parameter
    if [ -z "$filename" ]; then
        retjson 1 "ȱļ"
        return 1
    fi

    # Security: validate filename format (only allow agent-*.log.gz)
    if ! echo "$filename" | grep -qE '^agent-[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}-[0-9]{2}-[0-9]{2}\.[0-9]{3}\.log\.gz$'; then
        retjson 1 "Ƿļʽ"
        return 1
    fi

    # Get archive directory from common function
    local archive_dir=$(get_archive_log_dir)

    # Build full file path
    local file_path="${archive_dir}/${filename}"

    # Check if file exists
    if [ ! -f "$file_path" ]; then
        retjson 1 "ʷ־ļ: $filename"
        return 1
    fi

    # Delete file
    rm -f "$file_path" 2>/dev/null

    if [ $? -eq 0 ]; then
        WEB_LOGGER "ARCHIVE_LOG_DELETE" "ʷ־ɾ: $filename"
        retjson 0 "ɾɹ"
    else
        retjson 1 "ɾʧ"
    fi
}

# 봦
agent_activate() {
    local activation_code="${CGI_activation_code}"

    if [ -z "$activation_code" ]; then
        retjson 1 "벻Ϊ"
        return 1
    fi

    # ֤Ϸ base64 ַУ飩
    if ! echo "$activation_code" | grep -qE '^[A-Za-z0-9+/=]+$'; then
        retjson 1 "ʽȷ"
        return 1
    fi

    #  unisase-agent activate 
    local output
    output=$("$AGENT_BIN" activate "$activation_code" 2>&1)
    local exit_code=$?

    # CLI
    #  ActivationResult JSON "success" ֶΣ
    # ȡ豸кʧʱı JSON
    local success
    local error_msg

    # ȼǷ JSON ǣжǷΪ JSON ʽ
    local is_json
    is_json=$(echo "$output" | grep -c '"success"')

    if [ "$is_json" -eq 0 ]; then
        #  JSON ȡ豸кʧܣֱΪϢ
        error_msg="$output"
    else
        success=$(echo "$output" | grep -o '"success"[[:space:]]*:[[:space:]]*true' | head -1)
    fi

    if [ -n "$success" ]; then
        WEB_LOGGER "ACTIVATE" "豸ɹ"
        retjson 0 "ɹ"
    else
        #  error_msg δãJSON  success=false JSON ȡ error ֶ
        if [ -z "$error_msg" ]; then
            error_msg=$(echo "$output" | grep -o '"error"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 | sed 's/"error"[[:space:]]*:[[:space:]]*"\([^"]*\)"/\1/')
        fi
        if [ -z "$error_msg" ]; then
            error_msg="$output"
        fi

        # ӢĴϢתΪûѺõʾ
        local friendly_msg
        case "$error_msg" in
            *"get device serial number"*)
                friendly_msg="޷ȡ豸кţȷ豸" ;;
            *"device serial number mismatch"*|*"invalid activation code"*|*"failed to decrypt"*)
                friendly_msg="Ч뵱ǰ豸ƥ䣬鼤Ƿȷ" ;;
            *"unsupported activation code version"*)
                friendly_msg="汾֧֣ Agent " ;;
            *"customer ID and client ID are both 0"*)
                friendly_msg="쳣ͻվʶΪգϵԱ" ;;
            *"controller address"*)
                friendly_msg="쳣ַΪգϵԱ" ;;
            *"unknown mode"*)
                friendly_msg="쳣ģʽЧϵԱ" ;;
            *"has expired"*)
                friendly_msg="ѹڣϵԱ" ;;
            *"failed to write config"*)
                friendly_msg="дʧܣ̿ռļȨ" ;;
            *)
                friendly_msg="ʧ: $error_msg" ;;
        esac

        WEB_LOGGER "ACTIVATE_ERROR" "豸ʧ: $error_msg"
        retjson 1 "$friendly_msg"
    fi
}

# ·ɷַ
case "${CGI_action}" in
    "activate")
        agent_activate
        ;;
    "load_config")
        retjson 0 "OK" "`agent_load_config`"
        ;;
    "save_config")
        agent_save_config
        ;;
    "reset_config")
        agent_reset_config
        ;;
    "reset_log_config")
        agent_reset_log_config
        ;;
    "recover_config")
        agent_recover_config
        ;;
    "list_backups")
        retjson 0 "OK" "`agent_list_backups`"
        ;;
    "delete_backup")
        agent_delete_backup
        ;;
    "agent_start")
        agent_start
        ;;
    "agent_stop")
        agent_stop
        ;;
    "agent_restart")
        agent_restart
        ;;
    "download_log")
        agent_download_log
        ;;
    "list_archive_logs")
        retjson 0 "OK" "`agent_list_archive_logs`"
        ;;
    "download_archive_log")
        agent_download_archive_log
        ;;
    "delete_archive_log")
        agent_delete_archive_log
        ;;
    *)
        retjson 1 "UNKNOWN_ACTION!"
        ;;
esac
