{
  nodes,
  lib,
  config,
  ...
}:
with lib; let
  name = "prometheus";
  cfg = config.services.skynet."${name}";

  # dont have to worry about any external addresses for this
  # create a list of either "ip@port" or ""
  # the ""s then get filtered out by filter_empty
  exporters = {
    dns = (
      lib.attrsets.mapAttrsToList (
        key: value:
          if value.config.services.skynet.dns.server.enable
          then "${value.config.deployment.targetHost}:${toString value.config.services.prometheus.exporters.bind.port}"
          else ""
      )
      nodes
    );
    node = lib.attrsets.mapAttrsToList (key: value: "${value.config.deployment.targetHost}:${toString value.config.services.prometheus.exporters.node.port}") nodes;
  };

  # clears any invalid entries
  filter_empty = inputs: (builtins.filter (value: value != "") inputs);
in {
  imports = [];

  options.services.skynet."${name}" = {
    server = {
      enable = mkEnableOption "Prometheus Server";

      port = mkOption {
        type = types.port;
        default = 9001;
      };
    };

    external = {
      node = mkOption {
        type = types.listOf types.str;
        default = [];
        description = ''
          To add other nodes outside of nix, specify ip and port that server should listen to here
        '';
      };
    };

    ports = {
      node = mkOption {
        type = types.port;
        default = 9100;
      };
    };
  };

  config = mkMerge [
    {
      services.prometheus.exporters.node = {
        enable = true;
        port = cfg.ports.node;
        openFirewall = true;
        # most collectors are on by default see https://github.com/prometheus/node_exporter for more options
        enabledCollectors = ["systemd" "processes"];
      };
    }
    (mkIf cfg.server.enable {
      services.prometheus = {
        enable = true;
        port = cfg.server.port;
        scrapeConfigs = [
          {
            job_name = "node_exporter";
            static_configs = [
              {
                targets = filter_empty (exporters.node ++ cfg.external.node);
              }
            ];
          }
          {
            job_name = "bind";
            static_configs = [
              {
                targets = filter_empty exporters.dns;
              }
            ];
          }
        ];
      };
    })
  ];
}