let
  sources = import ./npins;
  metadata = import ./meta;

  lib = import (sources.nix-lib + "/src/trivial.nix");

  patch = import sources.nix-patches { patchFile = ./patches; };

  mkNode = node: _: {
    # Import the base configuration for each node
    imports = builtins.map (lib.mkRel ./machines/${node}) [
      "_configuration.nix"
      "_hardware-configuration.nix"
    ];

    # Include default secrets
    age-secrets.sources = [ ./machines/${node}/secrets ];

    # Deployment config is specified in meta.nodes.${node}.deployment
    inherit (metadata.nodes.${node}) deployment;

    # Set NIX_PATH to the patched version of nixpkgs
    nix.nixPath = [ "nixpkgs=${mkNixpkgs node}" ];
    nix.optimise.automatic = true;

    # Allow unfree packages
    nixpkgs.config.allowUnfree = true;

    # Use the stateVersion declared in the metadata
    system = {
      inherit (metadata.nodes.${node}) stateVersion;
    };
  };

  mkNixpkgs =
    node:
    patch.mkNixpkgsSrc rec {
      src = sources.${version};
      version = "nixos-${metadata.nodes.${node}.nixpkgs}";
    };

  mkNixpkgs' = node: import (mkNixpkgs node) { };

  ###
  # Function to create arguments based on the node
  #
  mkArgs =
    node:
    let
      lib' = (mkNixpkgs' node).lib;
    in
    {
      lib = import sources.nix-lib {
        lib = lib';
        keysRoot = ./keys;
      };
    };

  nodes = builtins.attrNames metadata.nodes;
in
{
  meta = {
    nodeNixpkgs = lib.mapSingleFuse mkNixpkgs' nodes;

    specialArgs = {
      inherit sources;
      meta = metadata;
    };

    nodeSpecialArgs = lib.mapSingleFuse mkArgs nodes;
  };

  defaults = _: {
    # Import the default modules
    imports = [ ./modules ];
  };
}
// (lib.mapSingleFuse mkNode nodes)