{ config, lib, ... }: let inherit (lib) mkOption types; cfg = config.pepe.core.network; in { options.pepe.core.network = { interfaces = mkOption { type = types.attrsOf (types.submodule { options = { interface = mkOption { type = types.str; description = "The network interface name."; }; type = mkOption { type = types.enum [ "lan" "wan" "vpn" ]; description = "The type of interface (lan, wan, or vpn)."; }; net = mkOption { type = types.str; description = "The network address in CIDR format."; }; devices = mkOption { type = types.attrsOf (types.submodule { options = { address = mkOption { type = types.str; description = "The IP address of the device."; }; hostname = mkOption { type = types.str; description = "The hostname of the device."; }; isEndpoint = mkOption { type = types.bool; default = false; description = "Whether this device serves as a DNS endpoint for this interface."; }; }; }); default = { }; description = "An attribute set of devices with their configurations."; }; }; }); default = { }; description = "An attribute set of networks with their configurations."; }; interfacesByType = mkOption { type = types.attrsOf (types.listOf types.str); default = { }; description = "Interfaces grouped by type (lan, wan, vpn) for easy access."; internal = true; }; dnsEndpoints = mkOption { type = types.attrsOf (types.submodule { options = { interface = mkOption { type = types.str; description = "The interface this DNS endpoint belongs to."; }; device = mkOption { type = types.str; description = "The device name that serves as the DNS endpoint."; }; address = mkOption { type = types.str; description = "The IP address of the DNS endpoint."; }; serverName = mkOption { type = types.str; default = ""; description = "DNS server name for TLS connections."; }; }; }); default = { }; description = "DNS endpoints for each interface."; internal = true; }; }; config = { # Create lists of interfaces by type for easy access elsewhere pepe.core.network.interfacesByType = { lan = lib.attrNames (lib.filterAttrs (_: iface: iface.type == "lan") cfg.interfaces); wan = lib.attrNames (lib.filterAttrs (_: iface: iface.type == "wan") cfg.interfaces); vpn = lib.attrNames (lib.filterAttrs (_: iface: iface.type == "vpn") cfg.interfaces); }; # Collect DNS endpoints from all interfaces pepe.core.network.dnsEndpoints = let collectEndpoints = ifaceName: iface: lib.mapAttrs' (deviceName: device: lib.nameValuePair "${ifaceName}-${deviceName}" { interface = ifaceName; device = deviceName; address = device.address; serverName = device.dnsServerName; } ) (lib.filterAttrs (_: device: device.isDnsEndpoint) iface.devices); in lib.foldl (acc: ifaceName: acc // (collectEndpoints ifaceName cfg.interfaces.${ifaceName}) ) { } (lib.attrNames cfg.interfaces); }; }