# A NixOS module which can run a service tracking spending of ZKAPs.
# ZKAPs.
{ lib, pkgs, config, ourpkgs, ... }@args: let
  cfg = config.services.private-storage-spending;
in
{
  options = {
    services.private-storage-spending = {
      enable = lib.mkEnableOption "PrivateStorage Spending Service";
      package = lib.mkOption {
        default = ourpkgs.zkap-spending-service;
        type = lib.types.package;
        example = "ourpkgs.zkap-spending-service";
        description = ''
          The package to use for the spending service.
        '';
      };
      unixSocket = lib.mkOption {
        default = "/run/zkap-spending-service/api.socket";
        type = lib.types.path;
        description = ''
          The unix socket that the spending service API listens on.
        '';
      };
    };
    services.private-storage-spending.domain = lib.mkOption {
      default = config.networking.fqdn;
      type = lib.types.str;
      example = [ "spending.example.com" ];
      description = ''
        The domain name at which the spending service is reachable.
      '';
    };
  };

  config =
    lib.mkIf cfg.enable {
      systemd.sockets.zkap-spending-service = {
        enable = true;
        wantedBy = [ "sockets.target" ];
        listenStreams = [ cfg.unixSocket ];
      };

      # Add a systemd service to run zkap-spending-service.
      systemd.services.zkap-spending-service = {
        enable = true;
        description = "ZKAP Spending Service";
        wantedBy = [ "multi-user.target" ];

        serviceConfig = (import ./restricted-service.nix) // {
          NonBlocking = true;

          # It really shouldn't ever exit on its own!  If it does, it's a bug
          # we'll have to fix.  Restart it and hope it doesn't happen too much
          # before we can fix whatever the issue is.
          Restart = "always";
          Type = "simple";

          # Work around https://twistedmatrix.com/trac/ticket/10261
          # Create a runtime directory so that the service has permission
          # to change the mode on the socket.
          RuntimeDirectory = "zkap-spending-service";
        };

        script = let
          httpArgs = "--http-endpoint systemd:domain=UNIX:index=0";
        in
          "exec ${cfg.package}/bin/${cfg.package.meta.mainProgram} run ${httpArgs}";
      };

      services.nginx = {
        enable = true;

        recommendedGzipSettings = true;
        recommendedOptimisation = true;
        recommendedProxySettings = true;
        recommendedTlsSettings = true;

        virtualHosts."${cfg.domain}" = {
          locations."/v1/" = {
            # Only forward requests beginning with /v1/ so
            # we pass less scanning spam on to our backend
            # Want a regex instead? try locations."~ /v\d+/"
            proxyPass = "http://unix:${cfg.unixSocket}";
          };
          locations."/metrics" = {
            proxyPass = "http://unix:${cfg.unixSocket}";
            # Only allow our monitoringvpn subnet
            extraConfig = ''
              allow 172.23.23.0/24;
              allow 127.0.0.1;
              allow ::1;
              deny all;
            '';
          };
          locations."/" = {
            # Return a 404 error for any paths not specified above.
            extraConfig = ''
              return 404;
            '';
          };
        };
      };

      # Open 80 and 443 for nginx
      networking.firewall.allowedTCPPorts = [
        80
        443
      ];
    };
}