#!/bin/bash
# SecuBox VHost Controller
# Nginx virtual host management for Debian
# Three-fold architecture: Components, Status, Access

VERSION="1.1.0"
CONFIG_FILE="/etc/secubox/vhost.toml"
NGINX_VHOST_DIR="/etc/nginx/sites-available"
NGINX_ENABLED_DIR="/etc/nginx/sites-enabled"
ACME_DIR="/etc/acme"
DATA_PATH="/srv/vhost"
HTPASSWD_DIR="/etc/nginx/.htpasswd"

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

log() { echo -e "${GREEN}[VHOST]${NC} $1"; }
warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
error() { echo -e "${RED}[ERROR]${NC} $1" >&2; }

# ============================================================================
# Configuration (TOML parsing)
# ============================================================================

config_get() {
    local key="$1" default="$2"
    [ -f "$CONFIG_FILE" ] && grep "^${key} *=" "$CONFIG_FILE" 2>/dev/null | head -1 | cut -d= -f2- | tr -d ' "' || echo "$default"
}

DEFAULT_DOMAIN=$(config_get "default_domain" "secubox.local")

init_dirs() {
    mkdir -p "$NGINX_VHOST_DIR" "$NGINX_ENABLED_DIR" "$ACME_DIR" "$DATA_PATH" "$HTPASSWD_DIR"
}

# ============================================================================
# VHost Management
# ============================================================================

vhost_add() {
    local domain="$1"
    local backend="$2"
    local tls_mode="${3:-off}"
    local websocket="${4:-0}"

    if [ -z "$domain" ] || [ -z "$backend" ]; then
        echo "Usage: vhostctl add <domain> <backend_url> [tls_mode] [websocket]"
        echo "  tls_mode: off, acme, manual"
        echo "  websocket: 0 or 1"
        return 1
    fi

    init_dirs

    local conf="$NGINX_VHOST_DIR/${domain}.conf"
    if [ -f "$conf" ]; then
        warn "VHost $domain already exists. Use 'update' to modify."
        return 1
    fi

    generate_vhost_config "$domain" "$backend" "$tls_mode" "$websocket"
    enable_vhost "$domain"
    log "VHost created: $domain -> $backend"
}

vhost_update() {
    local domain="$1"
    local backend="$2"
    local tls_mode="${3:-off}"
    local websocket="${4:-0}"

    if [ -z "$domain" ]; then
        echo "Usage: vhostctl update <domain> <backend_url> [tls_mode] [websocket]"
        return 1
    fi

    local conf="$NGINX_VHOST_DIR/${domain}.conf"
    if [ ! -f "$conf" ]; then
        error "VHost $domain does not exist"
        return 1
    fi

    generate_vhost_config "$domain" "$backend" "$tls_mode" "$websocket"
    log "VHost updated: $domain"
}

vhost_delete() {
    local domain="$1"

    if [ -z "$domain" ]; then
        echo "Usage: vhostctl delete <domain>"
        return 1
    fi

    rm -f "$NGINX_VHOST_DIR/${domain}.conf"
    rm -f "$NGINX_ENABLED_DIR/${domain}.conf"
    rm -f "$HTPASSWD_DIR/${domain}"
    log "VHost deleted: $domain"
}

vhost_enable() {
    local domain="$1"
    if [ -z "$domain" ]; then
        echo "Usage: vhostctl enable <domain>"
        return 1
    fi
    enable_vhost "$domain"
}

vhost_disable() {
    local domain="$1"
    if [ -z "$domain" ]; then
        echo "Usage: vhostctl disable <domain>"
        return 1
    fi
    rm -f "$NGINX_ENABLED_DIR/${domain}.conf"
    log "VHost disabled: $domain"
}

enable_vhost() {
    local domain="$1"
    local conf="$NGINX_VHOST_DIR/${domain}.conf"
    if [ -f "$conf" ]; then
        ln -sf "$conf" "$NGINX_ENABLED_DIR/${domain}.conf"
        log "VHost enabled: $domain"
    else
        error "Config not found: $conf"
        return 1
    fi
}

vhost_list() {
    echo "Virtual Hosts:"
    echo "=============="
    for conf in "$NGINX_VHOST_DIR"/*.conf; do
        [ -f "$conf" ] || continue
        local domain=$(basename "$conf" .conf)
        local enabled="disabled"
        [ -L "$NGINX_ENABLED_DIR/${domain}.conf" ] && enabled="enabled"
        local backend=$(grep -E "proxy_pass" "$conf" | head -1 | awk '{print $2}' | tr -d ';')
        local ssl="no"
        grep -q "listen 443" "$conf" && ssl="yes"
        printf "  %-30s %-10s %-6s %s\n" "$domain" "$enabled" "ssl:$ssl" "$backend"
    done
}

# ============================================================================
# Config Generation
# ============================================================================

generate_vhost_config() {
    local domain="$1"
    local backend="$2"
    local tls_mode="$3"
    local websocket="$4"
    local conf="$NGINX_VHOST_DIR/${domain}.conf"

    # Check for redirect
    if echo "$backend" | grep -q '^return [0-9]'; then
        cat > "$conf" << NGINXEOF
# Redirect for ${domain}
# Generated by SecuBox VHost Manager

server {
    listen 80;
    server_name ${domain};
    ${backend};
    access_log /var/log/nginx/${domain}_access.log;
    error_log /var/log/nginx/${domain}_error.log;
}
NGINXEOF
        return
    fi

    # Standard proxy config
    cat > "$conf" << NGINXEOF
# VHost for ${domain}
# Generated by SecuBox VHost Manager

server {
    listen 80;
    server_name ${domain};
NGINXEOF

    # TLS handling
    local ssl_active=0
    local cert_path=""
    local key_path=""

    case "$tls_mode" in
        acme)
            cert_path="$ACME_DIR/${domain}/fullchain.cer"
            key_path="$ACME_DIR/${domain}/${domain}.key"
            [ -f "$cert_path" ] && [ -f "$key_path" ] && ssl_active=1
            ;;
        manual)
            cert_path="$DATA_PATH/ssl/${domain}/fullchain.pem"
            key_path="$DATA_PATH/ssl/${domain}/privkey.pem"
            [ -f "$cert_path" ] && [ -f "$key_path" ] && ssl_active=1
            ;;
    esac

    if [ "$ssl_active" = "1" ]; then
        cat >> "$conf" << NGINXEOF
    return 301 https://\$host\$request_uri;
}

server {
    listen 443 ssl http2;
    server_name ${domain};
    ssl_certificate ${cert_path};
    ssl_certificate_key ${key_path};
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;
NGINXEOF
    fi

    # Proxy location
    cat >> "$conf" << NGINXEOF
    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;
NGINXEOF

    if [ "$websocket" = "1" ]; then
        cat >> "$conf" << NGINXEOF
        proxy_set_header Upgrade \$http_upgrade;
        proxy_set_header Connection "upgrade";
NGINXEOF
    fi

    cat >> "$conf" << NGINXEOF
        proxy_connect_timeout 60s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;
    }
    access_log /var/log/nginx/${domain}_access.log;
    error_log /var/log/nginx/${domain}_error.log;
}
NGINXEOF

    log "Config generated: $conf"
}

# ============================================================================
# Auth Management
# ============================================================================

auth_add() {
    local domain="$1"
    local username="$2"
    local password="$3"

    if [ -z "$domain" ] || [ -z "$username" ] || [ -z "$password" ]; then
        echo "Usage: vhostctl auth add <domain> <username> <password>"
        return 1
    fi

    init_dirs
    local htpasswd_file="$HTPASSWD_DIR/${domain}"
    local hash=$(openssl passwd -apr1 "$password")
    echo "${username}:${hash}" > "$htpasswd_file"
    chmod 600 "$htpasswd_file"
    log "Auth set for $domain: user $username"
}

auth_remove() {
    local domain="$1"
    if [ -z "$domain" ]; then
        echo "Usage: vhostctl auth remove <domain>"
        return 1
    fi
    rm -f "$HTPASSWD_DIR/${domain}"
    log "Auth removed for $domain"
}

# ============================================================================
# Certificate Management
# ============================================================================

cert_request() {
    local domain="$1"
    local email="${2:-admin@${domain}}"

    if [ -z "$domain" ]; then
        echo "Usage: vhostctl cert request <domain> [email]"
        return 1
    fi

    if ! command -v acme.sh >/dev/null 2>&1; then
        error "acme.sh not installed"
        echo "Install with: curl https://get.acme.sh | sh"
        return 1
    fi

    log "Requesting certificate for $domain..."
    if acme.sh --issue -d "$domain" --standalone --accountemail "$email" --force; then
        log "Certificate issued for $domain"

        # Update vhost to use new cert
        local conf="$NGINX_VHOST_DIR/${domain}.conf"
        if [ -f "$conf" ]; then
            local backend=$(grep -E "proxy_pass" "$conf" | head -1 | awk '{print $2}' | tr -d ';')
            generate_vhost_config "$domain" "$backend" "acme" "0"
        fi
    else
        error "Certificate request failed"
        return 1
    fi
}

cert_list() {
    echo "Certificates:"
    echo "============="
    if [ -d "$ACME_DIR" ]; then
        for cert_dir in "$ACME_DIR"/*/; do
            [ -d "$cert_dir" ] || continue
            local domain=$(basename "$cert_dir")
            local cert_file="$cert_dir/fullchain.cer"
            if [ -f "$cert_file" ]; then
                local expires=$(openssl x509 -in "$cert_file" -noout -enddate 2>/dev/null | cut -d= -f2)
                printf "  %-30s expires: %s\n" "$domain" "$expires"
            fi
        done
    else
        echo "  No certificates found"
    fi
}

# ============================================================================
# Migration
# ============================================================================

cmd_migrate() {
    local source="${1:-192.168.255.1}"

    log "Migrating VHosts from $source..."

    # Check SSH connectivity
    if ! ssh -o ConnectTimeout=5 "root@$source" "echo ok" >/dev/null 2>&1; then
        error "Cannot connect to $source via SSH"
        echo "Ensure SSH key is configured: ssh-copy-id root@$source"
        return 1
    fi

    # Create backup directory
    local backup_dir="$DATA_PATH/migration_$(date +%Y%m%d_%H%M%S)"
    mkdir -p "$backup_dir"

    # Export UCI config
    log "Exporting VHost configuration..."
    ssh "root@$source" "uci export vhosts" > "$backup_dir/vhosts.uci" 2>/dev/null || true

    # Copy nginx configs
    log "Copying nginx configs..."
    rsync -avz --progress "root@$source:/etc/nginx/conf.d/*.conf" "$NGINX_VHOST_DIR/" 2>/dev/null || true

    # Copy ACME certificates
    log "Copying certificates..."
    rsync -avz --progress "root@$source:/etc/acme/" "$ACME_DIR/" 2>/dev/null || true

    # Import UCI vhosts
    if [ -f "$backup_dir/vhosts.uci" ]; then
        log "Converting UCI vhosts to nginx configs..."
        while read -r line; do
            case "$line" in
                *"option domain"*)
                    domain=$(echo "$line" | grep -oP "'\K[^']+")
                    ;;
                *"option upstream"*)
                    backend=$(echo "$line" | grep -oP "'\K[^']+")
                    ;;
                *"option tls"*)
                    tls_mode=$(echo "$line" | grep -oP "'\K[^']+")
                    ;;
                *"option websocket"*)
                    websocket=$(echo "$line" | grep -oP "'\K[^']+" | grep -q "1" && echo "1" || echo "0")
                    ;;
                "config vhost"*)
                    # Start of new vhost, reset vars
                    domain="" backend="" tls_mode="off" websocket="0"
                    ;;
                "")
                    # End of section, create vhost if valid
                    if [ -n "$domain" ] && [ -n "$backend" ]; then
                        vhost_add "$domain" "$backend" "$tls_mode" "$websocket"
                    fi
                    ;;
            esac
        done < "$backup_dir/vhosts.uci"
    fi

    # Enable imported vhosts
    for conf in "$NGINX_VHOST_DIR"/*.conf; do
        [ -f "$conf" ] || continue
        local domain=$(basename "$conf" .conf)
        enable_vhost "$domain"
    done

    log "Migration complete!"
    log "Data backed up to: $backup_dir"
    log "Reload nginx: systemctl reload nginx"
}

# ============================================================================
# THREE-FOLD ARCHITECTURE: Components (What)
# ============================================================================

cmd_components() {
    local nginx_running=false
    pgrep nginx >/dev/null 2>&1 && nginx_running=true

    local acme_installed=false
    command -v acme.sh >/dev/null 2>&1 && acme_installed=true

    local vhost_count=0
    for conf in "$NGINX_VHOST_DIR"/*.conf; do
        [ -f "$conf" ] && vhost_count=$((vhost_count + 1))
    done

    local cert_count=0
    if [ -d "$ACME_DIR" ]; then
        for cert_dir in "$ACME_DIR"/*/; do
            [ -d "$cert_dir" ] && [ -f "$cert_dir/fullchain.cer" ] && cert_count=$((cert_count + 1))
        done
    fi

    cat <<EOF
{
  "components": [
    {
      "name": "Nginx Web Server",
      "type": "service",
      "description": "HTTP/HTTPS reverse proxy",
      "installed": true,
      "running": $nginx_running,
      "version": "$(nginx -v 2>&1 | grep -o '[0-9.]*' | head -1)"
    },
    {
      "name": "ACME Client",
      "type": "tool",
      "description": "Let's Encrypt certificate automation",
      "installed": $acme_installed,
      "running": false
    },
    {
      "name": "VHost Configs",
      "type": "config",
      "path": "$NGINX_VHOST_DIR",
      "description": "Virtual host configurations",
      "count": $vhost_count
    },
    {
      "name": "SSL Certificates",
      "type": "certs",
      "path": "$ACME_DIR",
      "description": "Let's Encrypt certificates",
      "count": $cert_count
    }
  ]
}
EOF
}

# ============================================================================
# THREE-FOLD ARCHITECTURE: Access (How to connect)
# ============================================================================

cmd_access() {
    local vhosts_json="["
    local first=true

    for conf in "$NGINX_VHOST_DIR"/*.conf; do
        [ -f "$conf" ] || continue
        local domain=$(basename "$conf" .conf)
        local enabled=false
        [ -L "$NGINX_ENABLED_DIR/${domain}.conf" ] && enabled=true
        local backend=$(grep -E "proxy_pass" "$conf" 2>/dev/null | head -1 | awk '{print $2}' | tr -d ';')
        local ssl=false
        grep -q "listen 443" "$conf" 2>/dev/null && ssl=true

        [ "$first" = "false" ] && vhosts_json+=","
        first=false
        vhosts_json+="{\"domain\":\"$domain\",\"enabled\":$enabled,\"ssl\":$ssl,\"backend\":\"$backend\"}"
    done
    vhosts_json+="]"

    cat <<EOF
{
  "nginx_status_url": "http://localhost/nginx_status",
  "admin_panel": "/vhost/",
  "vhosts": $vhosts_json,
  "management": {
    "add": "vhostctl add <domain> <backend> [acme|manual|off] [websocket:0|1]",
    "cert": "vhostctl cert request <domain>",
    "list": "vhostctl list"
  }
}
EOF
}

# ============================================================================
# Commands
# ============================================================================

cmd_reload() {
    if nginx -t >/dev/null 2>&1; then
        systemctl reload nginx
        log "Nginx reloaded"
    else
        error "Nginx config invalid"
        nginx -t
        return 1
    fi
}

cmd_status() {
    echo ""
    echo "VHost Manager v$VERSION"
    echo "======================"
    echo ""

    echo "Nginx:"
    if pgrep nginx >/dev/null 2>&1; then
        echo -e "  Status: ${GREEN}Running${NC}"
        echo "  Version: $(nginx -v 2>&1 | grep -o 'nginx/[0-9.]*' | cut -d/ -f2)"
    else
        echo -e "  Status: ${RED}Stopped${NC}"
    fi

    echo ""
    echo "ACME:"
    if command -v acme.sh >/dev/null 2>&1; then
        echo -e "  Available: ${GREEN}Yes${NC}"
        echo "  Version: $(acme.sh --version 2>/dev/null | head -1)"
    else
        echo -e "  Available: ${RED}No${NC}"
    fi

    local count=0
    for conf in "$NGINX_VHOST_DIR"/*.conf; do
        [ -f "$conf" ] && count=$((count + 1))
    done
    echo ""
    echo "VHosts: $count"
    echo ""
}

show_help() {
    cat << EOF
SecuBox VHost Manager v$VERSION
Three-fold architecture: Components, Status, Access

Usage: vhostctl <command> [options]

Information (Three-fold):
  components                           List system components (JSON)
  status                               Show service status
  access                               Show vhosts and access info (JSON)

VHost Management:
  add <domain> <backend> [tls] [ws]   Add vhost (tls: off/acme/manual, ws: 0/1)
  update <domain> <backend> [tls] [ws] Update vhost
  delete <domain>                      Delete vhost
  enable <domain>                      Enable vhost
  disable <domain>                     Disable vhost
  list                                 List all vhosts

Authentication:
  auth add <domain> <user> <pass>      Set basic auth
  auth remove <domain>                 Remove basic auth

Certificates:
  cert request <domain> [email]        Request Let's Encrypt cert
  cert list                            List certificates

Service:
  reload                               Reload nginx
  migrate [host]                       Migrate from OpenWrt

Examples:
  vhostctl components                  # JSON list of components
  vhostctl access                      # JSON list of vhosts
  vhostctl add app.example.com http://localhost:3000
  vhostctl add secure.example.com http://localhost:8080 acme 1
  vhostctl cert request secure.example.com admin@example.com

EOF
}

# ============================================================================
# Main
# ============================================================================

init_dirs

case "${1:-}" in
    # Three-fold architecture
    components) cmd_components ;;
    access)     cmd_access ;;
    status)     shift; cmd_status "$@" ;;
    # VHost management
    add)        shift; vhost_add "$@" ;;
    update)     shift; vhost_update "$@" ;;
    delete)     shift; vhost_delete "$@" ;;
    enable)     shift; vhost_enable "$@" ;;
    disable)    shift; vhost_disable "$@" ;;
    list)       shift; vhost_list "$@" ;;
    # Auth
    auth)
        shift
        case "$1" in
            add) shift; auth_add "$@" ;;
            remove) shift; auth_remove "$@" ;;
            *) echo "Usage: vhostctl auth add|remove ..." ;;
        esac
        ;;
    # Certificates
    cert)
        shift
        case "$1" in
            request) shift; cert_request "$@" ;;
            list) shift; cert_list "$@" ;;
            *) echo "Usage: vhostctl cert request|list ..." ;;
        esac
        ;;
    # Service
    reload)     shift; cmd_reload "$@" ;;
    migrate)    shift; cmd_migrate "$@" ;;
    # Help
    help|--help|-h|'') show_help ;;
    *)          error "Unknown: $1"; exit 1 ;;
esac

exit 0
