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

let
  cfg = config.services.radicale;
  domain = config.networking.domain;
  subdomain = cfg.reverseProxy.subdomain;
  fqdn = if (cfg.reverseProxy.enable && subdomain != "") then "${subdomain}.${domain}" else domain;
  port = 5232;

  inherit (lib)
    concatLines
    mkDefault
    mkIf
    mkOption
    types
    ;

  inherit (lib.utils)
    mkReverseProxyOption
    ;
in
{
  options.services.radicale = {
    users = mkOption {
      type = types.listOf types.str;
      default = [ ];
      example = [
        "alice"
        "bob"
      ];
      description = "List of users for Radicale. Each user must have a corresponding entry in the SOPS file under 'radicale/<user>'";
    };
    reverseProxy = mkReverseProxyOption "Radicale" "dav";
  };

  config = mkIf cfg.enable {
    services.radicale = {
      settings = {
        server = {
          hosts = [
            "${if cfg.reverseProxy.enable then "127.0.0.1" else "0.0.0.0"}:${builtins.toString port}"
          ];
          max_connections = mkDefault 20;
          max_content_length = mkDefault 500000000;
          timeout = mkDefault 30;
        };
        auth = {
          type = "htpasswd";
          delay = mkDefault 1;
          htpasswd_filename = config.sops.templates."radicale/users".path;
          htpasswd_encryption = mkDefault "sha512";
        };
        storage = {
          filesystem_folder = mkDefault "/var/lib/radicale/collections";
        };
      };
    };

    services.nginx.virtualHosts = mkIf cfg.reverseProxy.enable {
      "${fqdn}" = {
        forceSSL = cfg.reverseProxy.forceSSL;
        enableACME = cfg.reverseProxy.forceSSL;
        locations = {
          "/" = {
            proxyPass = "http://localhost:${builtins.toString port}/";
            extraConfig = ''
              proxy_set_header  X-Script-Name /;
              proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;
              proxy_pass_header Authorization;
            '';
          };
          "/.well-known/caldav" = {
            return = "301 $scheme://$host/";
          };
          "/.well-known/carddav" = {
            return = "301 $scheme://$host/";
          };
        };
      };
    };

    environment.systemPackages = [
      pkgs.openssl
    ];

    sops =
      let
        owner = "radicale";
        group = "radicale";
        mode = "0440";

        mkSecrets =
          users:
          builtins.listToAttrs (
            map (user: {
              name = "radicale/${user}";
              value = { inherit owner group mode; };
            }) users
          );

        mkTemplate = users: {
          inherit owner group mode;
          content = concatLines (map (user: "${user}:${config.sops.placeholder."radicale/${user}"}") users);
        };
      in
      {
        secrets = mkSecrets cfg.users;
        templates."radicale/users" = mkTemplate cfg.users;
      };
  };
}
