#!/bin/bash
# Caddy Manager - Add/remove/list HTTPS reverse proxy sites
# Usage: caddy-manager.sh <command> [args]

CADDYFILE="/etc/caddy/Caddyfile"
DEFAULT_DOMAIN="dev.apps.symph.co"
PORT_STATE_FILE="/home/aria/.openclaw/workspace/agency/infra/caddy-ports.json"

# Port allocation range
# 3001-3100: permanent dev app ports (tracked in caddy-ports.json)
# 3100-3199: landing pages
# 3200-3299: ephemeral worktree copilot sessions (auto-released)
PORT_MIN=3001
PORT_MAX=3299

# Initialize port state file if it doesn't exist
init_port_state() {
    if [[ ! -f "$PORT_STATE_FILE" ]]; then
        echo '{"allocated":{}}' > "$PORT_STATE_FILE"
    fi
}

# Get next available port
get_next_port() {
    init_port_state
    for port in $(seq $PORT_MIN $PORT_MAX); do
        if ! grep -q "\"$port\"" "$PORT_STATE_FILE" 2>/dev/null; then
            echo "$port"
            return 0
        fi
    done
    echo ""
    return 1
}

# Allocate a port for a subdomain
allocate_port() {
    local subdomain="$1"
    local port="$2"
    init_port_state
    
    # Use jq if available, otherwise use sed
    if command -v jq &> /dev/null; then
        local tmp=$(mktemp)
        jq ".allocated[\"$subdomain\"] = $port" "$PORT_STATE_FILE" > "$tmp" && mv "$tmp" "$PORT_STATE_FILE"
    else
        # Simple sed-based approach
        sed -i "s/\"allocated\":{/\"allocated\":{\"$subdomain\":$port,/" "$PORT_STATE_FILE"
        sed -i 's/,}/}/' "$PORT_STATE_FILE"
    fi
}

# Release a port for a subdomain
release_port() {
    local subdomain="$1"
    init_port_state
    
    if command -v jq &> /dev/null; then
        local tmp=$(mktemp)
        jq "del(.allocated[\"$subdomain\"])" "$PORT_STATE_FILE" > "$tmp" && mv "$tmp" "$PORT_STATE_FILE"
    else
        sed -i "s/\"$subdomain\":[0-9]*,//" "$PORT_STATE_FILE"
        sed -i "s/,\"$subdomain\":[0-9]*//" "$PORT_STATE_FILE"
    fi
}

# List allocated ports
list_ports() {
    init_port_state
    echo "📊 Port Allocation (${PORT_MIN}-${PORT_MAX}):"
    echo "---"
    if command -v jq &> /dev/null; then
        jq -r '.allocated | to_entries[] | "  \(.key): \(.value)"' "$PORT_STATE_FILE" 2>/dev/null
    else
        grep -oE '"[^"]+": ?[0-9]+' "$PORT_STATE_FILE" | sed 's/"//g' | sed 's/:/: /' | sed 's/^/  /'
    fi
    
    local used=$(grep -oE ':[0-9]+' "$PORT_STATE_FILE" 2>/dev/null | wc -l)
    local available=$((PORT_MAX - PORT_MIN + 1 - used))
    echo "---"
    echo "  Used: $used / $((PORT_MAX - PORT_MIN + 1))"
    echo "  Available: $available"
}

list_sites() {
    echo "📋 Configured sites:"
    echo "---"
    grep -E "^[a-zA-Z0-9].*\{" "$CADDYFILE" 2>/dev/null | sed 's/ {//' | while read -r site; do
        port=$(grep -A1 "^${site} {" "$CADDYFILE" | grep reverse_proxy | awk '{print $NF}' | sed 's/localhost://')
        echo "  🔗 https://${site} → localhost:${port}"
    done
    echo "---"
}

add_site() {
    local subdomain="$1"
    local port="$2"
    local domain="${3:-$DEFAULT_DOMAIN}"
    local is_worktree="${4:-false}"  # "true" = ephemeral worktree session; blocks direct browser access
    local full_domain="${subdomain}.${domain}"
    
    if [[ -z "$subdomain" ]]; then
        echo "❌ Usage: caddy-manager.sh add <subdomain> [port] [domain]"
        echo "   Example: caddy-manager.sh add myapp"
        echo "   Example: caddy-manager.sh add myapp 3005"
        exit 1
    fi
    
    # Auto-allocate port if not specified
    if [[ -z "$port" ]]; then
        port=$(get_next_port)
        if [[ -z "$port" ]]; then
            echo "❌ No available ports in range ${PORT_MIN}-${PORT_MAX}!"
            echo "   Run 'caddy-manager.sh ports' to see allocation"
            exit 1
        fi
        echo "🎯 Auto-allocated port: $port"
    fi
    
    # Validate port is in range
    if [[ "$port" -lt "$PORT_MIN" || "$port" -gt "$PORT_MAX" ]]; then
        echo "⚠️  Warning: Port $port is outside allocated range (${PORT_MIN}-${PORT_MAX})"
        read -p "   Continue anyway? [y/N] " -n 1 -r
        echo
        if [[ ! $REPLY =~ ^[Yy]$ ]]; then
            exit 1
        fi
    fi
    
    # Check if site already exists
    if grep -q "^${full_domain} {" "$CADDYFILE" 2>/dev/null; then
        echo "⚠️  Site ${full_domain} already exists!"
        echo "   Use 'remove' first if you want to update it."
        exit 1
    fi
    
    # Add the new site block
    echo "" | sudo tee -a "$CADDYFILE" > /dev/null
    echo "# ${subdomain}" | sudo tee -a "$CADDYFILE" > /dev/null
    echo "${full_domain} {" | sudo tee -a "$CADDYFILE" > /dev/null
    echo "    import security_headers" | sudo tee -a "$CADDYFILE" > /dev/null
    echo "    import offline_fallback" | sudo tee -a "$CADDYFILE" > /dev/null
    echo "    import access_log" | sudo tee -a "$CADDYFILE" > /dev/null
    if [[ "$is_worktree" == "true" ]]; then
        # Worktree mode: override X-Frame-Options (set by security_headers to SAMEORIGIN)
        # CSP frame-ancestors in Next.js already controls framing — XFO would block the symphony.symph.co iframe
        echo "    header -X-Frame-Options" | sudo tee -a "$CADDYFILE" > /dev/null
        # Strip CSP from app response — worktree apps often set frame-ancestors 'self'
        # which would block the symphony.symph.co preview iframe
        # Worktree mode: require valid Symphony session via forward_auth
        echo "    # Require Symphony auth — blocks direct access without a valid session" | sudo tee -a "$CADDYFILE" > /dev/null
        echo "    forward_auth localhost:4000 {" | sudo tee -a "$CADDYFILE" > /dev/null
        echo "        uri /api/copilot-worktree/validate" | sudo tee -a "$CADDYFILE" > /dev/null
        echo "        copy_headers Cookie" | sudo tee -a "$CADDYFILE" > /dev/null
        echo "    }" | sudo tee -a "$CADDYFILE" > /dev/null
    fi
    if [[ "$is_worktree" == "true" ]]; then
        # Strip CSP frame-ancestors from app response so symphony.symph.co iframe works
        echo "    reverse_proxy localhost:${port} {" | sudo tee -a "$CADDYFILE" > /dev/null
        echo "        header_down -Content-Security-Policy" | sudo tee -a "$CADDYFILE" > /dev/null
        echo "    }" | sudo tee -a "$CADDYFILE" > /dev/null
    else
        echo "    reverse_proxy localhost:${port}" | sudo tee -a "$CADDYFILE" > /dev/null
    fi
    echo "}" | sudo tee -a "$CADDYFILE" > /dev/null
    
    # Track port allocation
    allocate_port "$subdomain" "$port"
    
    # Reload Caddy
    sudo systemctl reload caddy
    
    echo "✅ Added: https://${full_domain} → localhost:${port}"
    echo "🔄 Caddy reloaded - SSL cert will be issued automatically"
}

remove_site() {
    local subdomain="$1"
    local domain="${2:-$DEFAULT_DOMAIN}"
    local full_domain="${subdomain}.${domain}"
    
    if [[ -z "$subdomain" ]]; then
        echo "❌ Usage: caddy-manager.sh remove <subdomain> [domain]"
        exit 1
    fi
    
    # Check if site exists
    if ! grep -q "^${full_domain} {" "$CADDYFILE" 2>/dev/null; then
        echo "⚠️  Site ${full_domain} not found in Caddyfile"
        exit 1
    fi
    
    # Remove the site block (including comment line before it)
    sudo sed -i "/^# ${subdomain}$/,/^}$/d" "$CADDYFILE"
    # Also try without comment
    sudo sed -i "/^${full_domain} {$/,/^}$/d" "$CADDYFILE"
    # Clean up empty lines
    sudo sed -i '/^$/N;/^\n$/d' "$CADDYFILE"
    
    # Release port allocation
    release_port "$subdomain"
    
    # Reload Caddy
    sudo systemctl reload caddy
    
    echo "✅ Removed: ${full_domain}"
    echo "🔄 Caddy reloaded"
}

show_caddyfile() {
    echo "📄 Caddyfile contents:"
    echo "---"
    cat "$CADDYFILE"
    echo "---"
}

reload_caddy() {
    sudo systemctl reload caddy
    echo "🔄 Caddy reloaded"
    sudo systemctl status caddy --no-pager | head -5
}

# Main
case "$1" in
    list)
        list_sites
        ;;
    add)
        # Support: add <subdomain> <port> [worktree]
        # "worktree" flag generates a Caddy block that blocks direct browser access
        is_worktree="false"
        if [[ "$4" == "worktree" || "$4" == "--worktree" ]]; then
            is_worktree="true"
        fi
        add_site "$2" "$3" "" "$is_worktree"
        ;;
    remove)
        remove_site "$2" "$3"
        ;;
    show)
        show_caddyfile
        ;;
    reload)
        reload_caddy
        ;;
    ports)
        list_ports
        ;;
    *)
        echo "🔒 Caddy Manager"
        echo ""
        echo "Usage: caddy-manager.sh <command> [args]"
        echo ""
        echo "Commands:"
        echo "  list                         List all configured sites"
        echo "  add <subdomain> [port] [worktree]  Add new site; use 'worktree' flag to restrict to iframe-only access"
        echo "  remove <subdomain>           Remove a site"
        echo "  show                         Show Caddyfile contents"
        echo "  reload                       Reload Caddy configuration"
        echo "  ports                        Show port allocation status"
        echo ""
        echo "Default domain: ${DEFAULT_DOMAIN}"
        echo "Port range: ${PORT_MIN}-${PORT_MAX}"
        ;;
esac
