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

let
  inherit (lib)
    mkDefault mkEnableOption mkIf mkOption

    types;

  cfg = config.dgn-fail2ban;

  settingsFormat = pkgs.formats.keyValue { };

  configFormat = pkgs.formats.ini { };

  jailOptions = {
    options = {
      enabled = mkOption {
        type = types.bool;

        default = true;
        description = "Wether to enable this jail.";
      };

      filter = mkOption {
        type =
          types.nullOr (types.submodule { freeformType = configFormat.type; });

        description = "Content of the filter used for this jail.";
      };

      settings = mkOption {
        type = types.submodule { freeformType = settingsFormat.type; };

        default = { };
        description = "Additional configuration for the jail.";
      };
    };
  };

in {
  options.dgn-fail2ban = {
    enable = mkEnableOption "fail2ban service.";

    jails = mkOption {
      type = types.attrsOf (types.submodule jailOptions);

      default = { };
      description = "Set of jails defined for fail2ban.";
    };
  };

  config = mkIf cfg.enable {
    dgn-fail2ban.jails = builtins.mapAttrs (_: j: j // { enabled = mkDefault false; })
      (import ./jails.nix { });

    services.fail2ban = {
      enable = true;

      inherit (cfg) jails;

      ignoreIP = [
        "10.0.0.0/8"
        "125.199.0.0/16"
        "172.16.0.0/12"
        "192.168.0.0/16"
        "100.64.0.0/10"
        "fd00::/8"
      ];

      bantime-increment = {
        enable = true;

        maxtime = "48h";
        factor = "600";
      };

      extraPackages = [ pkgs.ipset ];
      banaction = "iptables-ipset-proto6-allports";
    };
  };
}