# source: https://github.com/fufexan/nix-gaming/raw/master/modules/pipewireLowLatency.nix
{
  config,
  pkgs,
  lib,
  ...
}:
let
  inherit (lib.modules) mkIf;
  inherit (lib.options) mkOption mkEnableOption;
  inherit (lib.types) int;
  inherit (lib.generators) toLua;

  cfg = config.services.pipewire.lowLatency;
  qr = "${toString cfg.quantum}/${toString cfg.rate}";
in
{
  # low-latency PipeWire configuration
  # extends the nixpkgs module
  meta.maintainers = with lib.maintainers; [ fufexan ];

  options = {
    services.pipewire.lowLatency = {
      enable = mkEnableOption ''
        low latency for PipeWire. This will also set `services.pipewire.enable` and
        `services.pipewire.wireplumber.enable` to true.
      '';

      quantum = mkOption {
        description = "Minimum quantum to set";
        type = int;
        default = 64;
        example = 32;
      };

      rate = mkOption {
        description = "Rate to set";
        type = int;
        default = 48000;
        example = 96000;
      };
    };
  };

  config = mkIf cfg.enable {
    services.pipewire = {
      # make sure PipeWire is enabled if the module is imported
      # and low latency is enabledd
      enable = true;

      # write extra config
      extraConfig.pipewire = {
        "99-lowlatency" = {
          context = {
            properties.default.clock.min-quantum = cfg.quantum;
            modules = [
              {
                name = "libpipewire-module-rtkit";
                flags = [
                  "ifexists"
                  "nofail"
                ];
                args = {
                  nice.level = -15;
                  rt = {
                    prio = 88;
                    time.soft = 200000;
                    time.hard = 200000;
                  };
                };
              }
              {
                name = "libpipewire-module-protocol-pulse";
                args = {
                  server.address = [ "unix:native" ];
                  pulse.min = {
                    req = qr;
                    quantum = qr;
                    frag = qr;
                  };
                };
              }
            ];

            stream.properties = {
              node.latency = qr;
              resample.quality = 1;
            };
          };
        };
      };

      # ensure WirePlumber is enabled explicitly (defaults to true while PW is enabled)
      # and write extra config to ship low latency rules for alsa
      wireplumber = {
        enable = true;
        configPackages =
          let
            # generate "matches" section of the rules
            matches =
              toLua
                {
                  multiline = false; # looks better while inline
                  indent = false;
                }
                [
                  [
                    [
                      "node.name"
                      "matches"
                      "alsa_output.*"
                    ]
                  ]
                ]; # nested lists are to produce `{{{ }}}` in the output

            # generate "apply_properties" section of the rules
            apply_properties = toLua { } {
              "audio.format" = "S32LE";
              "audio.rate" = cfg.rate * 2;
              "api.alsa.period-size" = 2;
            };
          in
          [
            (pkgs.writeTextDir "share/lowlatency.lua.d/99-alsa-lowlatency.lua" ''
              -- Generated by nix-gaming
              alsa_monitor.rules = {
                {
                  matches = ${matches};
                  apply_properties = ${apply_properties};
                }
              }
            '')
          ];
      };
    };
  };
}