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

with lib;

let
  cfg = config.services.zapret;
in
{
  options.services.zapret = {
    enable = mkEnableOption "DPI bypass multi platform service";

    package = mkPackageOption pkgs "zapret" { };

    settings = mkOption {
      type = types.lines;
      default = "";

      example = ''
        TPWS_OPT="--hostspell=HOST --split-http-req=method --split-pos=3 --oob"
        NFQWS_OPT_DESYNC="--dpi-desync-ttl=5"
      '';

      description = ''
        Rules for zapret to work. Run ```nix-shell -p zapret --command blockcheck``` to get values to pass here.
        Config example can be found here https://github.com/bol-van/zapret/blob/master/config.default
      '';
    };

    firewallType = mkOption {
      type = types.enum [
        "iptables"
        "nftables"
      ];
      default = "iptables";
      description = ''
        Which firewall zapret should use
      '';
    };

    disableIpv6 = mkOption {
      type = types.bool;
      # recommended by upstream
      default = true;
      description = ''
        Disable or enable usage of IpV6 by zapret
      '';
    };

    mode = mkOption {
      type = types.enum [
        "tpws"
        "tpws-socks"
        "nfqws"
        "filter"
        "custom"
      ];
      default = "tpws";
      description = ''
        Which mode zapret should use
      '';
    };
  };

  config = mkIf cfg.enable {
    users.users.tpws = {
      isSystemUser = true;
      group = "tpws";
    };

    users.groups.tpws = { };

    systemd.services.zapret = {
      after = [ "network-online.target" ];
      wants = [ "network-online.target" ];
      wantedBy = [ "multi-user.target" ];

      path = with pkgs; [
        (if cfg.firewallType == "iptables" then iptables else nftables)
        gawk
        ipset
      ];

      serviceConfig = {
        Type = "forking";
        Restart = "no";
        TimeoutSec = "30sec";
        IgnoreSIGPIPE = "no";
        KillMode = "none";
        GuessMainPID = "no";
        RemainAfterExit = "no";
        ExecStart = "${cfg.package}/bin/zapret start";
        ExecStop = "${cfg.package}/bin/zapret stop";

        EnvironmentFile = pkgs.writeText "${cfg.package.pname}-environment" (concatStrings [
          ''
            MODE=${cfg.mode}
            FWTYPE=${cfg.firewallType}
            DISABLE_IPV6=${if cfg.disableIpv6 then "1" else "0"}
          ''
          cfg.settings
        ]);

        # hardening
        DevicePolicy = "closed";
        KeyringMode = "private";
        PrivateTmp = true;
        PrivateMounts = true;
        ProtectHome = true;
        ProtectHostname = true;
        ProtectKernelModules = true;
        ProtectKernelTunables = true;
        ProtectSystem = "strict";
        ProtectProc = "invisible";
        RemoveIPC = true;
        RestrictNamespaces = true;
        RestrictRealtime = true;
        RestrictSUIDSGID = true;
        SystemCallArchitectures = "native";
      };
    };
  };
}
