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

with lib;

let
  cfg = config.services.xandikos;
in
{

  options = {
    services.xandikos = {
      enable = mkEnableOption "Xandikos CalDAV and CardDAV server";

      package = mkPackageOption pkgs "xandikos" { };

      address = mkOption {
        type = types.str;
        default = "localhost";
        description = ''
          The IP address on which Xandikos will listen.
          By default listens on localhost.
        '';
      };

      port = mkOption {
        type = types.port;
        default = 8080;
        description = "The port of the Xandikos web application";
      };

      routePrefix = mkOption {
        type = types.str;
        default = "/";
        description = ''
          Path to Xandikos.
          Useful when Xandikos is behind a reverse proxy.
        '';
      };

      extraOptions = mkOption {
        default = [ ];
        type = types.listOf types.str;
        example = literalExpression ''
          [ "--autocreate"
            "--defaults"
            "--current-user-principal user"
            "--dump-dav-xml"
          ]
        '';
        description = ''
          Extra command line arguments to pass to xandikos.
        '';
      };

      nginx = mkOption {
        default = { };
        description = ''
          Configuration for nginx reverse proxy.
        '';

        type = types.submodule {
          options = {
            enable = mkOption {
              type = types.bool;
              default = false;
              description = ''
                Configure the nginx reverse proxy settings.
              '';
            };

            hostName = mkOption {
              type = types.str;
              description = ''
                The hostname use to setup the virtualhost configuration
              '';
            };
          };
        };
      };

    };

  };

  meta.maintainers = with lib.maintainers; [ _0x4A6F ];

  config = mkIf cfg.enable (mkMerge [
    {

      systemd.services.xandikos = {
        description = "A Simple Calendar and Contact Server";
        after = [ "network.target" ];
        wantedBy = [ "multi-user.target" ];

        serviceConfig = {
          User = "xandikos";
          Group = "xandikos";
          DynamicUser = "yes";
          RuntimeDirectory = "xandikos";
          StateDirectory = "xandikos";
          StateDirectoryMode = "0700";
          PrivateDevices = true;
          # Sandboxing
          CapabilityBoundingSet = "CAP_NET_RAW CAP_NET_ADMIN";
          ProtectSystem = "strict";
          ProtectHome = true;
          PrivateTmp = true;
          ProtectKernelTunables = true;
          ProtectKernelModules = true;
          ProtectControlGroups = true;
          RestrictAddressFamilies = "AF_INET AF_INET6 AF_UNIX AF_PACKET AF_NETLINK";
          RestrictNamespaces = true;
          LockPersonality = true;
          MemoryDenyWriteExecute = true;
          RestrictRealtime = true;
          RestrictSUIDSGID = true;
          ExecStart = ''
            ${cfg.package}/bin/xandikos \
              --directory /var/lib/xandikos \
              --listen-address ${cfg.address} \
              --port ${toString cfg.port} \
              --route-prefix ${cfg.routePrefix} \
              ${lib.concatStringsSep " " cfg.extraOptions}
          '';
        };
      };
    }

    (mkIf cfg.nginx.enable {
      services.nginx = {
        enable = true;
        virtualHosts."${cfg.nginx.hostName}" = {
          locations."/" = {
            proxyPass = "http://${cfg.address}:${toString cfg.port}/";
          };
        };
      };
    })
  ]);
}
