#!/usr/bin/env bash

# ============================================
# IP Assignment
# ============================================

function ip::assigned() {
  grep -h "^Address" "$(ctx::clients)"/*.conf 2>/dev/null \
    | awk '{print $3}' \
    | cut -d'/' -f1
}

function ip::is_assigned() {
  local candidate="$1"
  ip::assigned | grep -q "^${candidate}$"
}

# ip::next_for_subnet <cidr>
# Finds the next unassigned host IP within a CIDR.
# Replaces ip::next_for_type for the subnet-aware allocation path.
function ip::next_for_subnet() {
  local cidr="${1:-}"
 
  if [[ -z "$cidr" ]]; then
    log::error "No subnet CIDR provided for IP allocation"
    return 1
  fi
 
  local prefix
  prefix=$(subnet::prefix "$cidr")
 
  local candidate
  for i in $(subnet::host_range "$cidr"); do
    candidate="${prefix}.${i}"
    ip::is_assigned "$candidate" || { echo "$candidate"; return 0; }
  done
 
  log::error "No available IPs in subnet ${cidr}"
  return 1
}
 

# ============================================
# Validation
# ============================================

function ip::is_valid() {
  local ip="${1:-}"
  [[ -z "$ip" ]] && return 1

  # Strip CIDR mask if present
  local addr="${ip%%/*}"

  # Structural check — 4 octets, optional /mask
  [[ "$ip" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}(/([0-9]|[1-2][0-9]|3[0-2]))?$ ]] || return 1

  # Octet range check — each must be 0-255
  local IFS='.'
  local -a octets
  read -ra octets <<< "$addr"
  for octet in "${octets[@]}"; do
    (( octet >= 0 && octet <= 255 )) || return 1
  done

  return 0
}
function ip::is_cidr() {
  [[ "$1" == *"/"* ]]
}
 
# ip::is_valid_for_subnet <cidr> <ip>
# Convenience wrapper — validates an IP against a specific subnet.
# Delegates to subnet::ip_valid_for which handles all the checks.
function ip::is_valid_for_subnet() {
  local cidr="${1:-}" ip="${2:-}"
  subnet::ip_valid_for "$cidr" "$ip"
}
 
# ip::require_valid_for_subnet <cidr> <ip>
# Errors and returns 1 if the IP is not valid for the subnet.
# Used when a manual --ip override is provided.
function ip::require_valid_for_subnet() {
  local cidr="${1:-}" ip="${2:-}"
  subnet::require_ip_valid_for "$cidr" "$ip"
}

function ip::validate() {
  local ip="$1"
  if ! ip::is_valid "$ip"; then
    log::error "Invalid IP or CIDR: ${ip}"
    return 1
  fi
  return 0
}

function ip::require_valid() {
  local ip="$1"
  ip::validate "$ip" || exit 1
}
