{
  pkgs,
  config,
  lib,
  ...
}:
let
  ms-accept = pkgs.callPackage ../pkgs/moonlight-sunshine-accept { };
  sunshineConfiguration = pkgs.writeText "sunshine.conf" ''
    address_family = both
    channels = 5
    pkey = /var/lib/sunshine/sunshine.key
    cert = /var/lib/sunshine/sunshine.cert
    file_state = /var/lib/sunshine/state.json
    credentials_file = /var/lib/sunshine/credentials.json
  '';
  listenPort = 48011;
in
{
  networking.firewall = {
    allowedTCPPorts = [
      47984
      47989
      47990
      48010
      48011
    ];

    allowedUDPPorts = [
      47998
      47999
      48000
      48002
      48010
    ];
  };

  networking.firewall.allowedTCPPortRanges = [
    {
      from = 47984;
      to = 48010;
    }
  ];
  networking.firewall.allowedUDPPortRanges = [
    {
      from = 47998;
      to = 48010;
    }
  ];
  networking.firewall.interfaces."zt+".allowedTCPPorts = [
    47984
    47989
    47990
    48010
    listenPort
  ];
  networking.firewall.interfaces."zt+".allowedUDPPortRanges = [
    {
      from = 47998;
      to = 48010;
    }
  ];

  environment.systemPackages = [
    ms-accept
    pkgs.sunshine
    pkgs.avahi
    # Convenience script, until we find a better UX
    (pkgs.writers.writeDashBin "sun" ''
      ${pkgs.sunshine}/bin/sunshine -0 ${sunshineConfiguration} "$@"
    '')
    # Create a dummy account, for easier setup,
    # don't use this account in actual production yet.
    (pkgs.writers.writeDashBin "init-sun" ''
      ${pkgs.sunshine}/bin/sunshine \
      --creds "sunshine" "sunshine"
    '')
  ];

  # Required to simulate input
  boot.kernelModules = [ "uinput" ];

  services.udev.extraRules = ''
    KERNEL=="uinput", SUBSYSTEM=="misc", OPTIONS+="static_node=uinput", TAG+="uaccess"
  '';

  security = {
    rtkit.enable = true;
    wrappers.sunshine = {
      owner = "root";
      group = "root";
      capabilities = "cap_sys_admin+p";
      source = "${pkgs.sunshine}/bin/sunshine";
    };
  };

  systemd.tmpfiles.rules = [
    "d '/var/lib/sunshine' 0770 'user' 'users' - -"
    "C '/var/lib/sunshine/sunshine.cert' 0644 'user' 'users' - ${
      config.clan.core.facts.services.sunshine.secret."sunshine.cert".path or ""
    }"
    "C '/var/lib/sunshine/sunshine.key' 0644 'user' 'users' - ${
      config.clan.core.facts.services.sunshine.secret."sunshine.key".path or ""
    }"
  ];

  hardware.opengl.enable = true;

  systemd.user.services.sunshine = {
    enable = true;
    description = "Sunshine self-hosted game stream host for Moonlight";
    startLimitBurst = 5;
    startLimitIntervalSec = 500;
    script = "/run/current-system/sw/bin/env /run/wrappers/bin/sunshine ${sunshineConfiguration}";
    serviceConfig = {
      Restart = "on-failure";
      RestartSec = "5s";
      ReadWritePaths = [ "/var/lib/sunshine" ];
      ReadOnlyPaths = [
        (config.clan.core.facts.services.sunshine.secret."sunshine.key".path or "")
        (config.clan.core.facts.services.sunshine.secret."sunshine.cert".path or "")
      ];
    };
    wantedBy = [ "graphical-session.target" ];
    partOf = [ "graphical-session.target" ];
    wants = [ "graphical-session.target" ];
    after = [
      "sunshine-init-state.service"
      "sunshine-init-credentials.service"
    ];
  };

  systemd.user.services.sunshine-init-state = {
    enable = true;
    description = "Sunshine self-hosted game stream host for Moonlight";
    startLimitBurst = 5;
    startLimitIntervalSec = 500;
    script = ''
      ${ms-accept}/bin/moonlight-sunshine-accept sunshine init-state --uuid ${
        config.clan.core.facts.services.sunshine.public.sunshine-uuid.value or null
      } --state-file /var/lib/sunshine/state.json
    '';
    serviceConfig = {
      Restart = "on-failure";
      RestartSec = "5s";
      Type = "oneshot";
      ReadWritePaths = [ "/var/lib/sunshine" ];
    };
    wantedBy = [ "graphical-session.target" ];
  };

  systemd.user.services.sunshine-init-credentials = {
    enable = true;
    description = "Sunshine self-hosted game stream host for Moonlight";
    startLimitBurst = 5;
    startLimitIntervalSec = 500;
    script = ''
      ${lib.getExe pkgs.sunshine} ${sunshineConfiguration} --creds sunshine sunshine
    '';
    serviceConfig = {
      Restart = "on-failure";
      RestartSec = "5s";
      Type = "oneshot";
      ReadWritePaths = [ "/var/lib/sunshine" ];
    };
    wantedBy = [ "graphical-session.target" ];
  };

  systemd.user.services.sunshine-listener = {
    enable = true;
    description = "Sunshine self-hosted game stream host for Moonlight";
    startLimitBurst = 5;
    startLimitIntervalSec = 500;
    script = ''
      ${ms-accept}/bin/moonlight-sunshine-accept sunshine listen --port ${builtins.toString listenPort} --uuid ${
        config.clan.core.facts.services.sunshine.public.sunshine-uuid.value or null
      }  --state /var/lib/sunshine/state.json --cert '${
        config.clan.core.facts.services.sunshine.public."sunshine.cert".value or null
      }'
    '';
    serviceConfig = {
      # );
      Restart = "on-failure";
      RestartSec = 5;
      ReadWritePaths = [ "/var/lib/sunshine" ];
    };
    wantedBy = [ "graphical-session.target" ];
  };

  clan.core.facts.services.ergochat = {
    secret."sunshine.key" = { };
    secret."sunshine.cert" = { };
    public."sunshine-uuid" = { };
    public."sunshine.cert" = { };
    generator.path = [
      pkgs.coreutils
      ms-accept
    ];
    generator.script = ''
      moonlight-sunshine-accept sunshine init
      mv credentials/cakey.pem "$secrets"/sunshine.key
      cp credentials/cacert.pem "$secrets"/sunshine.cert
      mv credentials/cacert.pem "$facts"/sunshine.cert
      mv uuid "$facts"/sunshine-uuid
    '';
  };
}
