{ lib }:

with lib;

rec {
  # Generate systemd network unit files from nix-nos network config
  generateNetworkdConfig = { interfaces }:
    listToAttrs (map (iface: {
      name = "10-${iface.name}";
      value = {
        matchConfig.Name = iface.name;
        networkConfig = {
          DHCP = "no";
        } // optionalAttrs (iface.mtu != null) {
          MTU = toString iface.mtu;
        };
        address = iface.addresses;
      };
    }) interfaces);

  # Generate BGP peer configurations in a backend-agnostic format
  generateBgpPeers = { asn, routerId, peers }:
    map (peer: {
      inherit (peer) address description;
      inherit asn;
      peerAsn = peer.asn;
      inherit routerId;
    }) peers;

  # Generate route table entries
  generateRouteTable = { routes }:
    map (route: {
      inherit (route) destination;
      gateway = route.gateway or null;
      interface = route.interface or null;
      metric = route.metric or 100;
    }) routes;

  # Helper: Convert CIDR to netmask
  cidrToNetmask = cidr:
    let
      parts = splitString "/" cidr;
      prefixLength = toInt (elemAt parts 1);

      # IPv4 netmask calculation
      masks = {
        "8" = "255.0.0.0";
        "16" = "255.255.0.0";
        "24" = "255.255.255.0";
        "32" = "255.255.255.255";
      };
    in
    masks.${toString prefixLength} or (throw "Unsupported prefix length: ${toString prefixLength}");

  # Helper: Extract IP from CIDR notation
  cidrToIp = cidr:
    let
      parts = splitString "/" cidr;
    in
    elemAt parts 0;

  # Helper: Extract prefix length from CIDR notation
  cidrToPrefixLength = cidr:
    let
      parts = splitString "/" cidr;
    in
    toInt (elemAt parts 1);

  # Validate IP address format
  isValidIpv4 = ip:
    let
      parts = splitString "." ip;
      validOctet = octet:
        let n = toInt octet;
        in n >= 0 && n <= 255;
    in
    (length parts == 4) && all validOctet parts;

  # Validate IPv6 address (simplified check)
  isValidIpv6 = ip:
    hasInfix ":" ip;

  # Validate CIDR notation
  isValidCidr = cidr:
    let
      parts = splitString "/" cidr;
      ip = elemAt parts 0;
      prefixLength = toInt (elemAt parts 1);
    in
    (length parts == 2) &&
    (isValidIpv4 ip || isValidIpv6 ip) &&
    (prefixLength >= 0) &&
    (if isValidIpv4 ip then prefixLength <= 32 else prefixLength <= 128);
}
