#!/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}$"
}

function ip::next_for_type() {
  local type="$1"
  local subnet
  subnet=$(config::subnet_for "$type")

  if [[ -z "$subnet" ]]; then
    log::error "Unknown device type: ${type}"
    return 1
  fi

  for i in $(seq 1 254); do
    local candidate="${subnet}.${i}"
    if ! ip::is_assigned "$candidate"; then
      echo "$candidate"
      return 0
    fi
  done

  log::error "No available IPs in subnet ${subnet}.0/24"
  return 1
}

# 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"
  [[ "$ip" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}(/([0-9]|[1-2][0-9]|3[0-2]))?$ ]]
}

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
}
