{
  config,
  lib,
  ...
}:
let
  inherit (lib.options) mkOption;
  inherit (lib.modules) mkIf mkMerge mkDefault mkOptionDefault;
  inherit (lib.strings) concatMapStringsSep;
  inherit (lib.lists) optionals;
  inherit (config.services) tailscale;
  inherit (config.services.nginx) virtualHosts;
  inherit (config.networking.access) cidrForNetwork;
  cfg = config.services.kanidm;
  access = config.services.nginx.access.kanidm;
  proxyPass = mkDefault "https://${access.host}:${toString access.port}";
  locations = {
    "/" = {
      inherit proxyPass;
    };
    "=/ca.pem" = mkIf cfg.server.unencrypted.enable {
      alias = "${cfg.server.unencrypted.package.ca}";
    };
  };
  allows = let
    mkAllow = cidr: "allow ${cidr};";
    allowAddresses =
      cidrForNetwork.loopback.all
      ++ cidrForNetwork.local.all
      ++ optionals tailscale.enable cidrForNetwork.tail.all;
    allows = concatMapStringsSep "\n" mkAllow allowAddresses;
  in ''
    ${allows}
    deny all;
  '';
in {
  options.services.nginx.access.kanidm = with lib.types; {
    host = mkOption {
      type = str;
    };
    domain = mkOption {
      type = str;
      default = "id.${config.networking.domain}";
    };
    localDomain = mkOption {
      type = str;
      default = "id.local.${config.networking.domain}";
    };
    tailDomain = mkOption {
      type = str;
      default = "id.tail.${config.networking.domain}";
    };
    ldapDomain = mkOption {
      type = str;
      default = "ldap.${config.networking.domain}";
    };
    ldapLocalDomain = mkOption {
      type = str;
      default = "ldap.local.${config.networking.domain}";
    };
    ldapTailDomain = mkOption {
      type = str;
      default = "ldap.tail.${config.networking.domain}";
    };
    port = mkOption {
      type = port;
    };
    ldapPort = mkOption {
      type = port;
    };
    ldapEnable = mkOption {
      type = bool;
      default = true;
    };
    useACMEHost = mkOption {
      type = nullOr str;
      default = virtualHosts.${access.domain}.useACMEHost;
    };
  };
  config = {
    services.nginx = {
      access.kanidm = mkIf cfg.enableServer {
        domain = mkOptionDefault cfg.server.frontend.domain;
        host = mkOptionDefault "localhost";
        port = mkOptionDefault cfg.server.frontend.port;
        ldapPort = mkOptionDefault cfg.server.ldap.port;
        ldapEnable = mkDefault cfg.server.ldap.enable;
      };
      streamConfig = let
        inherit (config.security.acme) certs;
        sslConfig = if access.useACMEHost != null then ''
          ssl_certificate ${certs.${access.useACMEHost}.directory}/fullchain.pem;
          ssl_certificate_key ${certs.${access.useACMEHost}.directory}/key.pem;
          ssl_trusted_certificate ${certs.${access.useACMEHost}.directory}/chain.pem;
        '' else ''
          ssl_certificate ${cfg.serverSettings.tls_chain};
          ssl_certificate_key ${cfg.serverSettings.tls_key};
        '';
      in mkIf access.ldapEnable ''
        server {
          listen 0.0.0.0:389;
          listen [::]:389;
          ${allows}
          proxy_pass ${access.host}:${toString access.ldapPort};
          proxy_ssl on;
          proxy_ssl_verify off;
        }
        server {
          listen 0.0.0.0:636 ssl;
          listen [::]:636 ssl;
          ${sslConfig}
          proxy_pass ${access.host}:${toString access.ldapPort};
          proxy_ssl on;
          proxy_ssl_verify off;
        }
      '';

      virtualHosts = {
        ${access.domain} = {
          inherit locations;
        };
        ${access.localDomain} = {
          inherit (virtualHosts.${access.domain}) useACMEHost;
          addSSL = mkDefault (access.useACMEHost != null || virtualHosts.${access.domain}.forceSSL);
          local.enable = true;
          inherit locations;
        };
        ${access.tailDomain} = mkIf config.services.tailscale.enable {
          inherit (virtualHosts.${access.domain}) useACMEHost;
          addSSL = mkDefault (access.useACMEHost != null || virtualHosts.${access.domain}.forceSSL);
          local.enable = true;
          inherit locations;
        };
      };
    };

    services.kanidm.server.unencrypted.domain = mkMerge [
      [
        access.localDomain
        config.networking.fqdn
        config.networking.access.hostnameForNetwork.local
      ]
      (mkIf config.services.tailscale.enable [
        "id.tail.${config.networking.domain}"
        config.networking.access.hostnameForNetwork.tail
      ])
    ];

    networking.firewall = {
      interfaces.local.allowedTCPPorts = [
        389
      ];
      allowedTCPPorts = [
        636
      ];
    };
  };
}
