{
  config,
  lib,
  pkgs,
  ...
}:
let
  inherit (lib)
    mkIf
    mkEnableOption
    mkOption
    concatLists
    concatStringsSep
    ;
  inherit (lib.types)
    str
    listOf
    enum
    bool
    ;
  cfg = config.modules.services.tailscale;
in
{
  options.modules.services.tailscale = {
    enable = mkEnableOption "Tailscale";

    server = mkOption {
      type = str;
      default = "https://hs.ccnlc.eu";
      description = "The coordination server tailscale should be using.";
    };

    isExitNode = mkOption {
      type = bool;
      default = false;
      description = "Enable if node should serve advertise itself as an exit node.";
    };

    tags = mkOption {
      type = listOf (enum [
        "client"
        "server"
      ]);
      default = [ ];
      apply = map (e: "tag:${e}");
    };

    defaultFlags = mkOption {
      type = listOf str;
      default = [ "--ssh" ];
    };

    extraFlags = mkOption {
      type = listOf str;
      default = [ ];
    };

    systemTray = mkOption {
      type = bool;
      default = config.modules.system.roles.desktop.enable;
      description = "Display a system tray icon to interact with tailscale.";
    };
  };

  config = mkIf cfg.enable {
    services.tailscale = {
      enable = true;
      extraUpFlags = concatLists [
        cfg.defaultFlags
        cfg.extraFlags
        (
          mkIf cfg.tags != [ ] [
            "--advertise-tags"
            (concatStringsSep "," cfg.tags)
          ]
        )
        (mkIf cfg.server [
          "--login-server"
          cfg.server
        ])
      ];
      useRoutingFeatures = mkIf cfg.isExitNode "server";
    };

    systemd.user.services.tailscale-system-tray = mkIf cfg.systemTray {
      description = "tailscale system tray";
      wantedBy = [ "graphical-session.target" ];
      after = [ "graphical-session.target" ];
      path = [ pkgs.polkit ];
      serviceConfig = {
        Type = "simple";
        ExecStart = "/bin/sh -lc ${pkgs.tailscale-systray}/bin/tailscale-systray";
        Restart = "on-failure";
        RestartSec = 1;
        TimeoutStopSec = 10;
        IPAddressDeny = "any";
      };
    };
  };
}