{ lib, pkgs, extendModules, modulesPath, options, config, ... }:
let
  inherit (lib) recursiveUpdate mkOption mkDefault mkIf mkMerge mkForce flatten optional;
  inherit (lib.my) mkBoolOpt' dummyOption;

  cfg = config.my.build;

  allHardware = (optional config.my.build.allHardware { imports = [ "${modulesPath}/profiles/all-hardware.nix" ]; });

  asDevVM = extendModules {
    modules = [
      "${modulesPath}/virtualisation/qemu-vm.nix"
      { my.build.isDevVM = true; }
    ];
  };
  asISO = extendModules {
    modules = flatten [
      "${modulesPath}/installer/cd-dvd/iso-image.nix"
      allHardware
      {
        # Doesn't work right now... (missing /dev/root)
        boot.initrd.systemd.enable = false;

        isoImage = {
          makeEfiBootable = true;
          makeUsbBootable = true;
          # Not necessarily an installer
          appendToMenuLabel = mkDefault "";

          squashfsCompression = "zstd -Xcompression-level 8";
        };
      }
    ];
  };
  asContainer = extendModules {
    modules = [
      {
        boot.isContainer = true;
      }
    ];
  };
  asKexecTree = extendModules {
    modules = flatten [
      "${modulesPath}/installer/netboot/netboot.nix"
      allHardware
    ];
  };

  asNetboot = extendModules {
    modules = flatten [
      allHardware
      ({ pkgs, config, ... }: {
        boot = {
          loader.grub.enable = false;
          initrd = {
            kernelModules = [ "nbd" ];
            availableKernelModules = [ "igb" "igc" ];

            systemd = {
              storePaths = with pkgs; [
                gnused
                nbd
                netcat
              ];
              extraBin = with pkgs; {
                dmesg = "${util-linux}/bin/dmesg";
                ip = "${iproute2}/bin/ip";
                nbd-client = "${nbd}/bin/nbd-client";
              };
              extraConfig = ''
                DefaultTimeoutStartSec=20
                DefaultDeviceTimeoutSec=20
              '';

              network = {
                enable = true;
                wait-online.enable = true;

                networks."10-netboot" = {
                  matchConfig.Name = "et-boot";
                  DHCP = "yes";
                };
              };

              services = {
                nbd = {
                  description = "NBD Root FS";

                  script = ''
                    get_cmdline() {
                      ${pkgs.gnused}/bin/sed -rn "s/^.*$1=(\\S+).*\$/\\1/p" < /proc/cmdline
                    }

                    s="$(get_cmdline nbd_server)"
                    until ${pkgs.netcat}/bin/nc -zv "$s" 22; do
                      sleep 0.1
                    done

                    exec ${pkgs.nbd}/bin/nbd-client -systemd-mark -N "$(get_cmdline nbd_export)" "$s" /dev/nbd0
                  '';
                  unitConfig = {
                    IgnoreOnIsolate = "yes";
                    DefaultDependencies = "no";
                  };
                  serviceConfig = {
                    Type = "forking";
                    Restart = "on-failure";
                    RestartSec = 10;
                  };

                  wantedBy = [ "initrd-root-device.target" ];
                };
              };
            };
          };

          postBootCommands = ''
            # After booting, register the contents of the Nix store
            # in the Nix database in the COW root.
            ${config.nix.package}/bin/nix-store --load-db < /nix-path-registration

            # nixos-rebuild also requires a "system" profile and an
            # /etc/NIXOS tag.
            touch /etc/NIXOS
            ${config.nix.package.out}/bin/nix-env -p /nix/var/nix/profiles/system --set /run/current-system
          '';
        };

        programs.nbd.enable = true;

        fileSystems = {
          "/" = {
            fsType = "ext4";
            device = "/dev/nbd0";
            noCheck = true;
            autoResize = true;
          };
        };

        networking.useNetworkd = mkForce true;

        systemd = {
          network.networks."10-boot" = {
            matchConfig.Name = "et-boot";
            DHCP = "yes";
            networkConfig.KeepConfiguration = "yes";
          };
        };

        system.build = {
          rootImage = pkgs.callPackage "${modulesPath}/../lib/make-ext4-fs.nix" {
            storePaths = [ config.system.build.toplevel ];
            volumeLabel = "netboot-root";
          };
          netbootScript = pkgs.writeText "boot.ipxe" ''
            #!ipxe
            kernel ${pkgs.stdenv.hostPlatform.linux-kernel.target} init=${config.system.build.toplevel}/init initrd=initrd ifname=et-boot:''${mac} nbd_server=''${next-server} ${toString config.boot.kernelParams} ''${cmdline}
            initrd initrd
            boot
          '';

          netbootTree = pkgs.linkFarm "netboot-${config.system.name}" [
            {
              name = config.system.boot.loader.kernelFile;
              path = "${config.system.build.kernel}/${config.system.boot.loader.kernelFile}";
            }
            {
              name = "initrd";
              path = "${config.system.build.initialRamdisk}/initrd";
            }
            {
              name = "rootfs.ext4";
              path = config.system.build.rootImage;
            }
            {
              name = "boot.ipxe";
              path = config.system.build.netbootScript;
            }
          ];
          netbootArchive = pkgs.runCommand "netboot-${config.system.name}.tar.zst" { } ''
            export PATH=${pkgs.zstd}/bin:$PATH
            ${pkgs.gnutar}/bin/tar --dereference --zstd -cvC ${config.system.build.netbootTree} -f "$out" .
          '';
        };
      })
    ];
  };

  mkAsOpt = ext: desc: with lib.types; mkOption {
    type = unspecified;
    default = ext;
    visible = "shallow";
    description = "Configuration as ${desc}.";
  };
in
{
  options = {
    my = {
      build = {
        isDevVM = mkBoolOpt' false "Whether the system is a development VM.";
        allHardware = mkBoolOpt' false
          ("Whether to enable a lot of firmware and kernel modules for a wide range of hardware." +
          "Only applies to some build targets.");
      };

      asDevVM = mkAsOpt asDevVM "a development VM";
      asISO = mkAsOpt asISO "a bootable .iso image";
      asContainer = mkAsOpt asContainer "a container";
      asKexecTree = mkAsOpt asKexecTree "a kexec-able kernel and initrd";
      asNetboot = mkAsOpt asNetboot "a netboot-able kernel initrd, and iPXE script";

      buildAs = options.system.build;
    };

    # Forward declare options that won't exist until the VM module is actually imported
    virtualisation = {
      diskImage = dummyOption;
      forwardPorts = dummyOption;
      sharedDirectories = dummyOption;
      cores = dummyOption;
      memorySize = dummyOption;
      qemu.options = dummyOption;
    };
    image.baseName = dummyOption;
    isoImage = {
      volumeID = dummyOption;
      edition = dummyOption;
      appendToMenuLabel = dummyOption;
    };
  };

  config = {
    virtualisation = {
      diskImage = mkDefault "./.vms/${config.system.name}.qcow2";
    };

    my = {
      buildAs = {
        # The meta.mainProgram should probably be set upstream but oh well...
        devVM = recursiveUpdate config.my.asDevVM.config.system.build.vm { meta.mainProgram = "run-${config.system.name}-vm"; };
        iso = config.my.asISO.config.system.build.isoImage;
        container = config.my.asContainer.config.system.build.toplevel;
        kexecTree = config.my.asKexecTree.config.system.build.kexecTree;
        netbootTree = config.my.asNetboot.config.system.build.netbootTree;
        netbootArchive = config.my.asNetboot.config.system.build.netbootArchive;
      };
    };
  };

  meta.buildDocsInSandbox = false;
}
