#!/usr/bin/env bash

function net::exists() {
  local name="${1:?}"
  local result
  result=$(json::net_exists "$(ctx::net)" "$name")
  [[ "$result" == "true" ]]
}

function net::require_exists() {
  local name="${1:?}"
  if ! net::exists "$name"; then
    log::error "Service not found: ${name}"
    return 1
  fi
}

function net::resolve() {
  local name="${1:?}"
  json::net_resolve "$(ctx::net)" "$name"
}

function net::reverse_lookup() {
  local ip="${1:-}" port="${2:-}" proto="${3:-}"
  [[ -z "$ip" ]] && return 0
  json::net_reverse_lookup "$(ctx::net)" "$ip" "$port" "$proto"
}

function net::annotation() {
  # Returns " → service:port" or "" — for display use
  local ip="${1:-}" port="${2:-}" proto="${3:-}"
  local match
  match=$(net::reverse_lookup "$ip" "$port" "$proto")
  [[ -n "$match" ]] && echo " → ${match}" || echo ""
}

function net::annotate() {
  # Returns " → service:port-name" or "" for display use
  local entry="${1:-}"
  [[ -z "$entry" ]] && return 0

  local ann=""
  if [[ "$entry" == *:*:* ]]; then
    # ip:port:proto
    local b_ip b_port b_proto
    IFS=":" read -r b_ip b_port b_proto <<< "$entry"
    ann=$(net::reverse_lookup "$b_ip" "$b_port" "$b_proto")
  else
    # ip or ip/cidr
    local ip="${entry%%/*}"
    ann=$(net::reverse_lookup "$ip")
  fi

  [[ -n "$ann" ]] && echo "${ann}" || echo ""
}

function net::print_entry() {
  local sign="${1:-}" entry="${2:-}" indent="${3:-6}"
  local ann
  ann=$(net::annotate "$entry")
  local color
  [[ "$sign" == "+" ]] && color="\033[0;32m" || color="\033[0;31m"
  local spaces
  spaces=$(printf '%*s' "$indent" '')
  printf "%s%b%s\033[0m %-20s\033[0;37m%s\033[0m\n" \
    "$spaces" "$color" "$sign" "$entry" \
    "${ann:+  → ${ann}}"
}

function net::print_dns_redirect() {
  local ip="${1:-}" indent="${2:-6}" label="${3:-DNS}"
  local spaces
  spaces=$(printf '%*s' "$indent" '')
  local ann
  ann=$(net::annotate "$ip")
  printf "%s\033[0;36m↺\033[0m %s → %s\033[0;37m%s\033[0m\n" \
    "$spaces" "$label" "$ip" "${ann:+  → ${ann}}"
}

function net::print_dns_redirect_full() {
  # For rule::show — slightly different prefix
  local ip="${1:-}"
  local ann
  ann=$(net::annotate "$ip")
  printf "    \033[0;36m↺\033[0m Redirect all DNS → %s\033[0;37m%s\033[0m\n" \
    "$ip" "${ann:+  → ${ann}}"
}

function net::resolve_display() {
  local ip="${1:-}" port="${2:-}" proto="${3:-}"
  [[ -z "$ip" ]] && return 0
 
  # --raw flag bypass
  [[ "${_WGCTL_RAW:-false}" == "true" ]] && echo "$ip" && return 0
 
  # 1. hosts.json exact IP match
  local host_name=""
  if [[ -f "$(ctx::hosts)" ]]; then
    host_name=$(hosts::lookup_ip "$ip")
  fi
  [[ -n "$host_name" ]] && echo "$host_name" && return 0
 
  # 2. services.json match
  local svc_name=""
  svc_name=$(net::reverse_lookup "$ip" "$port" "$proto" 2>/dev/null) || true
  [[ -n "$svc_name" ]] && echo "$svc_name" && return 0
 
  # 3. Raw IP fallback
  echo "$ip"
}