#!/bin/bash

# Find next available port in range (randomized).
#
# Host-bound ports that aren't tracked in the docker port table — extend
# CFG_RESERVED_PORTS_EXTRA in your config to add more (comma-separated).
# These are skipped during allocation so a randomly-picked app port can
# never collide with a host service at compose-up time.
portIsReservedHostPort()
{
    local p="$1"
    local default_reserved=(8080 6060)   # CrowdSec LAPI + Prometheus metrics
    local extra
    IFS=',' read -ra extra <<< "${CFG_RESERVED_PORTS_EXTRA:-}"
    for r in "${default_reserved[@]}" "${extra[@]}"; do
        [[ -n "$r" && "$r" == "$p" ]] && return 0
    done
    return 1
}

portFindNextAvailablePort()
{
    IFS='-' read -ra PORT_RANGE <<< "$CFG_PORT_RANGE"
    local port_start=${PORT_RANGE[0]}
    local port_end=${PORT_RANGE[1]}

    if [[ ! -f "$docker_dir/$db_file" ]]; then
        isNotice "Database not found: $docker_dir/$db_file"
        allocated_port=""
    else
        local available_port=""
        local attempts=0
        local max_attempts=50

        # Try random ports up to max_attempts
        while [[ $attempts -lt $max_attempts && -z "$available_port" ]]; do
            # Generate random port in range
            local random_port=$(( RANDOM % (port_end - port_start + 1) + port_start ))

            # Skip host-reserved ports (CrowdSec LAPI, etc.)
            if portIsReservedHostPort "$random_port"; then
                ((attempts++))
                continue
            fi

            # Check if port is available
            local check_result=$(runInstallOp sqlite3 "$docker_dir/$db_file" "SELECT 1 FROM network_resources WHERE resource_value LIKE '$random_port:%' AND resource_type='port' AND status='active' LIMIT 1" 2>/dev/null)
            if [[ -z "$check_result" ]]; then
                available_port="$random_port"
            fi

            ((attempts++))
        done

        # Fallback to sequential if random fails
        if [[ -z "$available_port" ]]; then
            isNotice "Random allocation failed, trying sequential..."
            for ((port=port_start; port<=port_end; port++)); do
                if portIsReservedHostPort "$port"; then
                    continue
                fi
                local check_result=$(runInstallOp sqlite3 "$docker_dir/$db_file" "SELECT 1 FROM network_resources WHERE resource_value LIKE '$port:%' AND resource_type='port' AND status='active' LIMIT 1" 2>/dev/null)
                if [[ -z "$check_result" ]]; then
                    available_port="$port"
                    break
                fi
            done
        fi
        
        if [[ -z "$available_port" ]]; then
            isError "No available ports found in range $CFG_PORT_RANGE"
        fi
        
        allocated_port="$available_port"
    fi
}
