{ pkgs, ... }:
let
  certs = import ./common/acme/server/snakeoil-certs.nix;
  domain = certs.domain;
in
{
  name = "rspamd-trainer";
  meta = with pkgs.lib.maintainers; {
    maintainers = [ onny ];
  };

  nodes = {
    machine =
      { options, config, ... }:
      {

        security.pki.certificateFiles = [
          certs.ca.cert
        ];

        networking.extraHosts = ''
          127.0.0.1 ${domain}
        '';

        services.rspamd-trainer = {
          enable = true;
          settings = {
            HOST = domain;
            USERNAME = "spam@${domain}";
            INBOXPREFIX = "INBOX/";
          };
          secrets = [
            # Do not use this in production. This will make passwords
            # world-readable in the Nix store
            "${pkgs.writeText "secrets" ''
              PASSWORD = test123
            ''}"
          ];
        };

        services.maddy = {
          enable = true;
          hostname = domain;
          primaryDomain = domain;
          ensureAccounts = [ "spam@${domain}" ];
          ensureCredentials = {
            # Do not use this in production. This will make passwords world-readable
            # in the Nix store
            "spam@${domain}".passwordFile = "${pkgs.writeText "postmaster" "test123"}";
          };
          tls = {
            loader = "file";
            certificates = [
              {
                certPath = "${certs.${domain}.cert}";
                keyPath = "${certs.${domain}.key}";
              }
            ];
          };
          config =
            builtins.replaceStrings
              [
                "imap tcp://0.0.0.0:143"
                "submission tcp://0.0.0.0:587"
              ]
              [
                "imap tls://0.0.0.0:993 tcp://0.0.0.0:143"
                "submission tls://0.0.0.0:465 tcp://0.0.0.0:587"
              ]
              options.services.maddy.config.default;
        };

        services.rspamd = {
          enable = true;
          locals = {
            "redis.conf".text = ''
              servers = "${config.services.redis.servers.rspamd.unixSocket}";
            '';
            "classifier-bayes.conf".text = ''
              backend = "redis";
              autolearn = true;
            '';
          };
        };

        services.redis.servers.rspamd = {
          enable = true;
          port = 0;
          unixSocket = "/run/redis-rspamd/redis.sock";
          user = config.services.rspamd.user;
        };

        environment.systemPackages = [
          (pkgs.writers.writePython3Bin "send-testmail" { } ''
            import smtplib
            import ssl
            from email.mime.text import MIMEText
            context = ssl.create_default_context()
            msg = MIMEText("Hello World")
            msg['Subject'] = 'Test'
            msg['From'] = "spam@${domain}"
            msg['To'] = "spam@${domain}"
            with smtplib.SMTP_SSL(host='${domain}', port=465, context=context) as smtp:
                smtp.login('spam@${domain}', 'test123')
                smtp.sendmail(
                  'spam@${domain}', 'spam@${domain}', msg.as_string()
                )
          '')
          (pkgs.writers.writePython3Bin "create-mail-dirs" { } ''
            import imaplib
            with imaplib.IMAP4_SSL('${domain}') as imap:
                imap.login('spam@${domain}', 'test123')
                imap.create("\"INBOX/report_spam\"")
                imap.create("\"INBOX/report_ham\"")
                imap.create("\"INBOX/report_spam_reply\"")
                imap.select("INBOX")
                imap.copy("1", "\"INBOX/report_ham\"")
                imap.logout()
          '')
          (pkgs.writers.writePython3Bin "test-imap" { } ''
            import imaplib
            with imaplib.IMAP4_SSL('${domain}') as imap:
                imap.login('spam@${domain}', 'test123')
                imap.select("INBOX/learned_ham")
                status, refs = imap.search(None, 'ALL')
                assert status == 'OK'
                assert len(refs) == 1
                status, msg = imap.fetch(refs[0], 'BODY[TEXT]')
                assert status == 'OK'
                assert msg[0][1].strip() == b"Hello World"
                imap.logout()
          '')
        ];

      };

  };

  testScript =
    { nodes }:
    ''
      start_all()
      machine.wait_for_unit("maddy.service")
      machine.wait_for_open_port(143)
      machine.wait_for_open_port(993)
      machine.wait_for_open_port(587)
      machine.wait_for_open_port(465)

      # Send test mail to spam@domain
      machine.succeed("send-testmail")

      # Create mail directories required for rspamd-trainer and copy mail from
      # INBOX into INBOX/report_ham
      machine.succeed("create-mail-dirs")

      # Start rspamd-trainer. It should read mail from INBOX/report_ham
      machine.wait_for_unit("rspamd.service")
      machine.wait_for_unit("redis-rspamd.service")
      machine.wait_for_file("/run/rspamd/rspamd.sock")
      machine.succeed("systemctl start rspamd-trainer.service")

      # Check if mail got processed by rspamd-trainer successfully and check for
      # it in INBOX/learned_ham
      machine.succeed("test-imap")
    '';
}
