{ inputs, pkgs, lib, config, ... }:
let
  inherit (builtins) hasAttr;
  inherit (config) networking;
  inherit (config.services) openldap postfix dovecot2;
  inherit (config.users) users groups;
  inherit (pkgs.lib) unlines;
  domain = "sourcephile.fr";
  domainGroup = "sourcephile";
  domainOrg = "sourcephile";
  domainSuffix = "dc=" + lib.concatStringsSep ",dc=" (lib.splitString "." domain);
  posixAccount = pkgs.callPackage (import ./posixAccount.nix) { inherit domain domainSuffix domainGroup; };
in
{
users.groups."${domainGroup}" = {
  gid = 20000;
  members = [users."julm".name];
};
# DEBUG: echo "$(nixops show-option mermet -d production services.openldap.databases."g".data)"
services.openldap.databases."${domainSuffix}" = {
  # DEBUG: sudo ldapsearch -LLL -H ldapi:// -D cn=admin,cn=config -Y EXTERNAL -b 'olcDatabase={1}mdb,cn=config' -s sub
  # WARNING: newlines matter
  conf = ''
    dn: olcDatabase=mdb,cn=config
    objectClass: olcDatabaseConfig
    objectClass: olcMdbConfig
    # Checkpoint the database periodically in case of system failure
    # and to speed up slapd shutdown.
    olcDbCheckpoint: 512 30
    # Database max size is 1G
    olcDbMaxSize: 1073741824
    olcLastMod: TRUE
    # Database superuser. Needed for syncrepl.
    olcRootDN: cn=admin,${domainSuffix}
    # Superuser password, generated with slappasswd -h "{SSHA}"
    # Commented-out because SASL EXTERNAL mechanism is used.
    #olcRootPW: {SSHA}COkATGNe7rs/g8vWcYP5rqt4u5sWdMgP
    #
    olcDbIndex: objectClass eq
    olcDbIndex: cn,uid eq
    olcDbIndex: uidNumber,gidNumber eq
    olcDbIndex: member,memberUid eq
    olcDbIndex: mail eq
    olcDbIndex: mailAlias eq
    olcDbIndex: mailEnabled eq
    #
    olcAccess: to attrs=userPassword
      by self write
      by anonymous auth
      by dn="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" write
      by * none
    olcAccess: to attrs=shadowLastChange
      by self write
      by dn="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" write
      by * none
    olcAccess: to dn.sub="ou=posix,${domainSuffix}"
      by self read
      ${lib.optionalString (hasAttr postfix.user users) ''by dn="gidNumber=${toString groups.postfix.gid}+uidNumber=${toString users.postfix.uid},cn=peercred,cn=external,cn=auth" read''}
      ${lib.optionalString (hasAttr dovecot2.user users) ''by dn="gidNumber=${toString groups.dovecot2.gid}+uidNumber=${toString users.dovecot2.uid},cn=peercred,cn=external,cn=auth" read''}
      by dn="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" read
    olcAccess: to *
      by self read
      by * none
  '';
  data = ''
    dn: ${domainSuffix}
    objectClass: top
    objectClass: dcObject
    objectClass: organization
    o: ${domainOrg}

    dn: cn=admin,${domainSuffix}
    objectClass: simpleSecurityObject
    objectClass: organizationalRole
    description: ${domainOrg} LDAP administrator
    roleOccupant: ${domainSuffix}
    userPassword: 

    dn: ou=posix,${domainSuffix}
    objectClass: top
    objectClass: organizationalUnit

    dn: ou=accounts,ou=posix,${domainSuffix}
    objectClass: top
    objectClass: organizationalUnit

    dn: ou=groups,ou=posix,${domainSuffix}
    objectClass: top
    objectClass: organizationalUnit

  ''
/*
    dn: cn=${domainGroup},ou=groups,ou=posix,${domainSuffix}
    objectClass: top
    objectClass: posixGroup
    gidNumber: 20000
    memberUid: julm

    dn: cn=autogeree,ou=groups,ou=posix,${domainSuffix}
    objectClass: top
    objectClass: posixGroup
    gidNumber: 20001
    memberUid: julm
*/
  + lib.concatMapStrings posixAccount [ rec
    { uid = "julm";
      cn = "Julien Moutinho";
      sn = uid;
      uidNumber = users."julm".uid;
      gidNumber = groups."users".gid;
      mailAlias = [ "julien.moutinho" ];
      userPassword = builtins.readFile (inputs.secrets + "/members/mail/julm/hashedPassword");
      mailHomeDirectory = "/home/${uid}/mail/${domain}";
      mailStorageDirectory =
        let stateDir = "/var/lib/dovecot"; in
        # I'm personnaly using "maildir:" instead of "sdbox:" to be able to use a local (neo)mutt on it,
        # bypassing IMAP because (neo)mutt support of IMAP is very bad
        # (can't even have a decent $folder_format (with %n or %m) working,
        # neither sorting them by date).
        # WARNING: regarding the atomicity of backuping,
        # it's not a good idea to put the mails
        # and the index/control on different ZFS datasets like here.
        "maildir:/home/${uid}/mail/${domain}/mail:LAYOUT=maildir++:UTF-8:CONTROL=${stateDir}/control/${domain}/${uid}:INDEX=${stateDir}/index/${domain}/${uid}";
    }
  ];
};
}