{ hostPkgs, lib, config, ... }:
let
  testDriver = hostPkgs.python3.pkgs.callPackage ./package.nix {
    inherit (config) extraPythonPackages;
    inherit (hostPkgs.pkgs) util-linux systemd;
  };
  containers = map (m: m.system.build.toplevel) (lib.attrValues config.nodes);
  pythonizeName = name:
    let
      head = lib.substring 0 1 name;
      tail = lib.substring 1 (-1) name;
    in
    (if builtins.match "[A-z_]" head == null then "_" else head) +
    lib.stringAsChars (c: if builtins.match "[A-z0-9_]" c == null then "_" else c) tail;
  nodeHostNames =
    let
      nodesList = map (c: c.system.name) (lib.attrValues config.nodes);
    in
    nodesList ++ lib.optional (lib.length nodesList == 1 && !lib.elem "machine" nodesList) "machine";
  machineNames = map (name: "${name}: Machine;") pythonizedNames;
  pythonizedNames = map pythonizeName nodeHostNames;
in
{
  driver = lib.mkForce (hostPkgs.runCommand "nixos-test-driver-${config.name}"
    {
      nativeBuildInputs = [
        hostPkgs.makeWrapper
      ] ++ lib.optionals (!config.skipTypeCheck) [ hostPkgs.mypy ];
      buildInputs = [ testDriver ];
      testScript = config.testScriptString;
      preferLocalBuild = true;
      passthru = config.passthru;
      meta = config.meta // {
        mainProgram = "nixos-test-driver";
      };
    }
    ''
      mkdir -p $out/bin

      containers=(${toString containers})

      ${lib.optionalString (!config.skipTypeCheck) ''
        # prepend type hints so the test script can be type checked with mypy
        cat "${./test-script-prepend.py}" >> testScriptWithTypes
        echo "${builtins.toString machineNames}" >> testScriptWithTypes
        echo -n "$testScript" >> testScriptWithTypes

        echo "Running type check (enable/disable: config.skipTypeCheck)"
        echo "See https://nixos.org/manual/nixos/stable/#test-opt-skipTypeCheck"

        mypy  --no-implicit-optional \
              --pretty \
              --no-color-output \
              testScriptWithTypes
      ''}

      echo -n "$testScript" >> $out/test-script

      ln -s ${testDriver}/bin/nixos-test-driver $out/bin/nixos-test-driver

      wrapProgram $out/bin/nixos-test-driver \
        ${lib.concatStringsSep " " (map (name: "--add-flags '--container ${name}'") containers)} \
        --add-flags "--test-script '$out/test-script'"
    '');

  test = lib.mkForce (lib.lazyDerivation {
    # lazyDerivation improves performance when only passthru items and/or meta are used.
    derivation = hostPkgs.stdenv.mkDerivation {
      name = "vm-test-run-${config.name}";

      requiredSystemFeatures = [ "uid-range" ];

      buildCommand = ''
        mkdir -p $out

        # effectively mute the XMLLogger
        export LOGFILE=/dev/null

        ${config.driver}/bin/nixos-test-driver -o $out
      '';

      passthru = config.passthru;

      meta = config.meta;
    };
    inherit (config) passthru meta;
  });
}
