# Kudos to https://github.com/notgne2

{ config, lib, pkgs, ... }:
with lib;
let cfg = config.services.ezwg;
in {
  options.services.ezwg = {
    enable = mkEnableOption "Enable simple Wireguard connection";
    proxy = mkOption {
      type = types.bool;
      default = true;
      description = "Route all your traffic through this connection";
    };
    lanSize = mkOption {
      type = types.int;
      default = 24;
      description = "Size of your VLAN (only relevant if proxy is false)";
    };
    serverIP = mkOption {
      type = types.str;
      description = "The IP of the wg server";
    };
    serverPort = mkOption {
      type = types.int;
      default = 51820;
      description = "The port of the wg server";
    };
    serverKey = mkOption {
      type = types.str;
      description = "The public key of the wg server";
    };
    privateKeyFile = mkOption {
      type = types.str;
      description = "Private wg key";
    };
    vlanIP = mkOption {
      type = types.str;
      description = "The IP to use on the wg VLAN";
    };
  };
  config = mkIf cfg.enable {
    networking.firewall.checkReversePath = false;
    systemd.services.wireguard-wg0.wantedBy = lib.mkForce [ ];
    systemd.paths.wireguard-wg0.wantedBy = lib.mkForce [ ];
    systemd.services."wireguard-wg0-peer-${
      lib.replaceChars [ "/" "-" " " "+" "=" ] [
        "-"
        "\\x2d"
        "\\x20"
        "\\x2b"
        "\\x3d"
      ] cfg.serverKey
    }".wantedBy = lib.mkForce [ ];

    networking.wireguard.interfaces.wg0 = let
      generateRangesScript =
        builtins.toFile "exclusionary-wildcard-ranges-generator.py" ''
          import ipaddress
          n1 = ipaddress.ip_network('0.0.0.0/0')
          n2 = ipaddress.ip_network('${cfg.serverIP}/32')
          print(':'.join(list(map(lambda x: str(x), list(n1.address_exclude(n2))))), end="")
        '';
      rangesOutput = pkgs.runCommandNoCC "exclusionary-wildcard-ranges" { } ''
        ${pkgs.python3}/bin/python3 ${generateRangesScript} > $out
      '';
      generateSubnetScript =
        builtins.toFile "subnet-without-host-bits-generator.py" ''
          import ipaddress
          n1 = ipaddress.ip_network('${cfg.vlanIP}/${
            toString cfg.lanSize
          }', False)
          print(n1, end="")
        '';
      subnetOutput = pkgs.runCommandNoCC "subnet-without-host-bits" { } ''
        ${pkgs.python3}/bin/python3 ${generateSubnetScript} > $out
      '';
      ranges = lib.splitString ":" (builtins.readFile "${rangesOutput}");
      subnet = builtins.readFile "${subnetOutput}";
    in {
      ips = [ "${cfg.vlanIP}/${toString cfg.lanSize}" ];
      privateKeyFile = cfg.privateKeyFile;
      peers = [{
        publicKey = cfg.serverKey;
        allowedIPs = if cfg.proxy then ranges else [ subnet ];
        endpoint = "${cfg.serverIP}:${toString cfg.serverPort}";
        persistentKeepalive = 25;
      }];
    };
  };
}
