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

with lib;

let
  cfg = config.clerie.minecraft-server;

  # We don't allow eula=false anyways
  eulaFile = builtins.toFile "eula.txt" ''
    # eula.txt managed by NixOS Configuration
    eula=true
  '';

  generateServerUnit = name: server: (
    nameValuePair "minecraft-server-${name}" (mkIf server.enable {

      description   = "Minecraft Server ${name}";
      wantedBy      = [ "multi-user.target" ];
      after         = [ "network.target" ];

      serviceConfig = {
        ExecStart = "${server.package}/bin/minecraft-server ${server.jvmOpts}";
        Restart = "always";
        WorkingDirectory = if server.dataDir != null then server.dataDir else "/var/lib/minecraft-server-${name}";
        StateDirectory = "minecraft-server-${name}";
        DynamicUser = true;
      };

      preStart = ''
        ln -sf ${eulaFile} eula.txt
      '';
    })
  );

  serverOpts = { config, ... }@moduleAttrs: {
    options = {

      enable = mkEnableOption "A shared minecraft hosting service.";

      dataDir = mkOption {
        type = with types; nullOr path;
        default = null;
        description = ''
          Directory to store Minecraft database and other state/data files.
          When null defaulting to /var/lib/minecraft-server-${name}
        '';
      };

      package = mkOption {
        type = types.package;
        default = pkgs.papermc;
        defaultText = "pkgs.papermc";
        example = literalExample "pkgs.minecraft-server_1_12_2";
        description = "Version of minecraft-server to run.";
      };

      jvmOpts = mkOption {
        type = types.separatedString " ";
        default = "-Xmx2G -Xms1G";
        # Example options from https://minecraft.gamepedia.com/Tutorials/Server_startup_script
        example = "-Xmx2048M -Xms4092M -XX:+UseG1GC -XX:+CMSIncrementalPacing "
          + "-XX:+CMSClassUnloadingEnabled -XX:ParallelGCThreads=2 "
          + "-XX:MinHeapFreeRatio=5 -XX:MaxHeapFreeRatio=10";
        description = "JVM options for the Minecraft server.";
      };
    };
  };

in {
  options = {
    clerie.minecraft-server = {

      servers = mkOption {
        type = with types; attrsOf (submodule serverOpts);
        default = {};
      };

    };
  };

  config = {
    systemd.services = (mapAttrs' generateServerUnit cfg.servers);
  };
}