{
  pkgs,
  config,
  lib,
  ...
}: let
  service = "minecraft_recpro";
  cfg = config.gameservers.${service};
  sec = config.sops.secrets;
  servers = {
    velocity = {
      data_dir = "/var/lib/gameservers/minecraft_recpro/velocity";
      db_dump = "/var/backup/mysql/${service}_db.zst";
      ram = "2G";
    };
    smp = {
      data_dir = "/var/lib/gameservers/minecraft_recpro/smp";
      ram = "12G";
    };
    superflat = {
      data_dir = "/var/lib/gameservers/minecraft_recpro/superflat";
      ram = "4G";
    };
    bento = {
      data_dir = "/var/lib/gameservers/minecraft_recpro/bento";
      ram = "2G";
    };
  };
in {
  options.gameservers.${service} = {
    enable = lib.mkEnableOption "enables ${service}";
    url = lib.mkOption {
      type = lib.types.str;
      default = "mc.recoil.pro";
      description = "set domain for ${service}";
    };
    data_dir = lib.mkOption {
      type = lib.types.str;
      default = "/var/lib/gameservers/${service}";
      description = "set data directory for ${service}";
    };
    ids = lib.mkOption {
      type = lib.types.int;
      default = 25565;
      description = "set uid and pid of ${service} user (matches port by default)";
    };
    backup = lib.mkOption {
      type = lib.types.bool;
      default = false;
      description = "enable backups for ${service}";
    };
    motd = lib.mkOption {
      type = lib.types.nullOr lib.types.str;
      default = "velocity";
    };
    backup_repo = lib.mkOption {
      type = lib.types.path;
      default = "/holocron/archives/gameservers/minecraft/recpro_stack";
      description = "path to take hourly backups to with borg!";
    };
  };

  config = lib.mkIf cfg.enable {
    # declare ${service} group
    users.groups.minecraft = {gid = lib.mkForce cfg.ids;};

    # declare ${service} user
    users.users.minecraft = {
      description = "minecraft server user";
      uid = lib.mkForce cfg.ids;
      isSystemUser = true;
      shell = pkgs.bash;
      group = "minecraft";
      extraGroups = [];
    };

    systemd.tmpfiles.rules =
      lib.attrsets.mapAttrsToList (
        name: cfg: "d ${cfg.data_dir} 0770 minecraft minecraft -"
      )
      servers;

    # Create a systemd service per server running in tmux
    systemd.services =
      lib.attrsets.mapAttrs (name: srv: {
        description = "minecraft_recpro: ${name}";
        after = ["network.target"];
        wants = ["network.target"];
        serviceConfig = {
          User = "minecraft";
          Group = "minecraft";
          WorkingDirectory = srv.data_dir;
          UMask = "0007";
          ExecStart = "${pkgs.openjdk21}/bin/java -Xmx${srv.ram} -jar server.jar nogui";
          Restart = "on-failure";
          KillMode = "process";
        };
        wantedBy = ["multi-user.target"];
      })
      servers;

    environment.systemPackages = with pkgs; [openjdk21 mcrcon];

    services.mysql = {
      enable = true;
      package = pkgs.mariadb;
      ensureDatabases = ["minecraft_recpro_db"];
      ensureUsers = [
        {
          name = "minecraft";
          ensurePermissions = {"minecraft_recpro_db.*" = "ALL PRIVILEGES";};
        }
      ];
      initialScript = pkgs.writeText "minecraft_recpro-init.sql" ''
        CREATE USER IF NOT EXISTS 'minecraft_recpro'@'localhost' IDENTIFIED BY 'IKNOWTHISISBADIJUSTNEEDTHISTOWORKRNPLS';
        GRANT ALL PRIVILEGES ON minecraft_recpro_db.* TO 'minecraft_recpro'@'localhost';
        FLUSH PRIVILEGES;
      '';
    };

    # open firewall
    networking.firewall.allowedTCPPorts = [25777 25565 25566 25567];

    sops.secrets = {
      "velocity_forwarding" = {
        owner = "minecraft";
        group = "minecraft";
        path = "/var/lib/gameservers/minecraft_recpro/velocity/forwarding.secret";
        mode = "0400";
      };
      "minecraft_recpro_db_passwd" = {
        owner = "mysql";
        group = "mysql";
      };
    };

    # backups minecraft_recpro with borg!
    services.borgbackup.jobs.${service} = {
      archiveBaseName = service;
      repo = cfg.backup_repo;
      paths = lib.flatten (
        lib.attrValues (
          lib.mapAttrs (_: srv:
            [srv.data_dir]
            ++ (
              if builtins.hasAttr "db_dump" srv
              then [srv.db_dump]
              else []
            ))
          servers
        )
      );
      compression = "auto,zstd";
      preHook = "systemctl start mysql-backup.service";
      startAt = "*-*-* *:00:00";
      group = "archives";
      encryption.mode = "repokey-blake2";
      encryption.passCommand = "cat ${config.sops.secrets."borg_passwd".path}";
      extraArgs = ["--verbose" "--show-rc" "--umask" "0007"];
      extraCreateArgs = ["--list" "--stats" "--filter" "AME"];
      prune.keep = {
        within = "1d"; # Keep all archives from the last day
        hourly = 24;
        daily = 7;
        weekly = 12;
        monthly = -1; # Keep at least one archive for each month
      };
    };
  };
}
