#!/usr/bin/env bash
# subnet.command.sh — manage the subnet map (subnets.json)
#
# Subcommands:
#   wgctl subnet list
#   wgctl subnet show  --name <name>
#   wgctl subnet add   --name <name> --subnet <cidr> [--type <type>]
#                      [--tunnel-mode split|full] [--desc <desc>]
#                      [--group <parent>]
#   wgctl subnet rm    --name <name>
#   wgctl subnet rename --name <old> --new-name <new>

# ============================================
# Lifecycle
# ============================================

function cmd::subnet::on_load() {
  flag::register --name
  flag::register --subnet
  flag::register --type
  flag::register --tunnel-mode
  flag::register --desc
  flag::register --group
  flag::register --new-name
}

# ============================================
# Help
# ============================================

function cmd::subnet::help() {
  cat <<EOF
Usage: wgctl subnet <subcommand> [options]

Manage the subnet map.

Subcommands:
  list                          List all configured subnets
  show   --name <name>          Show details for a subnet
  add    --name <name>          Add a new subnet entry
         --subnet <cidr>
         [--type <type>]
         [--tunnel-mode split|full]
         [--desc <desc>]
         [--group <parent>]
  rm     --name <name>          Remove a subnet (refused if in use)
  rename --name <old>           Rename a subnet (refused if in use)
         --new-name <new>

Examples:
  wgctl subnet list
  wgctl subnet show --name guests
  wgctl subnet add --name iot-cctv --subnet 10.1.211.0/24 --type iot
  wgctl subnet add --name desktop --subnet 10.1.101.0/24 --group guests
  wgctl subnet rm --name iot-cctv
  wgctl subnet rename --name iot-cctv --new-name cctv
EOF
}

# ============================================
# Run
# ============================================

function cmd::subnet::run() {
  local subcmd="${1:-list}"
  shift || true

  case "$subcmd" in
    list)   cmd::subnet::_list   "$@" ;;
    show)   cmd::subnet::_show   "$@" ;;
    add)    cmd::subnet::_add    "$@" ;;
    rm)     cmd::subnet::_rm     "$@" ;;
    rename) cmd::subnet::_rename "$@" ;;
    --help) cmd::subnet::help        ;;
    *)
      log::error "Unknown subcommand '${subcmd}'. Available: list, show, add, rm, rename"
      return 1
      ;;
  esac
}

# ============================================
# Subcommands
# ============================================

function cmd::subnet::_list() {
  local data
  data=$(subnet::list_data)
 
  if [[ -z "$data" ]]; then
    log::info "No subnets defined."
    return 0
  fi
 
  echo ""
  local prev_group=""
  while IFS='|' read -r display_name subnet type_key tunnel_mode desc is_group group_parent; do
    if [[ "$is_group" == "true" ]]; then
      # Print group parent header when we encounter first child
      if [[ "$group_parent" != "$prev_group" ]]; then
        [[ -n "$prev_group" ]] && ui::subnet::group_separator
        ui::subnet::row_group_parent "$group_parent"
        prev_group="$group_parent"
      fi
      ui::subnet::row_group_child "$type_key" "$subnet" "$tunnel_mode"
    else
      # Scalar entry
      [[ -n "$prev_group" ]] && ui::subnet::group_separator
      prev_group=""
      ui::subnet::row_scalar "$display_name" "$subnet" "$tunnel_mode"
    fi
  done <<< "$data"
  echo ""
}

function cmd::subnet::_maybe_group_separator() {
  local is_group="${1:-}" group_parent="${2:-}" prev_group="${3:-}"
  if [[ "$is_group" == "true" && "$group_parent" != "$prev_group" && -n "$prev_group" ]]; then
    ui::subnet::group_separator
  elif [[ "$is_group" == "false" && -n "$prev_group" ]]; then
    ui::subnet::group_separator
  fi
}

function cmd::subnet::_update_prev_group() {
  local is_group="${1:-}" group_parent="${2:-}" prev_group="${3:-}"
  if [[ "$is_group" == "true" ]]; then
    echo "$group_parent"
  else
    echo ""
  fi
}

function cmd::subnet::_show() {
  local name=""
  while [[ $# -gt 0 ]]; do
    case "$1" in
      --name) name="$2"; shift 2 ;;
      --help) cmd::subnet::help; return ;;
      *) log::error "Unknown flag: $1"; return 1 ;;
    esac
  done

  [[ -z "$name" ]] && { log::error "Missing required flag: --name"; return 1; }
  subnet::require_exists "$name" || return 1

  local data
  data=$(subnet::show_data "$name")

  local is_group="false"
  while IFS='|' read -r key val rest; do
    case "$key" in
      name)
        ui::subnet::detail "$val" "$is_group"
        ;;
      is_group)
        is_group="$val"
        # Only print type once
        if [[ "$val" == "true" ]]; then
          ui::subnet::detail_field "Type" "group"
          ui::subnet::child_header
        else
          ui::subnet::detail_field "Type" "scalar"
        fi
        ;;
      subnet)      ui::subnet::detail_field "Subnet"      "$val" ;;
      type)        ui::subnet::detail_field "Device type" "$val" ;;
      tunnel_mode) ui::subnet::detail_field "Tunnel"      "$val" ;;
      desc)        ui::subnet::detail_field "Description" "$val" ;;
      child)
        local c_type="$val"
        local c_subnet c_tunnel c_desc
        c_subnet=$(echo "$rest" | cut -d'|' -f1)
        c_tunnel=$(echo "$rest" | cut -d'|' -f2)
        c_desc=$(echo   "$rest" | cut -d'|' -f3)
        ui::subnet::child_row "$c_type" "$c_subnet" "$c_tunnel" "$c_desc"
        ;;
    esac
  done <<< "$data"

  local peers_using
  peers_using=$(subnet::peers_using "$name")
  ui::subnet::peers_in_use "$peers_using"
}

function cmd::subnet::_add() {
  local name="" cidr="" type_key="" tunnel_mode="split" desc="" group_parent=""

  while [[ $# -gt 0 ]]; do
    case "$1" in
      --name)        name="$2";         shift 2 ;;
      --subnet)      cidr="$2";         shift 2 ;;
      --type)        type_key="$2";     shift 2 ;;
      --tunnel-mode) tunnel_mode="$2";  shift 2 ;;
      --desc)        desc="$2";         shift 2 ;;
      --group)       group_parent="$2"; shift 2 ;;
      --help)        cmd::subnet::help; return  ;;
      *) log::error "Unknown flag: $1"; return 1 ;;
    esac
  done

  [[ -z "$name" ]] && { log::error "Missing required flag: --name";   return 1; }
  [[ -z "$cidr" ]] && { log::error "Missing required flag: --subnet"; return 1; }

  cmd::subnet::_validate_tunnel_mode "$tunnel_mode" || return 1
  cmd::subnet::_validate_cidr        "$cidr"        || return 1

  json::subnet_add "$(ctx::subnets)" "$name" "$cidr" \
    "${type_key:-$name}" "$tunnel_mode" "$desc" "$group_parent"

  log::ok "Subnet '${name}' added (${cidr})"
}

function cmd::subnet::_rm() {
  local name=""
  while [[ $# -gt 0 ]]; do
    case "$1" in
      --name) name="$2"; shift 2 ;;
      --help) cmd::subnet::help; return ;;
      *) log::error "Unknown flag: $1"; return 1 ;;
    esac
  done

  [[ -z "$name" ]] && { log::error "Missing required flag: --name"; return 1; }
  subnet::require_exists "$name" || return 1

  local peers_using
  peers_using=$(subnet::peers_using "$name")

  if [[ -n "$peers_using" ]]; then
    log::error "Cannot remove subnet '${name}' — in use by: ${peers_using//,/, }"
    log::error "Migrate or remove those peers first."
    return 1
  fi

  json::subnet_remove "$(ctx::subnets)" "$name" ""
  log::ok "Subnet '${name}' removed"
}

function cmd::subnet::_rename() {
  local name="" new_name=""
  while [[ $# -gt 0 ]]; do
    case "$1" in
      --name)     name="$2";     shift 2 ;;
      --new-name) new_name="$2"; shift 2 ;;
      --help)     cmd::subnet::help; return ;;
      *) log::error "Unknown flag: $1"; return 1 ;;
    esac
  done

  [[ -z "$name" ]]     && { log::error "Missing required flag: --name";     return 1; }
  [[ -z "$new_name" ]] && { log::error "Missing required flag: --new-name"; return 1; }
  subnet::require_exists "$name" || return 1

  local peers_using
  peers_using=$(subnet::peers_using "$name")
  if [[ -n "$peers_using" ]]; then
    log::error "Cannot rename subnet '${name}' — configs already distributed to: ${peers_using//,/, }"
    log::error "Client configs reference the subnet CIDR which cannot change after distribution."
    return 1
  fi

  json::subnet_rename "$(ctx::subnets)" "$name" "$new_name" ""
  log::ok "Subnet '${name}' renamed to '${new_name}'"
}

# ============================================
# Validation Helpers
# ============================================

function cmd::subnet::_validate_tunnel_mode() {
  local mode="${1:-}"
  case "$mode" in
    split|full) return 0 ;;
    *)
      log::error "Invalid --tunnel-mode '${mode}'. Use: split, full"
      return 1
      ;;
  esac
}

function cmd::subnet::_validate_cidr() {
  local cidr="${1:-}"
  if ! echo "$cidr" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/[0-9]+$'; then
    log::error "Invalid CIDR format: '${cidr}'"
    return 1
  fi
}