{
  lib,
  pkgs,
  config,
  ...
}: let
  qbittorent_data_directory = "/var/lib/qbittorrent";
in {
  options.services.qbittorrent = {
    enable = lib.mkEnableOption "should the headless qbittorrent service be enabled";

    dataDir = lib.mkOption {
      type = lib.types.path;
      default = "/var/lib/qbittorrent";
      description = lib.mdDoc ''
        The directory where qBittorrent stores its data files.
      '';
    };

    mediaDir = lib.mkOption {
      type = lib.types.path;
      description = lib.mdDoc ''
        The directory to create to store qbittorrent media.
      '';
    };

    user = lib.mkOption {
      type = lib.types.str;
      default = "qbittorrent";
      description = lib.mdDoc ''
        User account under which qBittorrent runs.
      '';
    };

    group = lib.mkOption {
      type = lib.types.str;
      default = "qbittorrent";
      description = lib.mdDoc ''
        Group under which qBittorrent runs.
      '';
    };

    webPort = lib.mkOption {
      type = lib.types.port;
      default = 8080;
      description = lib.mdDoc ''
        qBittorrent web UI port.
      '';
    };

    openFirewall = lib.mkOption {
      type = lib.types.bool;
      default = false;
      description = "Open services.qBittorrent.webPort to the outside network.";
    };

    package = lib.mkOption {
      type = lib.types.package;
      default = pkgs.qbittorrent-nox;
      defaultText = lib.literalExpression "pkgs.qbittorrent-nox";
      description = "The qbittorrent package to use.";
    };
  };

  config = lib.mkIf config.services.qbittorrent.enable (lib.mkMerge [
    {
      networking.firewall = lib.mkIf config.services.qbittorrent.openFirewall {
        allowedTCPPorts = [config.services.qbittorrent.webPort];
      };

      systemd.services.qbittorrent = {
        # based on the plex.nix service module and
        # https://github.com/qbittorrent/qBittorrent/blob/master/dist/unix/systemd/qbittorrent-nox%40.service.in
        description = "qBittorrent-nox service";
        documentation = ["man:qbittorrent-nox(1)"];
        after = ["network.target"];
        wantedBy = ["multi-user.target"];

        serviceConfig = {
          Type = "simple";
          User = config.services.qbittorrent.user;
          Group = config.services.qbittorrent.group;

          # Run the pre-start script with full permissions (the "!" prefix) so it
          # can create the data directory if necessary.
          ExecStartPre = let
            preStartScript = pkgs.writeScript "qbittorrent-run-prestart" ''
              #!${pkgs.bash}/bin/bash

              # Create data directory if it doesn't exist
              if ! test -d "$QBT_PROFILE"; then
                echo "Creating initial qBittorrent data directory in: $QBT_PROFILE"
                install -d -m 0755 -o "${config.services.qbittorrent.user}" -g "${config.services.qbittorrent.group}" "$QBT_PROFILE"
              fi
            '';
          in "!${preStartScript}";

          #ExecStart = "${pkgs.qbittorrent-nox}/bin/qbittorrent-nox";
          ExecStart = "${config.services.qbittorrent.package}/bin/qbittorrent-nox";
          # To prevent "Quit & shutdown daemon" from working; we want systemd to
          # manage it!
          #Restart = "on-success";
          #UMask = "0002";
          #LimitNOFILE = cfg.openFilesLimit;
        };

        environment = {
          QBT_PROFILE = config.services.qbittorrent.dataDir;
          QBT_WEBUI_PORT = toString config.services.qbittorrent.webPort;
        };
      };
    }
    (lib.mkIf config.host.impermanence.enable {
      fileSystems."/persist/system/qbittorrent".neededForBoot = true;

      host.storage.pool.extraDatasets = {
        # sops age key needs to be available to pre persist for user generation
        "persist/system/qbittorrent" = {
          type = "zfs_fs";
          mountpoint = "/persist/system/qbittorrent";
          options = {
            canmount = "on";
          };
        };
      };

      assertions = [
        {
          assertion = config.services.qbittorrent.dataDir == qbittorent_data_directory;
          message = "qbittorrent data directory does not match persistence";
        }
      ];

      environment.persistence = {
        "/persist/system/root" = {
          directories = [
            {
              directory = qbittorent_data_directory;
              user = "qbittorrent";
              group = "qbittorrent";
            }
          ];
        };

        "/persist/system/qbittorrent" = {
          enable = true;
          hideMounts = true;
          directories = [
            {
              directory = config.services.qbittorrent.mediaDir;
              user = "qbittorrent";
              group = "qbittorrent";
              mode = "1775";
            }
          ];
        };
      };
    })
  ]);
}