{
  config,
  pkgs,
  lib,
  ...
}:

with lib;
{
  imports = [
    ./disk-size-option.nix
    ../image/file-options.nix
    (lib.mkRenamedOptionModuleWith {
      sinceRelease = 2411;
      from = [
        "proxmox"
        "qemuConf"
        "diskSize"
      ];
      to = [
        "virtualisation"
        "diskSize"
      ];
    })
  ];

  options.proxmox = {
    qemuConf = {
      # essential configs
      boot = mkOption {
        type = types.str;
        default = "";
        example = "order=scsi0;net0";
        description = ''
          Default boot device. PVE will try all devices in its default order if this value is empty.
        '';
      };
      scsihw = mkOption {
        type = types.str;
        default = "virtio-scsi-single";
        example = "lsi";
        description = ''
          SCSI controller type. Must be one of the supported values given in
          <https://pve.proxmox.com/wiki/Qemu/KVM_Virtual_Machines>
        '';
      };
      virtio0 = mkOption {
        type = types.str;
        default = "local-lvm:vm-9999-disk-0";
        example = "ceph:vm-123-disk-0";
        description = ''
          Configuration for the default virtio disk. It can be used as a cue for PVE to autodetect the target storage.
          This parameter is required by PVE even if it isn't used.
        '';
      };
      ostype = mkOption {
        type = types.str;
        default = "l26";
        description = ''
          Guest OS type
        '';
      };
      cores = mkOption {
        type = types.ints.positive;
        default = 1;
        description = ''
          Guest core count
        '';
      };
      memory = mkOption {
        type = types.ints.positive;
        default = 1024;
        description = ''
          Guest memory in MiB (1024×1024 bytes)
        '';
      };
      bios = mkOption {
        type = types.enum [
          "seabios"
          "ovmf"
        ];
        default = "seabios";
        description = ''
          Select BIOS implementation (seabios = Legacy BIOS, ovmf = UEFI).
        '';
      };

      # optional configs
      name = mkOption {
        type = types.str;
        default = "nixos-${config.system.nixos.label}";
        description = ''
          VM name
        '';
      };
      additionalSpace = mkOption {
        type = types.str;
        default = "512M";
        example = "2048M";
        description = ''
          additional disk space to be added to the image if diskSize "auto"
          is used.
        '';
      };
      bootSize = mkOption {
        type = types.str;
        default = "256M";
        example = "512M";
        description = ''
          Size of the boot partition. Is only used if partitionTableType is
          either "efi" or "hybrid".
        '';
      };
      net0 = mkOption {
        type = types.commas;
        default = "virtio=00:00:00:00:00:00,bridge=vmbr0,firewall=1";
        description = ''
          Configuration for the default interface. When restoring from VMA, check the
          "unique" box to ensure device mac is randomized.
        '';
      };
      serial0 = mkOption {
        type = types.str;
        default = "socket";
        example = "/dev/ttyS0";
        description = ''
          Create a serial device inside the VM (n is 0 to 3), and pass through a host serial device (i.e. /dev/ttyS0),
          or create a unix socket on the host side (use qm terminal to open a terminal connection).
        '';
      };
      agent = mkOption {
        type = types.bool;
        apply = x: if x then "1" else "0";
        default = true;
        description = ''
          Expect guest to have qemu agent running
        '';
      };
    };
    qemuExtraConf = mkOption {
      type =
        with types;
        attrsOf (oneOf [
          str
          int
        ]);
      default = { };
      example = literalExpression ''
        {
          cpu = "host";
          onboot = 1;
        }
      '';
      description = ''
        Additional options appended to qemu-server.conf
      '';
    };
    partitionTableType = mkOption {
      type = types.enum [
        "efi"
        "hybrid"
        "legacy"
        "legacy+gpt"
      ];
      description = ''
        Partition table type to use. See make-disk-image.nix partitionTableType for details.
        Defaults to 'legacy' for 'proxmox.qemuConf.bios="seabios"' (default), other bios values defaults to 'efi'.
        Use 'hybrid' to build grub-based hybrid bios+efi images.
      '';
      default = if config.proxmox.qemuConf.bios == "seabios" then "legacy" else "efi";
      defaultText = lib.literalExpression ''if config.proxmox.qemuConf.bios == "seabios" then "legacy" else "efi"'';
      example = "hybrid";
    };
    filenameSuffix = mkOption {
      type = types.str;
      default = config.proxmox.qemuConf.name;
      example = "999-nixos_template";
      description = ''
        Filename of the image will be vzdump-qemu-''${filenameSuffix}.vma.zstd.
        This will also determine the default name of the VM on restoring the VMA.
        Start this value with a number if you want the VMA to be detected as a backup of
        any specific VMID.
      '';
    };
    cloudInit = {
      enable = mkOption {
        type = types.bool;
        default = true;
        description = ''
          Whether the VM should accept cloud init configurations from PVE.
        '';
      };
      defaultStorage = mkOption {
        default = "local-lvm";
        example = "tank";
        type = types.str;
        description = ''
          Default storage name for cloud init drive.
        '';
      };
      device = mkOption {
        default = "ide2";
        example = "scsi0";
        type = types.str;
        description = ''
          Bus/device to which the cloud init drive is attached.
        '';
      };
    };
  };

  config =
    let
      cfg = config.proxmox;
      cfgLine = name: value: ''
        ${name}: ${toString value}
      '';
      virtio0Storage = builtins.head (builtins.split ":" cfg.qemuConf.virtio0);
      cfgFile =
        fileName: properties:
        pkgs.writeTextDir fileName ''
          # generated by NixOS
          ${lib.concatStrings (lib.mapAttrsToList cfgLine properties)}
          #qmdump#map:virtio0:drive-virtio0:${virtio0Storage}:raw:
        '';
      inherit (cfg) partitionTableType;
      supportEfi = partitionTableType == "efi" || partitionTableType == "hybrid";
      supportBios =
        partitionTableType == "legacy"
        || partitionTableType == "hybrid"
        || partitionTableType == "legacy+gpt";
      hasBootPartition = partitionTableType == "efi" || partitionTableType == "hybrid";
      hasNoFsPartition = partitionTableType == "hybrid" || partitionTableType == "legacy+gpt";
      postVM =
        let
          # Build qemu with PVE's patch that adds support for the VMA format
          vma =
            (pkgs.qemu_kvm.override {
              alsaSupport = false;
              pulseSupport = false;
              sdlSupport = false;
              jackSupport = false;
              gtkSupport = false;
              vncSupport = false;
              smartcardSupport = false;
              spiceSupport = false;
              ncursesSupport = false;
              libiscsiSupport = false;
              tpmSupport = false;
              numaSupport = false;
              seccompSupport = false;
              guestAgentSupport = false;
            }).overrideAttrs
              (super: rec {
                # Check https://github.com/proxmox/pve-qemu/tree/master for the version
                # of qemu and patch to use
                version = "9.0.0";
                src = pkgs.fetchurl {
                  url = "https://download.qemu.org/qemu-${version}.tar.xz";
                  hash = "sha256-MnCKxmww2MiSYz6paMdxwcdtWX1w3erSGg0izPOG2mk=";
                };
                patches = [
                  # Proxmox' VMA tool is published as a particular patch upon QEMU
                  "${
                    pkgs.fetchFromGitHub {
                      owner = "proxmox";
                      repo = "pve-qemu";
                      rev = "14afbdd55f04d250bd679ca1ad55d3f47cd9d4c8";
                      hash = "sha256-lSJQA5SHIHfxJvMLIID2drv2H43crTPMNIlIT37w9Nc=";
                    }
                  }/debian/patches/pve/0027-PVE-Backup-add-vma-backup-format-code.patch"
                ];

                buildInputs = super.buildInputs ++ [ pkgs.libuuid ];
                nativeBuildInputs = super.nativeBuildInputs ++ [ pkgs.perl ];

              });
        in
        ''
          ${vma}/bin/vma create "${config.image.baseName}.vma" \
            -c ${
              cfgFile "qemu-server.conf" (cfg.qemuConf // cfg.qemuExtraConf)
            }/qemu-server.conf drive-virtio0=$diskImage
          rm $diskImage
          ${pkgs.zstd}/bin/zstd "${config.image.baseName}.vma"
          mv "${config.image.fileName}" $out/

          mkdir -p $out/nix-support
          echo "file vma $out/${config.image.fileName}" > $out/nix-support/hydra-build-products
        '';
      pveBaseConfigs = {
        name = config.image.baseName;
        baseName = config.image.baseName;
        inherit (cfg) partitionTableType;
        inherit (cfg.qemuConf) additionalSpace bootSize;
        inherit (config.virtualisation) diskSize;
        format = "raw";
        inherit config lib pkgs;
      };
    in
    {
      assertions = [
        {
          assertion = config.boot.loader.systemd-boot.enable -> config.proxmox.qemuConf.bios == "ovmf";
          message = "systemd-boot requires 'ovmf' bios";
        }
        {
          assertion = partitionTableType == "efi" -> config.proxmox.qemuConf.bios == "ovmf";
          message = "'efi' disk partitioning requires 'ovmf' bios";
        }
        {
          assertion = partitionTableType == "legacy" -> config.proxmox.qemuConf.bios == "seabios";
          message = "'legacy' disk partitioning requires 'seabios' bios";
        }
        {
          assertion = partitionTableType == "legacy+gpt" -> config.proxmox.qemuConf.bios == "seabios";
          message = "'legacy+gpt' disk partitioning requires 'seabios' bios";
        }
      ];
      image.baseName = lib.mkDefault "vzdump-qemu-${cfg.filenameSuffix}";
      image.extension = "vma.zst";
      system.build = {
        cloudImage = import ../../lib/make-disk-image.nix pveBaseConfigs;
        VMA = import ../../lib/make-disk-image.nix (
          pveBaseConfigs
          // {
            inherit postVM;
          }
        );
        image = config.system.build.VMA;
      };

      boot = {
        growPartition = true;
        kernelParams = [ "console=ttyS0" ];
        loader.grub = {
          device = lib.mkDefault (
            if (hasNoFsPartition || supportBios) then
              # Even if there is a separate no-fs partition ("/dev/disk/by-partlabel/no-fs" i.e. "/dev/vda2"),
              # which will be used the bootloader, do not set it as loader.grub.device.
              # GRUB installation fails, unless the whole disk is selected.
              "/dev/vda"
            else
              "nodev"
          );
          efiSupport = lib.mkDefault supportEfi;
          efiInstallAsRemovable = lib.mkDefault supportEfi;
        };

        loader.timeout = 0;
        initrd.availableKernelModules = [
          "uas"
          "virtio_blk"
          "virtio_pci"
        ];
      };

      fileSystems."/" = {
        device = "/dev/disk/by-label/nixos";
        autoResize = true;
        fsType = "ext4";
      };
      fileSystems."/boot" = lib.mkIf hasBootPartition {
        device = "/dev/disk/by-label/ESP";
        fsType = "vfat";
      };

      networking = mkIf cfg.cloudInit.enable {
        hostName = mkForce "";
        useDHCP = false;
      };

      services = {
        cloud-init = mkIf cfg.cloudInit.enable {
          enable = true;
          network.enable = true;
        };
        sshd.enable = mkDefault true;
        qemuGuest.enable = true;
      };

      proxmox.qemuExtraConf.${cfg.cloudInit.device} =
        "${cfg.cloudInit.defaultStorage}:vm-9999-cloudinit,media=cdrom";
    };
}
