# Adapted and simplified from https://nixos.wiki/wiki/Mailman
{
  config,
  lib,
  pkgs,
  ...
}: let
  inherit
    (lib)
    mkIf
    mkEnableOption
    mkOption
    ;
  inherit (lib.types) nonEmptyStr;
  cfg = config.services.mathebau-mailman;
in {
  options.services.mathebau-mailman = {
    enable = mkEnableOption "mathebau mailman service";
    hostName = mkOption {
      type = nonEmptyStr;
    };
    siteOwner = mkOption {
      type = nonEmptyStr;
    };
  };

  config = mkIf cfg.enable {
    services = {
      postfix = {
        enable = true;
        relayDomains = ["hash:/var/lib/mailman/data/postfix_domains"];
        config = {
          transport_maps = ["hash:/var/lib/mailman/data/postfix_lmtp"];
          local_recipient_maps = ["hash:/var/lib/mailman/data/postfix_lmtp"];
          proxy_interfaces = "130.83.2.184";
          smtputf8_enable = "no"; # HRZ does not know SMTPUTF8
        };
        relayHost = "192.168.0.24"; # Relay to eihort which relays to HRZ (see https://www.hrz.tu-darmstadt.de/services/it_services/email_infrastruktur/index.de.jsp)
      };
      mailman = {
        enable = true;
        inherit (cfg) siteOwner;
        hyperkitty.enable = true;
        webHosts = [cfg.hostName];
        serve.enable = true; #
        # Don't include confirmation tokens in reply addresses, because we would need to send them to HRZ otherwise.
        settings.mta.verp_confirmations = "no";
      };
    };

    environment.persistence.${config.impermanence.name} = {
      directories = [
        "/var/lib/mailman"
        "/var/lib/mailman-web"
      ];
      files = ["/root/.ssh/known_hosts"]; # for the backup server bragi
    };

    networking.firewall.allowedTCPPorts = [25 80];

    # Update HRZ allowlist
    # For account details see https://www-cgi.hrz.tu-darmstadt.de/mail/
    # will stop working if no valid TUIDs are associated to our domain.
    systemd.timers."mailAllowlist" = {
      wantedBy = ["timers.target"];
      timerConfig = {
        OnBootSec = "5m"; # Run every 5 minutes
        OnUnitActiveSec = "5m";
        RandomizedDelaySec = "2m"; # prevent overload on regular intervals
        Unit = "mailAllowlist.service";
      };
    };
    systemd.services."mailAllowlist" = {
      description = "Allowlist update: Post the mail addresses used by mailman to the HRZ allowllist";
      script = ''
        # Get the mail addresses' local-part
        cut -d '@' -f 1 /var/lib/mailman/data/postfix_lmtp | grep -v '#' | grep "\S" > /tmp/addresses
        # Post local-parts to HRZ
        ${pkgs.curl}/bin/curl https://www-cgi.hrz.tu-darmstadt.de/mail/whitelist-update.php -F emaildomain=${cfg.hostName} -F password=$(cat /run/secrets/allowlistPass) -F emailliste=@/tmp/addresses -F meldungen=voll
        # Cleanup
        rm /tmp/addresses
      '';
      serviceConfig = {
        Type = "oneshot";
        User = "mailman";
        NoNewPrivileges = true;
        # See https://www.man7.org/linux/man-pages/man5/systemd.exec.5.html
        PrivateTmp = true;
        ProtectHome = true;
        ReadOnlyPaths = "/";
        ReadWritePaths = "/tmp";
        InaccessiblePaths = "-/lost+found";
        PrivateDevices = true;
        PrivateUsers = true;
        ProtectHostname = true;
        ProtectClock = true;
        ProtectKernelTunables = true;
        ProtectKernelModules = true;
        ProtectKernelLogs = true;
        ProtectControlGroups = true;
        LockPersonality = true;
        MemoryDenyWriteExecute = true;
        RestrictRealtime = true;
        RestrictSUIDSGID = true;
      };
    };

    # Backups
    services.borgbackup.jobs.mailman = {
      paths = [
        "/var/lib/mailman/data"
        "/var/lib/mailman-web"
      ];
      encryption.mode = "none"; # Otherwise the key is next to the backup or we have human interaction.
      environment = {
        BORG_RSH = "ssh -i /run/secrets/backupKey";
        # “Borg ensures that backups are not created on random drives that ‘just happen’ to contain a Borg repository.”
        # https://borgbackup.readthedocs.io/en/stable/deployment/automated-local.html
        # We don't want this in order to not need to persist borg cache and simplify new deployments.
        BORG_UNKNOWN_UNENCRYPTED_REPO_ACCESS_IS_OK = "yes";
      };
      repo = "borg@192.168.1.11:lobon"; # TODO for https://gitea.mathebau.de/Fachschaft/nixConfig/issues/33
      startAt = "daily";
      user = "root";
      group = "root";
    };
  };
}