{ config, lib, pkgs, ... }:
with lib;
let
  cfg = config.services.syncthing.relay;
  dataDirectory = "/var/lib/syncthing-relay";
  relayOptions =
    [
      "--keys=${dataDirectory}"
      "--listen=${cfg.listenAddress}:${toString cfg.port}"
      "--status-srv=${cfg.statusListenAddress}:${toString cfg.statusPort}"
      "--provided-by=${escapeShellArg cfg.providedBy}"
    ]
    ++ optional (cfg.pools != null) "--pools=${escapeShellArg (concatStringsSep "," cfg.pools)}"
    ++ optional (cfg.globalRateBps != null) "--global-rate=${toString cfg.globalRateBps}"
    ++ optional (cfg.perSessionRateBps != null) "--per-session-rate=${toString cfg.perSessionRateBps}"
    ++ cfg.extraOptions;
in {
  ###### interface
  options.services.syncthing.relay = {
    enable = mkEnableOption "Syncthing relay service";
    listenAddress = mkOption {
      type = types.str;
      default = "";
      example = "1.2.3.4";
      description = ''
        Address to listen on for relay traffic.
      '';
    };
    port = mkOption {
      type = types.port;
      default = 22067;
      description = ''
        Port to listen on for relay traffic. This port should be added to
        networking.firewall.allowedTCPPorts.
      '';
    };
    statusListenAddress = mkOption {
      type = types.str;
      default = "";
      example = "1.2.3.4";
      description = ''
        Address to listen on for serving the relay status API.
      '';
    };
    statusPort = mkOption {
      type = types.port;
      default = 22070;
      description = ''
        Port to listen on for serving the relay status API. This port should be
        added to networking.firewall.allowedTCPPorts.
      '';
    };
    pools = mkOption {
      type = types.nullOr (types.listOf types.str);
      default = null;
      description = ''
        Relay pools to join. If null, uses the default global pool.
      '';
    };
    providedBy = mkOption {
      type = types.str;
      default = "";
      description = ''
        Human-readable description of the provider of the relay (you).
      '';
    };
    globalRateBps = mkOption {
      type = types.nullOr types.ints.positive;
      default = null;
      description = ''
        Global bandwidth rate limit in bytes per second.
      '';
    };
    perSessionRateBps = mkOption {
      type = types.nullOr types.ints.positive;
      default = null;
      description = ''
        Per session bandwidth rate limit in bytes per second.
      '';
    };
    extraOptions = mkOption {
      type = types.listOf types.str;
      default = [];
      description = ''
        Extra command line arguments to pass to strelaysrv.
      '';
    };
  };
  ###### implementation
  config = mkIf cfg.enable {
    systemd.services.syncthing-relay = {
      description = "Syncthing relay service";
      wantedBy = [ "multi-user.target" ];
      after = [ "network.target" ];
      serviceConfig = {
        DynamicUser = true;
        StateDirectory = baseNameOf dataDirectory;
        Restart = "on-failure";
        ExecStart = "${pkgs.syncthing-relay}/bin/strelaysrv ${concatStringsSep " " relayOptions}";
      };
    };
  };
}