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

with lib;
let
  inherit (lib.strings) concatStringsSep;
  cfg = config.fudo.mail-server;

in {

  options.fudo.mail-server = {
    enable = mkEnableOption "Fudo Email Server";

    enableContainer = mkEnableOption ''
      Run the mail server in a container.

      Mutually exclusive with mail-server.enable.
    '';

    domain = mkOption {
      type = types.str;
      description = "The main and default domain name for this email server.";
    };

    hostname = mkOption {
      type = types.str;
      description = "The domain name to use for the mail server.";
    };

    monitoring = mkEnableOption "Enable monitoring for the mail server.";

    mail-user = mkOption {
      type = types.str;
      description = "User to use for mail delivery.";
    };

    # No group id, because NixOS doesn't seem to use it
    mail-group = mkOption {
      type = types.str;
      description = "Group to use for mail delivery.";
    };

    mail-user-id = mkOption {
      type = types.int;
      description = "UID of mail-user.";
    };

    local-domains = mkOption {
      type = with types; listOf str;
      description = "A list of domains for which we accept mail.";
      default = ["localhost" "localhost.localdomain"];
      example = [
        "localhost"
        "localhost.localdomain"
        "somedomain.com"
        "otherdomain.org"
      ];
    };

    mail-directory = mkOption {
      type = types.str;
      description = "Path to use for mail storage.";
    };

    state-directory = mkOption {
      type = types.str;
      description = "Path to use for state data.";
    };

    trusted-networks = mkOption {
      type = with types; listOf str;
      description = "A list of trusted networks, for which we will happily relay without auth.";
      example = [
        "10.0.0.0/16"
        "192.168.0.0/24"
      ];
    };

    sender-blacklist = mkOption {
      type = with types; listOf str;
      description = "A list of email addresses for whom we will not send email.";
      default = [];
      example = [
        "baduser@test.com"
        "change-pw@test.com"
      ];
    };

    recipient-blacklist = mkOption {
      type = with types; listOf str;
      description = "A list of email addresses for whom we will not accept email.";
      default = [];
      example = [
        "baduser@test.com"
        "change-pw@test.com"
      ];
    };

    message-size-limit = mkOption {
      type = types.int;
      description = "Size of max email in megabytes.";
      default = 30;
    };

    user-aliases = mkOption {
      type = with types; attrsOf(listOf str);
      description = "A map of real user to list of aliases.";
      default = {};
      example = {
        someuser = ["alias0" "alias1"];
      };
    };

    alias-users = mkOption {
      type = with types; attrsOf(listOf str);
      description = "A map of email alias to a list of users.";
      example = {
        alias = ["realuser0" "realuser1"];
      };
    };

    mailboxes = mkOption {
      description = ''
        The mailboxes for dovecot.

        Depending on the mail client used it might be necessary to change some mailbox's name.
     '';
      default = {
        Trash = {
          auto = "create";
          specialUse = "Trash";
          autoexpunge = "30d";
        };
        Junk = {
          auto = "create";
          specialUse = "Junk";
          autoexpunge = "60d";
        };
        Drafts = {
          auto = "create";
          specialUse = "Drafts";
          autoexpunge = "60d";
        };
        Sent = {
          auto = "subscribe";
          specialUse = "Sent";
        };
        Archive = {
          auto = "no";
          specialUse = "Archive";
        };
        Flagged = {
          auto = "no";
          specialUse = "Flagged";
        };
      };
    };

    debug = mkOption {
      description = "Enable debugging on mailservers.";
      type = types.bool;
      default = false;
    };

    max-user-connections = mkOption {
      description = "Max simultaneous connections per user.";
      type = types.int;
      default = 20;
    };
  };

  imports = [
    ./mail/dkim.nix
    ./mail/dovecot.nix
    ./mail/postfix.nix
    ./mail/rspamd.nix
    ./mail/clamav.nix
  ];

  config =  mkIf cfg.enable {
    networking.firewall = {
      allowedTCPPorts = [ 25 110 143 587 993 995 ];
    };
    
    users = {
      users = {
        mailuser = {
          isSystemUser = true;
          uid = cfg.mail-user-id;
          group = "mailgroup";
        };
      };

      groups = {
        mailgroup = {
          members = ["mailuser"];
        };
      };
    };
  };
}