{ self
, nixpkgs
, ...
}@inputs:

let
  generateNixosSystem = {
    name,
    system ? "x86_64-linux",
    group ? null,
    modules ? [],
  }: let
    localNixpkgs = nixpkgs.lib.attrByPath [ "nixpkgs-${name}" ] nixpkgs inputs;
  in localNixpkgs.lib.nixosSystem {
    system = system;
    modules = modules ++ [
      self.nixosModules.nixfilesInputs
      self.nixosModules.clerie
      self.nixosModules.profiles

      ({ config, lib, ... }: {
        # Set hostname
        networking.hostName = lib.mkDefault name;

        # Apply overlays
        nixpkgs.overlays = [
          self.overlays.nixfilesInputs
          self.overlays.clerie
        ];

        /*
          Make the contents of the flake availiable to modules.
          Useful for having the monitoring server scraping the
          target config from all other servers automatically.
        */
        _module.args = {
          inputs = inputs;
          _nixfiles = self;
        };

        # Expose host group to monitoring
        clerie.monitoring = nixpkgs.lib.attrsets.optionalAttrs (group != null) { serviceLevel = group; };

        # Automatically load secrets from sops file for host
        sops.defaultSopsFile = ../hosts + "/${name}/secrets.json";
        sops.secrets = let
          secretFile = config.sops.defaultSopsFile;
          secretNames = builtins.filter (name: name != "sops") (builtins.attrNames (builtins.fromJSON (builtins.readFile secretFile)));
          secrets = if builtins.pathExists secretFile then
            lib.listToAttrs (builtins.map (name: lib.nameValuePair name {}) secretNames)
          else
            {};
        in
          secrets;

        # Enable clerie common config
        profiles.clerie.common.enable = true;
      })

      # Config to be applied to every host
      ../configuration/common
      ../users/clerie

      # Host specific config
      (../hosts + "/${name}/configuration.nix")
    ];
  };

  mapToNixosConfigurations = hosts: builtins.mapAttrs (name: host: generateNixosSystem ({ inherit name; } //  host)) hosts;

in
  mapToNixosConfigurations self.clerie.hosts