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

let cfg = config.sydnix.deertopia.authelia;
in {
  options.sydnix.deertopia.authelia = {
    enable = lib.mkEnableOption ''Deertopia's Authelia'';
    httpPort = lib.mkOption {
      description = ''
        The port on which Authelia's web UI will be served.
      '';
      type = lib.types.port;
      default = 9091;
    };
    bindUserName = lib.mkOption {
      description = ''
        The name of the LDAP user Authelia will bind as.
      '';
      type = lib.types.str;
      default = "authelia";
    };
  };

  config = lib.mkIf cfg.enable
    (let authelia-state-dir = "/var/lib/authelia-deertopia";
     in {
       sydnix.sops.secrets =
         let e = {
               mode = "0600";
               owner = config.services.authelia.instances."deertopia".user;
               group = config.services.authelia.instances."deertopia".group;
             };
         in {
           authelia-jwt-secret = e;
           authelia-session-secret = e;
           authelia-storage-encryption-key = e;
           authelia-authentication-backend-ldap-password = e;
         };

       sydnix.impermanence.directories = [
         authelia-state-dir
       ];

       # See:
       #  - https://github.com/authelia/authelia/blob/v4.38.19/config.template.yml
       #  - https://matwick.ca/authelia-nginx-sso/
       #  - https://www.gandalfk7.it/posts/20220713_01_sso-with-lldap-authelia-and-nginx/
       services.authelia.instances."deertopia" = {
         enable = true;
         # "Automatic" secrets are seemingly broken and offer little more than
         # some assertions from the Nix module.
         secrets.manual = true;
         environmentVariables = {
           AUTHELIA_JWT_SECRET_FILE =
             "/run/secrets/authelia-jwt-secret";
           AUTHELIA_SESSION_SECRET_FILE =
             "/run/secrets/authelia-session-secret";
           AUTHELIA_STORAGE_ENCRYPTION_KEY_FILE =
             "/run/secrets/authelia-storage-encryption-key";
           AUTHELIA_AUTHENTICATION_BACKEND_LDAP_PASSWORD_FILE =
             "/run/secrets/authelia-authentication-backend-ldap-password";
         };
         settings = {
           default_2fa_method = "totp";
           theme = "auto";
           server = {
             address = "tcp://:${builtins.toString cfg.httpPort}";
             # asset_path = "${authelia-state-dir}/assets";
             # Necessary for Nginx integration.  No, I do not understand what it
             # does.
             endpoints.authz.auth-request.implementation = "AuthRequest";
           };
           authentication_backend =
             let base-dn = config.services.lldap.settings.ldap_base_dn;
                 ldap-port =
                   builtins.toString config.services.lldap.settings.ldap_port;
             in {
               password_reset.disable = false;
               refresh_interval = "1 minutes";
               ldap = {
                 implementation = "custom";
                 address = "ldap://127.0.0.1:${ldap-port}";
                 timeout = "5s";
                 start_tls = "false";
                 base_dn = base-dn;
                 additional_users_dn = "ou=people";
                 additional_groups_dn = "ou=groups";
                 groups_filter = "(member={dn})";
                 users_filter = "(&({username_attribute}={input})(objectClass=person))";
                 attributes = {
                   username = "uid";
                   group_name = "cn";
                   mail = "mail";
                   display_name = "displayName";
                 };
                 user = "uid=${cfg.bindUserName},ou=people,${base-dn}";
               };
             };
           access_control = {
             default_policy = "deny";
             rules = [
               {
                 domain = "*.deertopia.net";
                 policy = "one_factor";
               }
             ];
           };
           session = {
             name = "authelia_session";
             same_site = "lax";
             inactivity = "5 minutes";
             expiration = "1 hour";
             remember_me = "1 month";
             cookies = [
               {
                 domain = "deertopia.net";
                 authelia_url = "https://auth.deertopia.net";
                 default_redirection_url = "https://deertopia.net";
               }
             ];
           };
           storage.local.path = "${authelia-state-dir}/db.sqlite";
           notifier = {
             disable_startup_check = false;
             filesystem.filename = "${authelia-state-dir}/notifications";
           };
           # Default is false, which prevents anything from showing up when you run
           # `systemctl status authelia-deertopia`, which is really, really confusing.
           log = {
             keep_stdout = true;
             file_path = "${authelia-state-dir}/authelia.log";
           };
         };
       };

       sydnix.deertopia.nginx.vhosts."auth" = {
         directory = null;
         vhost = {
           forceSSL = true;
           enableACME = true;
           extraConfig = ''
             set $upstream http://127.0.0.1:${builtins.toString cfg.httpPort};
           '';
           locations."/".extraConfig = ''
             include ${./authelia/proxy.conf};
             proxy_pass $upstream;
           '';
           locations."/api/verify".proxyPass = "$upstream";
           locations."/api/authz".proxyPass = "$upstream";
         };
       };
     });
}
