{
  lib,
  config,
  pkgs,
  vhackPackages,
  ...
}: let
  cfg = config.vhack.stalwart-mail;
  topCfg = config.services.stalwart-mail;

  configFormat = pkgs.formats.toml {};
  configFile = configFormat.generate "stalwart-mail.toml" topCfg.settings;
in {
  imports = [
    ./settings.nix
  ];

  options.vhack.stalwart-mail = {
    enable = lib.mkEnableOption "starwart-mail";

    package = lib.mkPackageOption vhackPackages "stalwart-mail-free" {};

    admin = lib.mkOption {
      description = ''
        Email address to advertise as administrator. This is the address, where dkim, spv
        etc. refusal reports are sent to.

        The format should be: `mailto:<name>@<domain>`
      '';
      type = lib.types.str;
      example = "mailto:dmarc+rua@example.com";
      default = "";
    };

    fqdn = lib.mkOption {
      type = lib.types.str;
      example = "mail.foss-syndicate.org";
      description = ''
        The fully qualified domain name for this mail server.
      '';
    };

    principals = lib.mkOption {
      default = [];
      type = lib.types.listOf (lib.types.submodule {
        options = {
          name = lib.mkOption {
            type = lib.types.str;
            description = "Specifies the username of the account";
          };

          class = lib.mkOption {
            type = lib.types.enum ["individual" "admin"];
            description = "Specifies the account type";
          };

          description = lib.mkOption {
            type = lib.types.str;
            description = "Provides a description or full name for the user";
            default = "";
          };

          secret = lib.mkOption {
            type = lib.types.str;
            description = ''
              Sets the password for the user account.
              Passwords can be stored hashed or in plain text (not recommended).
              See <https://stalw.art/docs/auth/authentication/password/> for a description
              of password encoding.
            '';
          };
          email = lib.mkOption {
            type = lib.types.listOf lib.types.str;
            description = ''
              A list of email addresses associated with the user.
              The first address in the list is considered the primary address.
            '';
          };
        };
      });
    };

    dataDirectory = lib.mkOption {
      description = ''
        The directory in which to store all storage things.
      '';
      default = "/var/lib/stalwart-mail";
      type = lib.types.path;
      readOnly = true;
    };

    openFirewall = lib.mkOption {
      type = lib.types.bool;
      default = false;
      description = ''
        Whether to open TCP firewall ports, which are specified in
        {option}`services.stalwart-mail.settings.listener` on all interfaces.
      '';
    };

    security = lib.mkOption {
      type = lib.types.nullOr (lib.types.submodule {
        options = {
          verificationMode = lib.mkOption {
            type = lib.types.enum ["relaxed" "strict"];
            description = ''
              Whether to allow invalid signatures/checks or not.
            '';
            default = "relaxed";
          };

          dkimKeys = lib.mkOption {
            type = lib.types.attrsOf (lib.types.submodule {
              options = {
                dkimPublicKey = lib.mkOption {
                  type = lib.types.str;
                  description = ''
                    The base 64 encoded representation of the public dkim key.
                  '';
                };
                dkimPrivateKeyPath = lib.mkOption {
                  type = lib.types.path;
                  description = ''
                    The path to the dkim private key agenix file.
                    Generate it via the `./gen_key` script:
                  '';
                };
                keyAlgorithm = lib.mkOption {
                  type = lib.types.enum ["ed25519-sha256" "rsa-sha-256" "rsa-sha-1"];
                  description = "The algorithm of the used key";
                };
              };
            });
            description = ''
              Which key to use for which domain. The attr keys are the domains
            '';
            default = {};
          };
        };
      });
      description = ''
        Security options. This should only be set to `null` when testing.
      '';
    };
  };

  config = lib.mkIf cfg.enable {
    assertions = [
      {
        assertion = cfg.admin != "";
        message = "You need to specify an admin address.";
      }
    ];

    vhack.nginx.enable = true;
    services = {
      stalwart-mail = {
        # NOTE(@bpeetz): We do not use the NixOS service, as it comes with too much
        # bothersome default configuration and not really any useful configuration.
        # However, this decision could obviously be reversed in the future. <2025-02-08>
        enable = false;
        inherit (cfg) package;
        # dataDir = cfg.dataDirectory;
      };

      # FIXME(@bpeetz): This is currently needed for a successful acme http-01 challenge.
      # We could also use the DNS challenge. <2025-03-01>
      nginx.virtualHosts."${cfg.fqdn}" = {
        enableACME = false;
        extraConfig =
          # This is copied directly from the nixos nginx module.
          # Rule for legitimate ACME Challenge requests (like /.well-known/acme-challenge/xxxxxxxxx)
          # We use ^~ here, so that we don't check any regexes (which could
          # otherwise easily override this intended match accidentally).
          ''
            location ^~ /.well-known/acme-challenge/ {
              root ${config.security.acme.certs.${cfg.fqdn}.webroot};
              auth_basic off;
              auth_request off;
            }
          '';
      };

      redis = {
        servers = {
          "stalwart-mail" = {
            enable = true;

            user = "stalwart-mail";

            # Disable TCP listening. (We have a UNIX socket)
            port = 0;
            bind = null;

            settings = {
              protected-mode = true;
              enable-protected-configs = false;
              enable-debug-command = false;
              enable-module-command = false;

              supervised = "systemd";
              stop-writes-on-bgsave-error = true;
              sanitize-dump-payload = "clients";
            };
          };
        };
      };
    };
    security.acme.certs = {
      "${cfg.fqdn}" = {
        domain = cfg.fqdn;
        group = "stalwart-mail";
      };
    };

    age.secrets = let
      keys =
        lib.mapAttrs' (
          keyDomain: keyConfig:
            lib.nameValuePair "stalwartMail${keyDomain}"
            {
              file = keyConfig.dkimPrivateKeyPath;
              mode = "600";
              owner = "stalwart-mail";
              group = "stalwart-mail";
            }
        )
        cfg.security.dkimKeys;
    in
      lib.mkIf (cfg.security != null) keys;

    vhack.persist.directories = [
      {
        directory = "${cfg.dataDirectory}";
        user = "stalwart-mail";
        group = "stalwart-mail";
        mode = "0700";
      }
      {
        directory = "${config.services.redis.servers."stalwart-mail".settings.dir}";
        user = "stalwart-mail";
        group = "redis";
        mode = "0770";
      }
    ];

    # This service stores a potentially large amount of data.
    # Running it as a dynamic user would force chown to be run every time the
    # service is restarted on a potentially large number of files.
    # That would cause unnecessary and unwanted delays.
    users = {
      groups.stalwart-mail = {};
      users.stalwart-mail = {
        isSystemUser = true;
        group = "stalwart-mail";
      };
    };

    systemd.tmpfiles.rules = [
      "d '${cfg.dataDirectory}' - stalwart-mail stalwart-mail - -"
    ];

    systemd = {
      services.stalwart-mail = {
        wantedBy = ["multi-user.target"];
        requires =
          [
            "redis-stalwart-mail.service"
            "network-online.target"
          ]
          ++ (lib.optional (cfg.security != null) "acme-${cfg.fqdn}.service");
        after = [
          "local-fs.target"
          "network.target"
          "network-online.target"
          "redis-stalwart-mail.service"
          "acme-${cfg.fqdn}.service"
        ];
        conflicts = [
          "postfix.service"
          "sendmail.service"
          "exim4.service"
        ];
        description = "Stalwart Mail Server";

        environment = {
          SSL_CERT_FILE = "/etc/ssl/certs/ca-certificates.crt";
          NIX_SSL_CERT_FILE = "/etc/ssl/certs/ca-certificates.crt";
        };

        preStart = let
          esa = lib.strings.escapeShellArg;
          mkTmpFile = path: "[ -d ${esa path} ] || mkdir --parents ${esa path}";

          # Create the directories for stalwart
          storageDirectories = lib.lists.filter (v: v != null) (lib.attrsets.mapAttrsToList (_: {path ? null, ...}:
            if (path != null)
            then mkTmpFile path
            else null)
          topCfg.settings.store);
        in
          ''
            # Stalwart actually wants to store _data_ (e.g., blocked ips) in it's own config file.
            # Thus we need to make it writable.
            cat ${esa configFile} >$CACHE_DIRECTORY/mutable_config_file.toml
          ''
          + (builtins.concatStringsSep "\n" storageDirectories);

        serviceConfig = {
          ExecStart = pkgs.writers.writeDash "start-stalwart-mail" ''
            ${lib.getExe cfg.package} --config="$CACHE_DIRECTORY/mutable_config_file.toml"
          '';

          Restart = "on-failure";
          RestartSec = 5;

          KillMode = "process";
          KillSignal = "SIGINT";

          Type = "simple";
          LimitNOFILE = 65536;

          StandardOutput = "journal";
          StandardError = "journal";

          ReadWritePaths = [
            cfg.dataDirectory
          ];
          CacheDirectory = "stalwart-mail";
          StateDirectory = "stalwart-mail";

          User = "stalwart-mail";
          Group = "stalwart-mail";

          SyslogIdentifier = "stalwart-mail";

          # Bind standard privileged ports
          AmbientCapabilities = ["CAP_NET_BIND_SERVICE"];
          CapabilityBoundingSet = ["CAP_NET_BIND_SERVICE"];

          # Hardening
          DeviceAllow = [""];
          LockPersonality = true;
          MemoryDenyWriteExecute = true;
          PrivateDevices = true;
          PrivateUsers = false; # incompatible with CAP_NET_BIND_SERVICE
          ProcSubset = "pid";
          PrivateTmp = true;
          ProtectClock = true;
          ProtectControlGroups = true;
          ProtectHome = true;
          ProtectHostname = true;
          ProtectKernelLogs = true;
          ProtectKernelModules = true;
          ProtectKernelTunables = true;
          ProtectProc = "invisible";
          ProtectSystem = "strict";
          RestrictAddressFamilies = [
            "AF_INET"
            "AF_INET6"
            "AF_UNIX"
          ];
          RestrictNamespaces = true;
          RestrictRealtime = true;
          RestrictSUIDSGID = true;
          SystemCallArchitectures = "native";
          SystemCallFilter = [
            "@system-service"
            "~@privileged"
          ];
          UMask = "0077";
        };
      };
    };

    # Make admin commands available in the shell
    environment.systemPackages = [cfg.package];

    networking.firewall = let
      parsePorts = listeners: let
        parseAddresses = listeners: lib.flatten (lib.mapAttrsToList (name: value: value.bind) listeners);
        splitAddress = addr: lib.splitString ":" addr;
        extractPort = addr: lib.toInt (builtins.foldl' (a: b: b) "" (splitAddress addr));
      in
        builtins.map extractPort (parseAddresses listeners);
    in
      lib.mkIf (cfg.openFirewall && (builtins.hasAttr "listener" topCfg.settings.server))
      {
        allowedTCPPorts = parsePorts topCfg.settings.server.listener;
      };
  };
}