{ config, lib, ... }:
{
  options.mj.services.remote-builder = with lib.types; {
    server = {
      enable = lib.mkEnableOption "Enable remote builder server";
      uidgid = lib.mkOption { type = int; };
      sshAllowSubnet = lib.mkOption { type = str; };
      publicKeys = lib.mkOption { type = listOf str; };
    };
    client = {
      enable = lib.mkEnableOption "Enable remote builder client";
      system = lib.mkOption {
        type = enum [
          "aarch64-linux"
          "x86_64-linux"
        ];
      };
      hostName = lib.mkOption { type = str; };
      sshKey = lib.mkOption { type = path; };
      supportedFeatures = lib.mkOption { type = listOf str; };
      maxJobs = lib.mkOption {
        type = int;
        default = 1;
      };
    };
  };

  config = lib.mkMerge [
    (
      let
        cfg = config.mj.services.remote-builder.server;
      in
      lib.mkIf cfg.enable {
        users.users.remote-builder = {
          description = "Remote Builder";
          home = "/var/lib/remote-builder";
          shell = "/bin/sh";
          group = "remote-builder";
          isSystemUser = true;
          createHome = true;
          uid = cfg.uidgid;
          openssh.authorizedKeys.keys = map (k: ''from="${cfg.sshAllowSubnet}" ${k}'') cfg.publicKeys;
        };
        users.groups.remote-builder.gid = cfg.uidgid;
        nix.settings.trusted-users = [ "remote-builder" ];
      }
    )
    (
      let
        cfg = config.mj.services.remote-builder.client;
      in
      lib.mkIf cfg.enable {
        nix = {
          buildMachines = [
            {
              inherit (cfg)
                hostName
                system
                sshKey
                supportedFeatures
                ;
              protocol = "ssh-ng";
              sshUser = "remote-builder";
            }
          ];
          distributedBuilds = true;
          extraOptions = "builders-use-substitutes = true";
        };
      }
    )
  ];
}