#!/bin/bash
#
# x-localip: script to display the local IP addresses of the system
#
# Author: Ismo Vuorinen <https://github.com/ivuorinen>
# License: MIT

VERSION="1.0.0"
SCRIPT_NAME="$(basename "$0")"

# Function to display usage
usage()
{
  echo "Usage: $SCRIPT_NAME [options] [interface]"
  echo "Options:"
  echo "  --help          Show this help message"
  echo "  --version       Show version information"
  echo "  --ipv4          Show only IPv4 addresses"
  echo "  --ipv6          Show only IPv6 addresses"
  echo "If an interface is specified, only the IP address of that interface will be returned."
}

# Initialize flags for filtering
show_ipv4=true
show_ipv6=true

# Check for arguments
while [[ $# -gt 0 ]]; do
  case $1 in
    --help)
      usage
      exit 0
      ;;
    --version)
      echo "$SCRIPT_NAME version $VERSION"
      exit 0
      ;;
    --ipv4)
      show_ipv6=false
      ;;
    --ipv6)
      show_ipv4=false
      ;;
    *)
      iface=$1
      ;;
  esac
  shift
done

declare -a interfaces

# Detect platform (macOS or Linux)
platform="$(uname)"
if [[ $platform == "Darwin" ]]; then
  read -r -a interfaces <<< "$(ifconfig -lu | grep -v '^bridge')"
elif [[ $platform == "Linux" ]]; then
  read -r -a interfaces <<< "$(ip link show | awk -F: '/^[0-9]+:/{print $2}' | tr -d ' ' | grep -v '^bridge')"
else
  echo "Error: Unsupported platform. Only macOS and Linux are supported."
  exit 1
fi

# Function to fetch IP addresses for an interface
fetch_ips()
{
  iface="$1"
  local ipv4 ipv6
  if [[ $platform == "Darwin" ]]; then
    ipv4=$(ipconfig getifaddr "$iface" 2> /dev/null || echo "")
    ipv6=$(ipconfig getifaddr -v6 "$iface" 2> /dev/null || echo "")
  else
    ipv4=$(ip -4 addr show "$iface" 2> /dev/null | awk '/inet / {print $2}' || echo "")
    ipv6=$(ip -6 addr show "$iface" 2> /dev/null | awk '/inet6 / {print $2}' || echo "")
  fi
  if [[ -n $ipv4 || -n $ipv6 ]]; then
    echo "$iface:$ipv4:$ipv6"
  fi
}

# Determine maximum lengths for formatting
max_iface_length=9 # "Interface" length
max_ipv4_length=11 # "IPv4 Address" length
max_ipv6_length=11 # "IPv6 Address" length

interface_ip_list=()
for iface in "${interfaces[@]}"; do
  result=$(fetch_ips "$iface")
  if [[ -n $result ]]; then
    interface_ip_list+=("$result")
  fi
done

interface_ip_list_array=()
for entry in "${interface_ip_list[@]}"; do
  IFS=: read -r iface ipv4 ipv6 <<< "$entry"
  [[ ${#iface} -gt $max_iface_length ]] && max_iface_length=${#iface}
  [[ ${#ipv4} -gt $max_ipv4_length ]] && max_ipv4_length=${#ipv4}
  [[ ${#ipv6} -gt $max_ipv6_length ]] && max_ipv6_length=${#ipv6}
  interface_ip_list_array+=("$iface:$ipv4:$ipv6")
done

# Print headers
printf "%-${max_iface_length}s : %-${max_ipv4_length}s : %-${max_ipv6_length}s\n" "Interface" "IPv4 Address" "IPv6 Address"
printf "%0.s-" $(seq 1 $((max_iface_length + max_ipv4_length + max_ipv6_length + 6)))
printf "\n"

# Print the results in a formatted table
for entry in "${interface_ip_list_array[@]}"; do
  # Split the entry into interface, IPv4, and IPv6
  iface="${entry%%:*}"
  rest="${entry#*:}"
  ipv4="${rest%%:*}"
  ipv6="${rest#*:}"

  # Skip IPv4 or IPv6 as per the flags
  ipv4_display=$([[ $show_ipv4 == true ]] && echo "$ipv4" || echo "")
  ipv6_display=$([[ $show_ipv6 == true ]] && echo "$ipv6" || echo "")

  # Print the interface name, padded to max_iface_length, followed by the IPs
  printf "%-${max_iface_length}s" "$iface"
  if $show_ipv4; then
    printf " : %-${max_ipv4_length}s" "$ipv4_display"
  fi
  if $show_ipv6; then
    printf " : %-${max_ipv6_length}s" "$ipv6_display"
  fi
  printf "\n"
done
