{ config, lib, pkgs, secretsDir, ... }:
let
  tailscale = config.deviceSpecific.vpn.tailscale;
  wg = config.deviceSpecific.vpn.wireguard;
  sing-box = config.deviceSpecific.vpn.sing-box;
  wgIFName = "wg0";
  isRouteAll = (builtins.elem "0.0.0.0/0" wg.allowedIPs) || (builtins.elem "::0/0" wg.allowedIPs);
in {
  config = lib.mkMerge [
    (lib.mkIf sing-box.enable {
      sops.secrets.${sing-box.config} = {
        sopsFile = secretsDir + /proxy.yaml;
        restartUnits = [ "sing-box.service" ];
        mode = "0600";
      };
      systemd.packages = [ pkgs.sing-box ];
      systemd.services.sing-box = {
        preStart = ''
          umask 0077
          mkdir -p /etc/sing-box
          cp ${config.sops.secrets.${sing-box.config}.path} /etc/sing-box/config.json
        '';
        wantedBy = [ "multi-user.target" ];
      };
    })
    (lib.mkIf tailscale.enable {
      services.tailscale.enable = true;
      services.tailscale.useRoutingFeatures = "client";
      persist.state.directories = [ "/var/lib/tailscale" ];
    })
    # TODO: currently broken, i'm using wg-quick for now
    (lib.mkIf wg.enable {
      networking.useNetworkd = false;
      systemd.network = {
        enable = false;
        wait-online.ignoredInterfaces = lib.optionals (!isRouteAll) [ wgIFName ];
        netdevs."90-${wgIFName}" = {
          netdevConfig = {
            Name = wgIFName;
            Kind = "wireguard";
            Description = "${wgIFName} - wireguard tunnel";
          };
          wireguardConfig = {
            PrivateKeyFile = wg.keys.privateFile;
            FirewallMark = 34952; # 0x8888
            ListenPort = wg.port + 1;
          };
          wireguardPeers = [{
            wireguardPeerConfig = {
              PublicKey = wg.keys.public;
              PresharedKeyFile = wg.keys.presharedFile;
              AllowedIPs = lib.concatStringsSep "," wg.allowedIPs;
              Endpoint = wg.endpoint;
              PersistentKeepalive = 25;
            };
          }];
        };
        networks."90-${wgIFName}" = {
          matchConfig.Name = wgIFName;
          address = wg.address;
          linkConfig.ActivationPolicy = if wg.autostart then "up" else "manual";
          networkConfig = {
            # IPForward = true;
            # IPMasquerade = "both";
            DNSDefaultRoute = true;
            DNS = wg.dns;
            Domains = "~";
          };
          routes = lib.optionals (isRouteAll && wg.gateway.ipv4 != null) [
            {
              routeConfig.Gateway = wg.gateway.ipv4;
              routeConfig.Destination = "0.0.0.0/0";
              routeConfig.GatewayOnLink = true;
              routeConfig.Table = 1000;
            }
            {
              routeConfig.Gateway = wg.gateway.ipv6;
              routeConfig.GatewayOnLink = true;
              routeConfig.Table = 1000;
            }
          ];
          routingPolicyRules = lib.optionals (isRouteAll && wg.gateway != null) [{
            routingPolicyRuleConfig.FirewallMark = 34952; # 0x8888
            routingPolicyRuleConfig.InvertRule = true;
            routingPolicyRuleConfig.Table = 1000;
            routingPolicyRuleConfig.Priority = 10;
          }];
        };
      };
    })
  ];
}
