packages:
{
  lib,
  pkgs,
  config,
  ...
}:

let
  inherit (lib) types mkOption mkEnableOption;

  cfg = config.environment.hakurei;
in

{
  options = {
    environment.hakurei = {
      enable = mkEnableOption "hakurei";

      package = mkOption {
        type = types.package;
        default = packages.${pkgs.stdenv.hostPlatform.system}.hakurei;
        description = "The hakurei package to use.";
      };

      hsuPackage = mkOption {
        type = types.package;
        default = packages.${pkgs.stdenv.hostPlatform.system}.hsu;
        description = "The hsu package to use.";
      };

      users = mkOption {
        type =
          let
            inherit (types) attrsOf ints;
          in
          attrsOf (ints.between 0 99);
        description = ''
          Users allowed to spawn hakurei apps and their corresponding hakurei identity.
        '';
      };

      extraHomeConfig = mkOption {
        type = types.anything;
        description = ''
          Extra home-manager configuration to merge with all target users.
        '';
      };

      sharefs = {
        package = mkOption {
          type = types.package;
          default = pkgs.linkFarm "sharefs" {
            "bin/sharefs" = "${cfg.package}/libexec/sharefs";
            "bin/mount.fuse.sharefs" = "${cfg.package}/libexec/sharefs";
          };
          description = "The sharefs package to use.";
        };

        user = mkOption {
          type = types.str;
          default = "sharefs";
          description = ''
            Name of the user to run the sharefs daemon as.
          '';
        };

        group = mkOption {
          type = types.str;
          default = "sharefs";
          description = ''
            Name of the group to run the sharefs daemon as.
          '';
        };

        name = mkOption {
          type = types.str;
          default = "/sdcard";
          description = ''
            Host path to mount sharefs on.
          '';
        };

        source = mkOption {
          type = types.nullOr types.str;
          default = null;
          description = ''
            Writable backing directory. Setting this to null disables sharefs.
          '';
        };
      };

      apps = mkOption {
        type =
          let
            inherit (types)
              int
              ints
              str
              bool
              enum
              package
              anything
              submodule
              listOf
              attrsOf
              nullOr
              functionTo
              ;
          in
          attrsOf (submodule {
            options = {
              name = mkOption {
                type = str;
                description = ''
                  Name of the app's launcher script.
                '';
              };

              verbose = mkEnableOption "launchers with verbose output";

              identity = mkOption {
                type = ints.between 1 9999;
                description = ''
                  Application identity. Identity 0 is reserved for system services.
                '';
              };
              shareUid = mkEnableOption "sharing identity with another application";

              packages = mkOption {
                type = listOf package;
                default = [ ];
                description = ''
                  List of extra packages to install via home-manager.
                '';
              };

              extraConfig = mkOption {
                type = anything;
                default = { };
                description = ''
                  Extra home-manager configuration.
                '';
              };

              path = mkOption {
                type = nullOr str;
                default = null;
                description = ''
                  Custom executable path.
                  Setting this to null will default to the start script.
                '';
              };

              args = mkOption {
                type = nullOr (listOf str);
                default = null;
                description = ''
                  Custom args.
                  Setting this to null will default to script name.
                '';
              };

              script = mkOption {
                type = nullOr str;
                default = null;
                description = ''
                  Application launch script.
                '';
              };

              command = mkOption {
                type = nullOr str;
                default = null;
                description = ''
                  Command to run as the target user.
                  Setting this to null will default command to launcher name.
                  Has no effect when script is set.
                '';
              };

              groups = mkOption {
                type = listOf str;
                default = [ ];
                description = ''
                  List of groups to inherit from the privileged user.
                '';
              };

              shareRuntime = mkEnableOption "sharing of XDG_RUNTIME_DIR between containers under the same identity";
              shareTmpdir = mkEnableOption "sharing of TMPDIR between containers under the same identity";

              dbus = {
                session = mkOption {
                  type = nullOr (functionTo anything);
                  default = null;
                  description = ''
                    D-Bus session bus custom configuration.
                    Setting this to null will enable built-in defaults.
                  '';
                };

                system = mkOption {
                  type = nullOr anything;
                  default = null;
                  description = ''
                    D-Bus system bus custom configuration.
                    Setting this to null will disable the system bus proxy.
                  '';
                };
              };

              env = mkOption {
                type = nullOr (attrsOf str);
                default = null;
                description = ''
                  Environment variables to set for the initial process in the sandbox.
                '';
              };

              wait_delay = mkOption {
                type = nullOr int;
                default = null;
                description = ''
                  Duration to wait for after interrupting a container's initial process in nanoseconds.
                  A negative value causes the container to be terminated immediately on cancellation.
                  Setting this to null defaults to five seconds.
                '';
              };

              devel = mkEnableOption "debugging-related kernel interfaces";
              userns = mkEnableOption "user namespace creation";
              tty = mkEnableOption "access to the controlling terminal";
              multiarch = mkEnableOption "multiarch kernel-level support";

              hostNet = mkEnableOption "share host net namespace" // {
                default = true;
              };
              hostAbstract = mkEnableOption "share abstract unix socket scope";

              schedPolicy = mkOption {
                type = nullOr (enum [
                  "fifo"
                  "rr"
                  "batch"
                  "idle"
                  "deadline"
                  "ext"
                ]);
                default = null;
                description = ''
                  Scheduling policy to set for the container.
                  The zero value retains the current scheduling policy.
                '';
              };
              schedPriority = mkOption {
                type = nullOr (ints.between 1 99);
                default = null;
                description = ''
                  Scheduling priority to set for the container.
                '';
              };

              nix = mkEnableOption "nix daemon access";
              mapRealUid = mkEnableOption "mapping to priv-user uid";
              device = mkEnableOption "access to all devices";
              insecureWayland = mkEnableOption "direct access to the Wayland socket";

              gpu = mkOption {
                type = nullOr bool;
                default = null;
                description = ''
                  Target process GPU and driver access.
                  Setting this to null will enable GPU whenever X or Wayland is enabled.
                '';
              };

              useCommonPaths = mkEnableOption "common extra paths" // {
                default = true;
              };

              extraPaths = mkOption {
                type = listOf (attrsOf anything);
                default = [ ];
                description = ''
                  Extra paths to make available to the container.
                '';
              };

              enablements = {
                wayland = mkOption {
                  type = nullOr bool;
                  default = true;
                  description = ''
                    Whether to share the Wayland server via security-context-v1.
                  '';
                };

                x11 = mkOption {
                  type = nullOr bool;
                  default = false;
                  description = ''
                    Whether to share the X11 socket and allow connection.
                  '';
                };

                dbus = mkOption {
                  type = nullOr bool;
                  default = true;
                  description = ''
                    Whether to proxy D-Bus.
                  '';
                };

                pipewire = mkOption {
                  type = nullOr bool;
                  default = true;
                  description = ''
                    Whether to share the PipeWire server via pipewire-pulse on a SecurityContext socket.
                  '';
                };
              };

              share = mkOption {
                type = nullOr package;
                default = null;
                description = ''
                  Package containing share files.
                  Setting this to null will default package name to wrapper name.
                '';
              };
            };
          });
        default = { };
        description = ''
          Declaratively configured hakurei apps.
        '';
      };

      commonPaths = mkOption {
        type = types.listOf (types.attrsOf types.anything);
        default = [ ];
        description = ''
          Common extra paths to make available to the container.
        '';
      };

      shell = mkOption {
        type = types.str;
        default = "/run/current-system/sw/bin/bash";
        description = ''
          Absolute path to preferred shell.
        '';
      };

      stateDir = mkOption {
        type = types.str;
        description = ''
          The state directory where app home directories are stored.
        '';
      };
    };
  };
}
