{
  config,
  pkgs,
  ...
}:
let
  domain = "login.kaareskovgaard.net";
  bootstrapping = config.khscodes."security.kaareskovgaard.net".bootstrap.enable;
  openbaoDomain = config.khscodes.infrastructure.openbao.domain;
  openbaoAllowedRedirectUrls = [
    "https://${openbaoDomain}/ui/vault/auth/kanidm/oidc/callback"
    "https://${openbaoDomain}/kanidm/callback"
  ];
  kanidm-reset-password = pkgs.writeShellApplication {
    name = "kanidm-reset-password";
    runtimeInputs = [
      config.services.kanidm.package
      pkgs.jq
      pkgs.gnugrep
      pkgs.expect
    ];
    text = ''
      username="''${1:-}"
      if [[ "$username" == "" ]]; then
        >&2 echo "Usage kanidm-reset-password <username>"
        exit 1
      fi
      echo "Resetting password for idm_admin, please provide sudo password"
      password="$(sudo -u kanidm kanidmd recover-account -c /etc/kanidm/server.toml -o json idm_admin 2> /dev/null | grep '^{' | jq --raw-output '.password')"
      expect <<EOD
      spawn kanidm login --url https://login.kaareskovgaard.net --name idm_admin
      expect "Enter password"
      send "$password\n"
      expect eof
      EOD
      trap "kanidm logout --url https://login.kaareskovgaard.net" EXIT
      kanidm person credential create-reset-token --url https://login.kaareskovgaard.net "$username"
    '';

  };
in
{
  imports = [
    ./kanidm_application.nix
    ./kanidm_dovecot.nix
    ./kanidm_ldap.nix
  ];
  config = {
    khscodes.security.kanidm.applications = {
      openbao = {
        allowedRedirectUris = openbaoAllowedRedirectUrls;
        landingUri = "https://${openbaoDomain}";
        displayName = "OpenBAO";
        scopeMaps = {
          "openbao_admin" = [
            "profile"
            "email"
            "openid"
          ];
        };
        claimMaps.groups = {
          joinType = "array";
          valuesByGroup = {
            "openbao_admin" = [
              "openbao_writer"
              "openbao_cli_writer"
            ];
          };
        };
      };
      openbao-cli = {
        terranixName = "openbao_cli";
        allowedRedirectUris = [ "http://localhost:8250/oidc/callback" ];
        landingUri = "http://localhost:8250";
        displayName = "OpenBAO CLI";
        scopeMaps = {
          "openbao_admin" = [
            "profile"
            "email"
            "openid"
          ];
        };
        claimMaps.groups = {
          joinType = "array";
          valuesByGroup = {
            "openbao_admin" = [
              "openbao_writer"
            ];
          };
        };
      };
      monitoring = {
        allowedRedirectUris = [ "https://monitoring.kaareskovgaard.net/login/generic_oauth" ];
        landingUri = "http://monitoring.kaareskovgaard.net/login/generic_oauth";
        displayName = "Monitoring";
        scopeMaps = {
          "openbao_admin" = [
            "profile"
            "email"
            "openid"
          ];
        };
      };
      forgejo = {
        allowedRedirectUris = [ "https://kas.codes/user/oauth2/Kanidm/callback" ];
        landingUri = "http://kas.codes";
        displayName = "KAS: Codes";
        scopeMaps = {
          "forgejo_user" = [
            "profile"
            "email"
            "openid"
          ];
        };
        claimMaps.groups = {
          joinType = "array";
          valuesByGroup = {
            "forgejo_comitter" = [
              "comitter"
            ];
            "forgejo_admin" = [
              "admin"
            ];
          };
        };
      };
      dovecot = {
        allowedRedirectUris = [ "https://mail.kaareskovgaard.net/index.php/login/oauth" ];
        landingUri = "https://mail.kaareskovgaard.net";
        displayName = "Mail";
        allowInsecureClientDisablePkce = true;
        scopeMaps = {
          "mail_user" = [
            "profile"
            "email"
            "openid"
          ];
        };
      };
    };
    services.kanidm = {
      enableServer = true;
      # Verify upgrade will be successful by running `kanidmd domain upgrade-check` before bumping package version.
      package = pkgs.kanidmWithSecretProvisioning_1_6;
      serverSettings = {
        inherit domain;
        tls_chain = "${config.security.acme.certs.${domain}.directory}/fullchain.pem";
        tls_key = "${config.security.acme.certs.${domain}.directory}/key.pem";
        origin = "https://${domain}";
        trust_x_forward_for = true;
      };
      provision = {
        enable = true;
        idmAdminPasswordFile = null;
        adminPasswordFile = null;
        acceptInvalidCerts = true;
        persons.khs = {
          present = true;
          mailAddresses = [
            "kaare@agerlin-skovgaard.dk"
            "kaare@agerlinskovgaard.dk"
          ];
          legalName = "Kaare Skovgaard";
          displayName = "Kaare Skovgaard";
        };
        groups.openbao_admin = {
          present = true;
          members = [ "khs" ];
        };
        groups.forgejo_user = {
          present = true;
          members = [ "khs" ];
        };
        groups.forgejo_comitter = {
          present = true;
          members = [ "khs" ];
        };
        groups.forgejo_admin = {
          present = true;
          members = [ "khs" ];
        };
        groups.mail_user = {
          present = true;
          members = [ "khs" ];
        };
      };
    };

    khscodes.infrastructure.provisioning.post.modules = [
      (
        { ... }:
        {
          khscodes.vault = {
            enable = true;
            mount.kanidm = {
              path = "kanidm";
              type = "kv";
              options = {
                version = "2";
              };
              description = "Secrets used for kanidm";
            };
          };
        }
      )
      # Sets up OIDC authentication within OpenBAO.
      # OpenBAO queries the openid url for its configuration when adding it, so it is not possible,
      # to add this before
      (
        if bootstrapping then
          { }
        else
          {
            resource.vault_jwt_auth_backend.kanidm_cli = {
              description = "Kanidm cli auth backend";
              path = "oidc";
              type = "oidc";
              oidc_discovery_url = "https://${domain}/oauth2/openid/openbao-cli";
              oidc_client_id = "openbao-cli";
              oidc_client_secret = "\${ resource.random_password.openbao_cli_secret.result }";
              default_role = "kanidm_cli_writer";
              jwt_supported_algs = [
                "ES256"
              ];
              tune = [
                {
                  listing_visibility = "hidden";
                  default_lease_ttl = "2h";
                  max_lease_ttl = "2h";
                  token_type = "default-service";
                  passthrough_request_headers = [ ];
                  allowed_response_headers = [ ];
                  audit_non_hmac_request_keys = [ ];
                  audit_non_hmac_response_keys = [ ];
                }
              ];
            };
            resource.vault_jwt_auth_backend.kanidm = {
              description = "Kanidm auth backend";
              path = "kanidm";
              type = "oidc";
              oidc_discovery_url = "https://${domain}/oauth2/openid/openbao";
              oidc_client_id = "openbao";
              oidc_client_secret = "\${ resource.random_password.openbao_secret.result }";
              default_role = "kanidm_writer";
              jwt_supported_algs = [
                "ES256"
              ];
              tune = [
                {
                  listing_visibility = "unauth";
                  default_lease_ttl = "2h";
                  max_lease_ttl = "2h";
                  token_type = "default-service";
                  passthrough_request_headers = [ ];
                  allowed_response_headers = [ ];
                  audit_non_hmac_request_keys = [ ];
                  audit_non_hmac_response_keys = [ ];
                }
              ];
            };

            resource.vault_jwt_auth_backend_role.kanidm_cli_writer = {
              backend = "\${ resource.vault_jwt_auth_backend.kanidm_cli.path }";
              role_name = "kanidm_cli_writer";
              bound_audiences = [ "openbao-cli" ];
              allowed_redirect_uris = [ "http://localhost:8250/oidc/callback" ];
              user_claim = "sub";
              token_policies = [ "writer" ];
              groups_claim = "groups";
              oidc_scopes = [
                "openid"
                "profile"
                "email"
              ];
            };

            resource.vault_jwt_auth_backend_role.kanidm_writer = {
              backend = "\${ resource.vault_jwt_auth_backend.kanidm.path }";
              role_name = "kanidm_writer";
              bound_audiences = [ "openbao" ];
              allowed_redirect_uris = openbaoAllowedRedirectUrls;
              user_claim = "sub";
              token_policies = [ "writer" ];
              groups_claim = "groups";
              oidc_scopes = [
                "openid"
                "profile"
                "email"
              ];
            };

            resource.vault_identity_group.kanidm_writer = {
              name = "kanidm_writer";
              policies = [ "writer" ];
              type = "external";
            };

            resource.vault_identity_group.kanidm_cli_writer = {
              name = "kanidm_cli_writer";
              policies = [ "writer" ];
              type = "external";
            };

            resource.vault_identity_group_alias.oidc_writer = {
              name = "openbao_cli_writer";
              mount_accessor = "\${ vault_jwt_auth_backend.kanidm_cli.accessor }";
              canonical_id = "\${ vault_identity_group.kanidm_cli_writer.id }";
            };

            resource.vault_identity_group_alias.kanidm_writer = {
              name = "openbao_writer";
              mount_accessor = "\${ vault_jwt_auth_backend.kanidm.accessor }";
              canonical_id = "\${ vault_identity_group.kanidm_writer.id }";
            };

            resource.vault_policy.writer = {
              name = "writer";

              policy = ''
                path "*" {
                  capabilities = ["create", "update", "patch", "read", "delete", "list"]
                }
              '';
            };
          }
      )
    ];
    security.acme.certs.${domain}.reloadServices = [ "kanidm.service" ];
    # Allow kanidm to read the certificate file
    users.groups.nginx.members = [ "kanidm" ];

    khscodes.services.nginx.virtualHosts.${domain} = {
      locations."/" = {
        proxyPass = "https://${config.services.kanidm.serverSettings.bindaddress}/";
        recommendedProxySettings = true;
      };
    };

    environment.systemPackages = [
      kanidm-reset-password
    ];
  };
}
