{ config, lib, options, pkgs, ... }:
let
  packageName = "custom-nixos-vm";

  mergedSystemOption =
    with options.system;
    lib.mergeDefinitions
      build.loc
      build.type
      (lib.lists.forEach
        (
          builtins.filter
            (item:
              !(lib.path.hasPrefix ./. (/. + item.file)))
            build.definitionsWithLocations)
        (item: { inherit (item) file value; }));

  vanillaVM = mergedSystemOption.mergedValue.vm;
in {
  options =
  let
    vmVariantOptions = {
      virtualisation = {
        runAsRoot = lib.mkOption {
          type = lib.types.bool;
          default = false;
        };

        sharedHostKeys = lib.mkOption {
          type = lib.types.bool;
          default = false;
        };

        virt-viewer = lib.mkOption {
          type = lib.types.bool;
          default = false;
        };

        qemu = {
          runInBackground = lib.mkOption {
            type = lib.types.bool;
            default = false;
          };

          spice = {
            enable = lib.mkEnableOption "spice";

            bindAddress = lib.mkOption {
              type = lib.types.str;
              default = "127.0.0.1";
            };

            port = lib.mkOption {
              type = lib.types.port;
              default = 5900;
            };
          };
        };
      };
    };
  in {
    virtualisation = {
      vmVariant = vmVariantOptions;
      vmVariantWithBootLoader = vmVariantOptions;
    };
  };

  config = {
    virtualisation =
      let
        extendVMConfig =
          vmVariant: {
            boot.loader.efi.efiSysMountPoint = lib.mkVMOverride "/boot";

            virtualisation = {
              runAsRoot = lib.mkIf vmVariant.virtualisation.sharedHostKeys true;

              qemu = {
                spice.enable = lib.mkIf vmVariant.virtualisation.virt-viewer true;
                runInBackground = lib.mkIf vmVariant.virtualisation.virt-viewer true;

                options =
                  with {
                    inherit (vmVariant.virtualisation.qemu) spice;
                  };
                  (
                    lib.optional (spice.enable)
                      ("-spice " + (
                        lib.concatStringsSep "," [
                          "addr=${lib.escapeShellArg spice.bindAddress}"
                          "port=${toString spice.port}"
                          "disable-ticketing=on"
                        ])));
              };

              sharedDirectories = lib.optionalAttrs (vmVariant.virtualisation.sharedHostKeys) {
                hostKeys =
                let
                  path = "/etc/ssh";
                in {
                  source = path;
                  target = path;
                };
              };
            };
          };

        virtualisation = config.virtualisation;
      in {
        vmVariant = extendVMConfig virtualisation.vmVariant;
        vmVariantWithBootLoader = extendVMConfig virtualisation.vmVariantWithBootLoader;
      };

    # Replace native `qemu` with `remote-viewer`
    system.build =
      {
        vm = lib.mkForce (
          (
            vm:
              if (vm.name == packageName)
              then
                vm
              else
                let
                  prefix =
                    lib.concatStringsSep " " (
                      lib.optionals config.virtualisation.runAsRoot (
                        ["sudo"] ++
                        lib.optional config.virtualisation.qemu.runInBackground "-b"));

                  suffix =
                    lib.concatStringsSep " " (
                      lib.optional
                        (!config.virtualisation.runAsRoot && config.virtualisation.qemu.runInBackground)
                        "&");

                  wrapped = pkgs.writeShellApplication {
                    name = "run-${config.system.name}-vm";
                    text = lib.strings.concatLines (
                      [
                        "${prefix} ${vm}/bin/run-${config.system.name}-vm ${suffix}"
                      ] ++ (
                        let
                          spice = config.virtualisation.qemu.spice;
                        in
                          (
                            lib.optionals
                              config.virtualisation.virt-viewer
                              [
                                "${pkgs.virt-viewer}/bin/remote-viewer spice://${lib.escapeShellArg spice.bindAddress}:${toString spice.port}"
                                "kill %1"
                              ])));
                  };
                in
                  pkgs.symlinkJoin {
                    name = packageName;
                    paths = [ wrapped ];
                  })
          vanillaVM);
      };
  };
}