#!/bin/sh
# /usr/libexec/rpcd/vhost-manager
# RPCD backend for VHost Manager module
# Provides ubus interface: luci.vhost-manager

. /lib/functions.sh
. /usr/share/libubox/jshn.sh

# Configuration
UCI_CONFIG="vhost_manager"
NGINX_VHOSTS_DIR="/etc/nginx/conf.d"
ACME_DIR="/etc/acme"

# Helper: Check if nginx is running
nginx_running() {
    pgrep -x nginx > /dev/null 2>&1
}

# Helper: Get nginx status
get_nginx_status() {
    if nginx_running; then
        echo "running"
    else
        echo "stopped"
    fi
}

# Helper: Count vhosts
count_vhosts() {
    if [ -d "$NGINX_VHOSTS_DIR" ]; then
        ls -1 "$NGINX_VHOSTS_DIR"/*.conf 2>/dev/null | wc -l
    else
        echo "0"
    fi
}

# Helper: List vhosts
list_vhosts() {
    json_add_array "vhosts"
    
    if [ -d "$NGINX_VHOSTS_DIR" ]; then
        for conf in "$NGINX_VHOSTS_DIR"/*.conf; do
            [ -f "$conf" ] || continue
            
            # Extract server_name from config
            SERVER_NAME=$(grep -m1 "server_name" "$conf" | awk '{print $2}' | tr -d ';')
            PROXY_PASS=$(grep -m1 "proxy_pass" "$conf" | awk '{print $2}' | tr -d ';')
            SSL_ENABLED="false"
            
            if grep -q "ssl_certificate" "$conf"; then
                SSL_ENABLED="true"
            fi
            
            json_add_object ""
            json_add_string "name" "$(basename "$conf" .conf)"
            json_add_string "domain" "$SERVER_NAME"
            json_add_string "backend" "$PROXY_PASS"
            json_add_boolean "ssl" "$SSL_ENABLED"
            json_add_boolean "enabled" 1
            json_close_object
        done
    fi
    
    json_close_array
}

# Helper: Get SSL certificates
list_certificates() {
    json_add_array "certificates"
    
    if [ -d "$ACME_DIR" ]; then
        for cert_dir in "$ACME_DIR"/*/; do
            [ -d "$cert_dir" ] || continue
            
            DOMAIN=$(basename "$cert_dir")
            CERT_FILE="$cert_dir/fullchain.cer"
            
            if [ -f "$CERT_FILE" ]; then
                # Get expiry date
                EXPIRY=$(openssl x509 -enddate -noout -in "$CERT_FILE" 2>/dev/null | cut -d= -f2)
                
                json_add_object ""
                json_add_string "domain" "$DOMAIN"
                json_add_string "expiry" "$EXPIRY"
                json_add_boolean "valid" 1
                json_close_object
            fi
        done
    fi
    
    json_close_array
}

# Initialize JSON
json_init

case "$1" in
    list)
        # List available methods
        json_add_object "status"
        json_close_object
        
        json_add_object "get_vhosts"
        json_close_object
        
        json_add_object "get_vhost"
            json_add_string "name" "string"
        json_close_object
        
        json_add_object "add_vhost"
            json_add_string "domain" "string"
            json_add_string "backend" "string"
            json_add_boolean "ssl" false
        json_close_object
        
        json_add_object "delete_vhost"
            json_add_string "name" "string"
        json_close_object
        
        json_add_object "get_certificates"
        json_close_object
        
        json_add_object "request_certificate"
            json_add_string "domain" "string"
        json_close_object
        
        json_add_object "reload_nginx"
        json_close_object
        
        json_add_object "test_config"
        json_close_object
        
        json_dump
        ;;
    
    call)
        case "$2" in
            status)
                # Return module status
                json_add_string "module" "vhost-manager"
                json_add_string "version" "2.0.0"
                json_add_string "nginx_status" "$(get_nginx_status)"
                json_add_boolean "nginx_running" $(nginx_running && echo 1 || echo 0)
                json_add_int "vhost_count" "$(count_vhosts)"
                json_add_string "config_dir" "$NGINX_VHOSTS_DIR"
                json_add_string "acme_dir" "$ACME_DIR"
                
                # Check nginx version
                if command -v nginx > /dev/null 2>&1; then
                    NGINX_VERSION=$(nginx -v 2>&1 | cut -d/ -f2)
                    json_add_string "nginx_version" "$NGINX_VERSION"
                fi
                
                json_dump
                ;;
            
            get_vhosts)
                # Return list of vhosts
                list_vhosts
                json_dump
                ;;
            
            get_vhost)
                # Get single vhost details
                read -r input
                json_load "$input"
                json_get_var vhost_name name
                
                CONF_FILE="$NGINX_VHOSTS_DIR/${vhost_name}.conf"
                
                if [ -f "$CONF_FILE" ]; then
                    json_add_boolean "found" 1
                    json_add_string "name" "$vhost_name"
                    json_add_string "config" "$(cat "$CONF_FILE")"
                else
                    json_add_boolean "found" 0
                    json_add_string "error" "VHost not found"
                fi
                
                json_dump
                ;;
            
            add_vhost)
                # Add new vhost
                read -r input
                json_load "$input"
                json_get_var domain domain
                json_get_var backend backend
                json_get_var ssl ssl
                
                # Validate
                if [ -z "$domain" ] || [ -z "$backend" ]; then
                    json_init
                    json_add_boolean "success" 0
                    json_add_string "error" "Domain and backend are required"
                    json_dump
                    exit 0
                fi
                
                # Create config
                VHOST_NAME=$(echo "$domain" | tr '.' '-')
                CONF_FILE="$NGINX_VHOSTS_DIR/${VHOST_NAME}.conf"
                
                mkdir -p "$NGINX_VHOSTS_DIR"
                
                cat > "$CONF_FILE" << NGINX_EOF
server {
    listen 80;
    listen [::]:80;
    server_name $domain;
    
    location / {
        proxy_pass $backend;
        proxy_http_version 1.1;
        proxy_set_header Host \$host;
        proxy_set_header X-Real-IP \$remote_addr;
        proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto \$scheme;
        proxy_set_header Upgrade \$http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}
NGINX_EOF
                
                json_init
                json_add_boolean "success" 1
                json_add_string "message" "VHost created"
                json_add_string "config_file" "$CONF_FILE"
                json_dump
                ;;
            
            delete_vhost)
                # Delete vhost
                read -r input
                json_load "$input"
                json_get_var vhost_name name
                
                CONF_FILE="$NGINX_VHOSTS_DIR/${vhost_name}.conf"
                
                if [ -f "$CONF_FILE" ]; then
                    rm -f "$CONF_FILE"
                    json_init
                    json_add_boolean "success" 1
                    json_add_string "message" "VHost deleted"
                else
                    json_init
                    json_add_boolean "success" 0
                    json_add_string "error" "VHost not found"
                fi
                
                json_dump
                ;;
            
            get_certificates)
                # List SSL certificates
                list_certificates
                json_dump
                ;;
            
            request_certificate)
                # Request Let's Encrypt certificate
                read -r input
                json_load "$input"
                json_get_var domain domain
                
                if [ -z "$domain" ]; then
                    json_init
                    json_add_boolean "success" 0
                    json_add_string "error" "Domain is required"
                    json_dump
                    exit 0
                fi
                
                # Check if acme.sh is available
                if command -v acme.sh > /dev/null 2>&1; then
                    # Request certificate (async - just start the process)
                    acme.sh --issue -d "$domain" --webroot /www --keylength ec-256 &
                    
                    json_init
                    json_add_boolean "success" 1
                    json_add_string "message" "Certificate request started"
                    json_add_string "domain" "$domain"
                else
                    json_init
                    json_add_boolean "success" 0
                    json_add_string "error" "acme.sh not installed"
                fi
                
                json_dump
                ;;
            
            reload_nginx)
                # Reload nginx configuration
                if nginx -t > /dev/null 2>&1; then
                    /etc/init.d/nginx reload
                    json_add_boolean "success" 1
                    json_add_string "message" "Nginx reloaded"
                else
                    json_add_boolean "success" 0
                    json_add_string "error" "Configuration test failed"
                    json_add_string "details" "$(nginx -t 2>&1)"
                fi
                json_dump
                ;;
            
            test_config)
                # Test nginx configuration
                TEST_OUTPUT=$(nginx -t 2>&1)
                TEST_RESULT=$?
                
                if [ $TEST_RESULT -eq 0 ]; then
                    json_add_boolean "valid" 1
                    json_add_string "message" "Configuration OK"
                else
                    json_add_boolean "valid" 0
                    json_add_string "error" "$TEST_OUTPUT"
                fi
                json_dump
                ;;
            
            *)
                # Unknown method
                json_add_int "error" -32601
                json_add_string "message" "Method not found: $2"
                json_dump
                ;;
        esac
        ;;
    
    *)
        echo "Usage: $0 {list|call}"
        exit 1
        ;;
esac
