{
  pkgs,
  config,
  lib,
  ...
}:
with lib;
let
  cfg = config.eboskma.services.wireguard.server;

  wireguardPeer = {
    options = {
      publicKey = mkOption {
        description = "The base64 of the public key";
        type = types.str;
      };

      persistentKeepalive = mkOption {
        description = "Keepalive interval in seconds";
        type = with types; nullOr int;
      };

      allowedIPs = mkOption {
        description = "List of IP (v4 or v6) addresses with CIDR mask from which this peer is allowed to send incoming traffic";
        type = with types; listOf str;
      };
    };
  };
in
{
  options.eboskma.services.wireguard.server = {
    enable = mkEnableOption "wireguard";

    externalInterface = mkOption {
      description = "The name of the external interface";
      type = with types; nullOr str;
      default = null;
      example = "enp4s0";
    };

    internalInterface = mkOption {
      description = "The name of the internal interface";
      type = types.str;
      default = "wg0";
      example = "wg0";
    };

    internalIPs = mkOption {
      description = "The internal IP addresses in CIDR notation";
      type = with types; listOf str;
      default = [ ];
      example = [ "10.0.0.0/24" ];
    };

    port = mkOption {
      description = "Wireguard port";
      type = types.port;
      default = 51820;
      example = 51820;
    };

    privateKeyFile = mkOption {
      description = "Private key file";
      type = with types; nullOr str;
      default = null;
      example = "/private/wireguard.key";
    };

    peers = mkOption {
      description = "Peers connected to the interface";
      type = with types; listOf (submodule wireguardPeer);
    };
  };

  config = mkIf cfg.enable {
    networking = {
      nat = {
        enable = true;
        externalInterface = cfg.externalInterface;
        internalInterfaces = [ cfg.internalInterface ];
      };

      firewall.allowedUDPPorts = [ cfg.port ];

      wireguard.interfaces."${cfg.internalInterface}" = {
        ips = cfg.internalIPs;
        listenPort = cfg.port;
        privateKeyFile = cfg.privateKeyFile;

        postSetup = concatMapStringsSep "\n" (range: ''
          ${pkgs.iptables}/bin/iptables -t nat -A POSTROUTING -s ${range} -o ${cfg.externalInterface} -j MASQUERADE
        '') cfg.internalIPs;

        postShutdown = concatMapStringsSep "\n" (range: ''
          ${pkgs.iptables}/bin/iptables -t nat -D POSTROUTING -s ${range} -o ${cfg.externalInterface} -j MASQUERADE
        '') cfg.internalIPs;

        peers = cfg.peers;
      };
    };
  };
}