#!/bin/bash

portLookupExisting()
{
    local app_name="$1"
    local service_name="$2"
    local row
    row=$(runInstallOp sqlite3 "$docker_dir/$db_file" \
        "SELECT resource_value FROM network_resources \
         WHERE app_name='$app_name' AND resource_type='port' \
           AND service_name='$service_name' AND status='active' LIMIT 1;" 2>/dev/null)
    [[ -z "$row" ]] 
    echo "${row%%:*}"
}

portAllocate()
{
    local app_name="$1"

    if [[ ${#port_config_data[@]} -eq 0 ]]; then
        local existing_services=$(runInstallOp sqlite3 "$docker_dir/$db_file" "SELECT service_name FROM network_resources WHERE app_name='$app_name' AND resource_type='port' AND service_name LIKE '${app_name}_service_%' AND status='active';" 2>/dev/null)

        local service_num=1
        if [[ -n "$existing_services" ]]; then
            while echo "$existing_services" | grep -q "${app_name}_service_${service_num}"; do
                ((service_num++))
            done
        fi
        local service_name="${app_name}_service_${service_num}"

        local existing_port
        if existing_port=$(portLookupExisting "$app_name" "$service_name"); then
            allocated_port="$existing_port"
        else
            portFindNextAvailablePort
        fi

        if [[ -z "$allocated_port" ]]; then
            allocated_ports=""
        else
            portStoreMapping "$app_name" "$service_name" "$allocated_port:private:tcp"
            allocated_ports="$allocated_port:private:tcp"
        fi
    else
        local service_mappings=()

        for i in "${!port_service_names[@]}"; do
            local full_service_name="${app_name}_${port_service_names[$i]}"

            if [[ "${port_external_ports[$i]}" == "random" ]]; then
                local existing_external_port=""
                if [[ "$LIBREPORTAL_RESET_NETWORK" != "1" ]]; then
                    existing_external_port=$(portLookupExisting "$app_name" "$full_service_name")
                fi

                if [[ -n "$existing_external_port" ]]; then
                    local allocated_external_port="$existing_external_port"
                else
                    portFindNextAvailablePort
                    if [[ -z "$allocated_port" ]]; then
                        isError "Failed to allocate random external port for ${port_service_names[$i]}"
                        continue
                    fi
                    local allocated_external_port="$allocated_port"
                fi
            else
                local allocated_external_port="${port_external_ports[$i]}"
            fi

            # `disabled` is a legitimate access type — the user is opting the
            # port out of host exposure. Skip allocation silently rather than
            # spamming "Invalid access type" once per port per dispatch.
            if [[ "${port_access_types[$i]}" == "disabled" ]]; then
                continue
            fi
            if [[ "${port_access_types[$i]}" != "public" && "${port_access_types[$i]}" != "private" ]]; then
                isNotice "Invalid access type '${port_access_types[$i]}' for ${port_service_names[$i]}. Use: public, private or disabled"
                continue
            fi

            if [[ "${port_protocols[$i]}" != "tcp" && "${port_protocols[$i]}" != "udp" ]]; then
                isNotice "Invalid protocol '${port_protocols[$i]}' for ${port_service_names[$i]}. Use: tcp or udp"
                continue
            fi

            portStoreMapping "$app_name" "$full_service_name" "$allocated_external_port:${port_internal_ports[$i]}:${port_access_types[$i]}:${port_protocols[$i]}" "${port_parent_services[$i]}"

            service_mappings+=("$full_service_name:${port_data_tags[$i]}:$allocated_external_port:${port_internal_ports[$i]}:${port_access_types[$i]}:${port_protocols[$i]}:${port_url_accessibles[$i]}:${port_labels[$i]}")
        done

        # Join with SOH so labels containing `,` or spaces don't fragment.
        local SEP=$'\x01'
        local service_result=""
        for i in "${!service_mappings[@]}"; do
            if [[ $i -eq 0 ]]; then
                service_result="${service_mappings[$i]}"
            else
                service_result="${service_result}${SEP}${service_mappings[$i]}"
            fi
        done

        allocated_ports=$service_result
    fi
}
