{ options
, config
, pkgs
, lib
, ...
}:
# FIXME: The transition to wireplumber from media-session has completely
# broken my setup. I'll need to invest some time to figure out how to override Alsa things
# again...
with lib;
with lib.plusultra; let
  cfg = config.plusultra.hardware.audio;

  lua-format = {
    type = with lib.types; let
      valueType =
        nullOr
          (oneOf [
            bool
            int
            float
            str
            path
            (attrsOf valueType)
            (listOf valueType)
          ])
        // {
          description = "Lua value";
        };
    in
    valueType;

    generate = name: value:
      let
        toLuaValue = value:
          if value == null
          then "null"
          else if value == true
          then "true"
          else if value == false
          then "false"
          else if builtins.isInt value || builtins.isFloat value
          then builtins.toString value
          else if builtins.isString value
          then toLuaString value
          else if builtins.isAttrs value
          then toLuaTable value
          else if builtins.isList value
          then toLuaList value
          else builtins.abort "Unsupported value used with formats.lua.generate: ${value}";

        toLuaString = value: "\"${builtins.toString value}\"";

        toLuaTable = value:
          let
            pairs =
              mapAttrsToList
                (name: value: "[${toLuaString name}] = ${toLuaValue value}")
                value;
            content = concatStringsSep ", " pairs;
          in
          "{ ${content} }";

        toLuaList = value:
          let
            parts = builtins.map toLuaValue value;
            content = concatStringsSep ", " parts;
          in
          "{ ${content} }";
      in
      toLuaValue value;
  };

  pipewire-config = {
    "context.objects" = cfg.nodes ++ [ ];
    "context.modules" =
      [
        {
          name = "libpipewire-module-rtkit";
          args = { };
          flags = [ "ifexists" "nofail" ];
        }
        { name = "libpipewire-module-protocol-native"; }
        { name = "libpipewire-module-profiler"; }
        # {
        #   name = "libpipewire-module-metadata";
        #   flags = [ "ifexists" "nofail" ];
        # }
        { name = "libpipewire-module-spa-device-factory"; }
        { name = "libpipewire-module-spa-node-factory"; }
        # {
        #   name = "libpipewire-module-client-node";
        #   flags = [ "ifexists" "nofail" ];
        # }
        # {
        #   name = "libpipewire-module-client-device";
        #   flags = [ "ifexists" "nofail" ];
        # }
        {
          name = "libpipewire-module-portal";
          flags = [ "ifexists" "nofail" ];
        }
        {
          name = "libpipewire-module-access";
          args = { };
        }
        { name = "libpipewire-module-adapter"; }
        { name = "libpipewire-module-link-factory"; }
        { name = "libpipewire-module-session-manager"; }
      ]
      ++ cfg.modules;
    "context.components" = [
      {
        name = "libwireplumber-module-lua-scripting";
        type = "module";
      }
      {
        name = "config.lua";
        type = "config/lua";
      }
    ];
  };

  alsa-config = {
    alsa_monitor = cfg.alsa-monitor;
  };
in
{
  options.plusultra.hardware.audio = with types; {
    enable = mkBoolOpt false "Whether or not to enable audio support.";
    alsa-monitor = mkOpt attrs { } "Alsa configuration.";
    nodes =
      mkOpt (listOf attrs) [ ]
        "Audio nodes to pass to Pipewire as `context.objects`.";
    modules =
      mkOpt (listOf attrs) [ ]
        "Audio modules to pass to Pipewire as `context.modules`.";
    extra-packages = mkOpt (listOf package) [
      pkgs.qjackctl
      pkgs.easyeffects
    ] "Additional packages to install.";
  };

  config = mkIf cfg.enable {
    security.rtkit.enable = true;

    services.pipewire = {
      enable = true;
      alsa.enable = true;
      pulse.enable = true;
      jack.enable = true;

      wireplumber.enable = true;
    };

    environment.etc = {
      # "pipewire/pipewire.conf.d/10-pipewire.conf".source =
      #   pkgs.writeText "pipewire.conf" (builtins.toJSON pipewire-config);
      # "pipewire/pipewire.conf.d/21-alsa.conf".source =
      #   pkgs.writeText "pipewire.conf" (builtins.toJSON alsa-config);

      #       "wireplumber/wireplumber.conf".source =
      #         pkgs.writeText "pipewire.conf" (builtins.toJSON pipewire-config);

      # "wireplumber/scripts/config.lua.d/alsa.lua".text = ''
      #   local input = ${lua-format.generate "sample.lua" cfg.alsa-monitor}

      #   if input.rules == nil then
      #    input.rules = {}
      #   end

      #   local rules = input.rules

      #   for _, rule in ipairs(input.rules) do
      #     table.insert(alsa_monitor.rules, rule)
      #   end
      # '';
    };

    hardware.pulseaudio.enable = mkForce false;

    environment.systemPackages = with pkgs;
      [
        pulsemixer
        pavucontrol
      ]
      ++ cfg.extra-packages;

    plusultra.user.extraGroups = [ "audio" ];

    plusultra.home.extraOptions = {
      systemd.user.services.mpris-proxy = {
        Unit.Description = "Mpris proxy";
        Unit.After = [ "network.target" "sound.target" ];
        Service.ExecStart = "${pkgs.bluez}/bin/mpris-proxy";
        Install.WantedBy = [ "default.target" ];
      };
    };
  };
}
