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

# This module provides a container whose traffic is routed through Mullvad VPN.
# Other modules may configure `containers.mullvad-vpn.config` to run their
# services through the container.

let cfg = config.sydnix.deertopia.mullvad;
in {
  options.sydnix.deertopia.mullvad = {
    enable = lib.mkEnableOption "Mullvad VPN";
    interface = lib.mkOption {
      description = ''
        The network interface to use.  See the output of `ip addr show`.
      '';
      type = lib.types.str;
      default = "eno1";
    };
    peer = lib.mkOption {
      default = "us-atl-wg-001";
      type = lib.types.str;
      description = ''
        The name of a Wireguard configuration file in
        modules/nixos/deertopia/mullvad/, without the .conf suffix.  Ideally, we
        would support multiple peers without rebuilding, but...
      '';
    };
  };

  config = lib.mkIf cfg.enable {
    sydnix.sops.secrets.wireguard-mullvad-key = {};

    networking.nat = {
      enable = true;
      internalInterfaces = [ "ve-mullvad-vpn" ];
      externalInterface = cfg.interface;
    };

    containers.mullvad-vpn = {
      # Impermanence-esque wiping of undeclared state.
      ephemeral = true;
      autoStart = true;
      privateNetwork = true;
      enableTun = true;
      # These IP choices are arbitrary.
      hostAddress = "192.168.100.10";
      # Counter-intuitively (IMO), the host reaches the container at *this*
      # address.
      localAddress = "192.168.100.11";

      # Bind these directories to their corresponding paths on the host as to
      # persist them through container reboots.
      bindMounts = {
        "/config/wg".hostPath = toString ./mullvad;
        "/run/secrets".hostPath = "/run/secrets";
      };

      config = { pkgs, ... }@args: lib.mkMerge [
        {
          systemd.services."create-wireguard-config" = {
            script = ''
              if [ ! -e /wg.conf ]; then
                cp "/config/wg/${cfg.peer}.conf" /wg.conf
                ${pkgs.replace-secret}/bin/replace-secret \
                  '{{WG_PRIVATE_KEY}}' \
                  /run/secrets/wireguard-mullvad-key \
                  /wg.conf
                  chmod 777 /wg.conf
              fi
            '';
            # requiredBy = [ "wg-quick0-wg0.service" ];
            requires = [ "tmp.mount" ];
          };

          # HACK: Make sure wg starts *after* its config exists.
          systemd.services."wg-quick-wg0".requires =
            [ "create-wireguard-config.service" ];

          networking.wg-quick.interfaces.wg0.configFile = "/wg.conf";
          system.stateVersion = "24.11";
        }
      ];
    };
  };
}
