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

let cfg = config.sydnix.deertopia.lldap;
in {
  options.sydnix.deertopia.lldap = {
    enable = lib.mkEnableOption ''
      Deertopia's lldap, a lightweight authentication server that provides an
      opinionated, simplified LDAP interface for authentication.
    '';
    baseDN = lib.mkOption {
      type = lib.types.str;
      default = "dc=deertopia,dc=net";
    };
  };

  imports = [
    ./lldap/pam.nix
  ];

  config = lib.mkIf cfg.enable {
    # HACK: Why doesn't the lldap module do this?  Sops-nix fails to set the
    # secrets' owner as the user does not yet exist.
    users.users.lldap = {
      isSystemUser = true;
      group = "lldap";
    };

    users.groups.lldap = {};

    sydnix.impermanence.directories = [
      "/var/lib/private/lldap"
    ];

    sydnix.sops.secrets =
      let e = {
            mode = "0440";
            owner = "lldap";
            group = "lldap";
          };
      in {
        lldap-ldap-user-pass = e;
        lldap-jwt-secret = e;
        lldap-secret-env = {};
        lldap-ldaps-key = e;
      };

    networking.firewall.allowedTCPPorts = [
      config.services.lldap.settings.http_port
      config.services.lldap.settings.ldap_port
      config.services.lldap.settings.ldaps_options.port
    ];

    services.lldap = {
      enable = true;
      environment = {
        LLDAP_LDAP_USER_PASS_FILE = "/run/secrets/lldap-ldap-user-pass";
        LLDAP_JWT_SECRET_FILE = "/run/secrets/lldap-jwt-secret";
        LLDAP_LDAPS_OPTIONS__ENABLED = "true";
      };
      environmentFile = "/run/secrets/lldap-secret-env";
      settings = {
        ldap_base_dn = cfg.baseDN;
        ldap_user_dn = "lain";
        ldap_user_email = "lain@deertopia.net";
        ldaps_options = {
          enabled = true;
          port = 6360;
          cert_file = ./lldap/cert.pem;
          key_file = "/run/secrets/lldap-ldaps-key";
        };
      };
    };

    sydnix.deertopia.nginx.vhosts."identify".vhost = {
      forceSSL = true;
      enableACME = true;
      locations."/" = {
        proxyPass =
          let port = builtins.toString config.services.lldap.settings.http_port;
          in "http://localhost:${port}";
      };
    };

    services.nginx.proxyCachePath."cache/" = {
      enable = true;
      keysZoneName = "auth_cache";
    };
  };
}
