{ hostRegistry, inputs, lib, microvm, self }:

let
  getHostAddr = name:
    let
      hostConf = hostRegistry."${name}" or (throw "Host ${name} has no ip4 or ip6 address");
    in
      hostConf.ip4 or hostConf.ip6;

  # all the input flakes for `nix copy` to the build machine,
  # to be available for --override-input
  inputPaths = lib.escapeShellArgs (builtins.attrValues inputs);
  overrideInputsArgs = lib.concatStringsSep " " (builtins.attrValues (lib.mapAttrs
    (name: value: "--override-input ${name} ${value}")
    (lib.filterAttrs (name: _value: name != "self") inputs)
  ));
in
lib.attrsets.mapAttrs
  (system: pkgs:
  let
    overlayPkgs = builtins.intersectAttrs (self.overlays { } { }) pkgs;
  in
  overlayPkgs //
  {
    host-registry = pkgs.runCommand "host-registry" {
      src = builtins.toFile "host-registry.nix" (
        lib.generators.toPretty { } hostRegistry
      );
    } ''
      ln -s $src $out
    '';

    list-upgradable = pkgs.writeScriptBin "list-upgradable" ''
      set -eou pipefail

      NORMAL="\033[0m"
      RED="\033[0;31m"
      YELLOW="\033[0;33m"
      GREEN="\033[0;32m"

      ${lib.concatMapStringsSep "\n" (name:
        let
          addr = getHostAddr name;
        in lib.optionalString (addr != null) ''
          echo -n -e "${name}: $RED"
          RUNNING=$(ssh -o PreferredAuthentications=publickey -o StrictHostKeyChecking=accept-new root@"${addr}" "readlink /run/current-system")
          if [ $? = 0 ] && [ -n "$RUNNING" ]; then
            CURRENT=$(nix eval --raw ".#nixosConfigurations.${name}.config.system.build.toplevel" 2>/dev/null)
            RUNNING_VER=$(basename $RUNNING|rev|cut -d - -f 1|rev)
            RUNNING_DATE=$(echo $RUNNING_VER|cut -d . -f 3)
            CURRENT_VER=$(basename $CURRENT|rev|cut -d - -f 1|rev)
            CURRENT_DATE=$(echo $CURRENT_VER|cut -d . -f 3)

            if [ "$RUNNING" = "$CURRENT" ]; then
              echo -e "$GREEN"current"$NORMAL $RUNNING_VER"
            elif [ $RUNNING_DATE -gt $CURRENT_DATE ]; then
              echo -e "$GREEN"newer"$NORMAL $RUNNING_VER > $CURRENT_VER"
            elif [ "$RUNNING_VER" = "$CURRENT_VER" ]; then
              echo -e "$YELLOW"modified"$NORMAL $RUNNING_VER"
            elif [ -n "$RUNNING_VER" ]; then
              echo -e "$RED"outdated"$NORMAL $RUNNING_VER < $CURRENT_VER"
            else
              echo -e "$RED"error"$NORMAL $RUNNING_VER"
            fi
          fi
          echo -n -e "$NORMAL"
        '') (builtins.attrNames self.nixosConfigurations)}
    '';

    prebuild-all = pkgs.runCommand "prebuild-all" {
      preferLocalBuild = true;
    } ''
      mkdir $out

      ${pkgs.lib.concatMapStrings (name: ''
        ln -s ${self.nixosConfigurations."${name}".config.system.build.toplevel} name
      '') (builtins.attrNames self.nixosConfigurations)}
    '';

    prebuild-all-remote = pkgs.writeScriptBin "prebuild-all" ''
      set -eou pipefail

      nix copy --no-check-sigs --to ssh-ng://$1 ${inputPaths}

      ssh $1 -- nix build -L --no-link ${lib.concatMapStringsSep " " (name:
        "${self}#nixosConfigurations.${name}.config.system.build.toplevel"
      ) (builtins.attrNames self.nixosConfigurations)}
    '';

  } //
  builtins.foldl'
    (result: name:
      let
        discardStringCtx = builtins.unsafeDiscardStringContext;
        host = getHostAddr name;
        target = ''root@"${host}"'';
        rebuildArg = "--flake ${self}#${name} ${overrideInputsArgs} --accept-flake-config";
        hostConfig = self.nixosConfigurations."${name}".config;
        declaredRunnerDrvPath = discardStringCtx hostConfig.microvm.declaredRunner.drvPath;
        toplevelDrvPath = discardStringCtx hostConfig.system.build.toplevel.drvPath;
        toplevelOutPath = discardStringCtx hostConfig.system.build.toplevel.outPath;
        # let /var/lib/microvm/*/flake point to the flake-update branch so that
        # `microvm -u $NAME` updates to what hydra built today.
        selfRef = "git+https://gitea.c3d2.de/c3d2/nix-config?ref=flake-update";
      in
      result // {
        # Generate a small script for copying this flake to the
        # remote machine and bulding and switching there.
        # Can be run with `nix run c3d2#…-nixos-rebuild switch`
        "${name}-nixos-rebuild" = pkgs.writeScriptBin "${name}-nixos-rebuild" ''
          set -eou pipefail

          ${lib.optionalString (hostConfig.c3d2.deployment.server or "" != "") ''
            echo "microvms cannot be updated with nixos-rebuild. Use nix run .#microvm-update-${name}"
            exit 2
          ''}

          hostname="$(ssh ${target} cat /etc/hostname)"
          if [[ "$hostname" != ${name} ]]; then
            echo "hostname of ${target} was expected to be ${name} but is $hostname. Aborting to be safe..."
            exit 2
          fi
          nix copy --no-check-sigs --derivation --to ssh-ng://${target} ${toplevelDrvPath}

          # use nixos-rebuild from target config
          ssh ${target} bash -e <<END
          set -eou pipefail

          nix build --no-link ${toplevelDrvPath}
          ${discardStringCtx hostConfig.nix.package}/bin/nix-env -p /nix/var/nix/profiles/system --set ${toplevelOutPath}
          ${toplevelOutPath}/bin/switch-to-configuration "''${@:-switch}"
          END
        '';

        "${name}-nixos-rebuild-hydra" = pkgs.writeScriptBin "${name}-nixos-rebuild" ''
          set -eou pipefail

          echo Copying Flakes
          nix copy --no-check-sigs --to ssh-ng://root@hydra.serv.zentralwerk.org ${inputPaths}

          echo Building on Hydra
          ssh root@hydra.serv.zentralwerk.org -- \
            nix build -L -o /tmp/nixos-system-${name} ${toplevelOutPath}

          echo Built. Obtaining link to data
          TOPLEVEL=$(ssh root@hydra.serv.zentralwerk.org \
            readlink /tmp/nixos-system-${name})

          echo Checking target ${name}
          ssh ${target} -- bash -e <<EOF
          [[ \$(cat /etc/hostname) == ${name} ]]
          echo Copying data from Hydra to ${name}
          nix copy --from https://nix-cache.hq.c3d2.de \
            $TOPLEVEL

          echo Activation on ${name}: "$@"
          nix-env -p /nix/var/nix/profiles/system --set $TOPLEVEL
          $TOPLEVEL/bin/switch-to-configuration "$@"
          EOF
        '';

        "${name}-nixos-rebuild-local" = pkgs.writeScriptBin "${name}-nixos-rebuild" ''
          set -eou pipefail

          if [[ ''${1:-} == build; then
            hostname=$(ssh root@${target} cat /etc/hostname)"
            if [[ "$hostname" != ${name} ]]; then
              echo "hostname of ${target} was expected to be ${name} but is $hostname. Aborting to be safe..."
              exit 2
            fi
          fi
          # don't re-execute, otherwise we run the targetPlatform locally
          _NIXOS_REBUILD_REEXEC=1 ${lib.getExe pkgs.nixos-rebuild} ${rebuildArg} --target-host ${target} --use-remote-sudo "$@"
        '';

        "${name}-cleanup" = pkgs.writeScriptBin "${name}-cleanup" ''
          set -eou pipefail
          ssh ${target} "time nix-collect-garbage -d && time nix-store --optimise"
        '';
      } // (let
        createDirsCopyCurrent = name: ''
          mkdir -p /var/lib/microvms/${name}
          cd /var/lib/microvms/${name}
          chown root:kvm .
          chmod 0775 .

          rm -f old
          [ -e current ] && cp --no-dereference current old
        '';
        createSymlinks = name: ''
          if [[ -e old ]]; then
            echo System package diff:
            nix --extra-experimental-features nix-command store diff-closures ./old ./current || true
          fi

          ln -sfT \$PWD/current /nix/var/nix/gcroots/microvm/${name}
          ln -sfT \$PWD/booted /nix/var/nix/gcroots/microvm/booted-${name}
          ln -sfT \$PWD/old /nix/var/nix/gcroots/microvm/old-${name}
        '';
      in {

        "microvm-update-${name}" = pkgs.writeScriptBin "microvm-update-${name}" (
          if builtins.elem (hostConfig.c3d2.deployment.server or null) [ "server9" "server10" ]
          then let
            closureInfo = pkgs.closureInfo { rootPaths = [ hostConfig.system.build.toplevel.outPath ]; };
          in ''
            set -eou pipefail

            ${hostConfig.system.build.copyToServer} ${declaredRunnerDrvPath} ${discardStringCtx closureInfo.drvPath}

            ${hostConfig.system.build.runOnServer} NIXOS_REBUILD="''${NIXOS_REBUILD:-}" bash -e <<END
            ${createDirsCopyCurrent name}

            nix build -L --accept-flake-config -o current ${declaredRunnerDrvPath}
            nix build -L --accept-flake-config --no-link ${discardStringCtx closureInfo.drvPath}
            echo '${selfRef}' > flake

            ${createSymlinks name}

            if [[ -z "''${NIXOS_REBUILD:-}" ]]; then
              echo "Restarting MicroVM..."
              systemctl restart microvm@${name}.service
            fi
            END

            if [[ -n "''${NIXOS_REBUILD:-}" ]]; then
              echo "Switching to configuration..."
              ssh ${target} bash -e <<END
              set -eou pipefail

              hostname=\$(cat /etc/hostname)
              if [[ "\$hostname" != ${name} ]]; then
                echo "hostname of ${target} was expected to be ${name} but is \$hostname. Aborting to be safe..."
                exit 2
              fi

              # refresh nix db which is required for nix-env -p ... --set
              ${discardStringCtx hostConfig.nix.package}/bin/nix-store --load-db < ${discardStringCtx closureInfo}
              ${discardStringCtx hostConfig.nix.package}/bin/nix-env -p /nix/var/nix/profiles/system --set ${toplevelOutPath}
              ${toplevelOutPath}/bin/switch-to-configuration "''${@:-switch}"
            END
            # ^ yes, this is required to be like this

            fi
          ''
          else throw "${name} is not configured to run on microvm.nix. Is it a physical host or is it deployed in Skyflake?"
        );

        "microvm-update-${name}-local" = pkgs.writeScriptBin "microvm-update-${name}" ''
          set -eou pipefail

          ${lib.optionalString (!builtins.elem (hostConfig.c3d2.deployment.server or null) [ "server9" "server10" ]) ''
            echo "MicroVM must be configured to proper server" >&2
            exit 2
          ''}

          ${hostConfig.system.build.copyToServer} ${declaredRunnerDrvPath}

          ${hostConfig.system.build.runOnServer} bash -e <<END
          set -eou pipefail
          hostname=\$(cat /etc/hostname)
          if [[ "\$hostname" != ${name} ]]; then
            echo "hostname of ${target} was expected to be ${name} but is \$hostname. Aborting to be safe..."
            exit 2
          fi

          ${createDirsCopyCurrent name}

          ln -sfT ${hostConfig.microvm.declaredRunner} current
          echo '${selfRef}' > flake

          ${createSymlinks name}

          systemctl restart microvm@${name}.service
          END
        '';
      }))
    { }
    (builtins.attrNames self.nixosConfigurations) //

  builtins.foldl'
    (result: host:
      let
        inherit (self.nixosConfigurations.${host}) config;
      in
      result // {
        # boot any machine in a microvm
        "${host}-vm" = (self.nixosConfigurations.${host}.extendModules {
          modules = [{
            microvm = {
              mem = lib.mkForce 2048;
              hypervisor = lib.mkForce "qemu";
              socket = lib.mkForce null;
              shares = lib.mkForce [{
                tag = "ro-store";
                source = "/nix/store";
                mountPoint = "/nix/.ro-store";
              }];
              interfaces = lib.mkForce [{
                type = "user";
                id = "eth0";
                mac = "02:23:de:ad:be:ef";
              }];
            };
            boot.isContainer = lib.mkForce false;
            users.users.root.password = "";
            fileSystems."/".fsType = lib.mkForce "tmpfs";
            services.getty.helpLine = ''
              Log in as "root" with an empty password.
              Use "reboot" to shut qemu down.
            '';
          }] ++ lib.optionals (! config ? microvm) [
            microvm.nixosModules.microvm
          ];
        }).config.microvm.declaredRunner;

        "${host}-tftproot" = config.system.build.tftproot or (lib.trace "No tftproot for ${host}" null);
      }
    )
    { }
    (builtins.attrNames self.nixosConfigurations)
  )
  self.legacyPackages
