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

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

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

      # Include default secrets
      dgn-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:
    let
      version = "nixos-${metadata.nodes.${node}.nixpkgs}";
      pkgs = import sources.${version} { };
    in pkgs.applyPatches {
      name = "${version}-patched";
      src = sources.${version};
      patches = (import sources.nix-patches {
        inherit pkgs;
        patchFile = ./patches;
      }).mkPatches version;
    };

  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 = { pkgs, ... }: {
    # Import the default modules
    imports = [ ./modules ];
  };
} // (lib.mapSingleFuse mkNode nodes)