{ config, lib, ... }:

with lib;

{
  options.architect = {
    firewall = {
      openTCP = mkOption {
        type = types.listOf types.int;
        default = [ ];
      };
      openUDP = mkOption {
        type = types.listOf types.int;
        default = [ ];
      };
    };

    networks = mkOption {
      type = types.attrsOf (types.submodule {
        options = {
          interface = mkOption {
            type = types.str;
            description = "The network interface name.";
          };

          net = mkOption {
            type = types.str;
            description = "The network address in CIDR format.";
          };

          devices = mkOption {
            type = types.attrsOf (types.submodule {
              options = {
                address = mkOption {
                  type = types.str;
                  description = "The IP address of the device.";
                };

                hostname = mkOption {
                  type = types.str;
                  description = "The hostname of the device.";
                };
              };
            });
            default = { };
            description = "An attribute set of devices with their configurations.";
          };
        };
      });
      default = { };
      description = "An attribute set of networks with their configurations.";
    };

    vhost = mkOption {
      type = types.attrsOf (types.submodule {
        options = {
          dnsInterfaces = mkOption {
            type = types.listOf types.str;
            default = [ ];
            description = "List of interfaces to add extra DNS hosts for this vhost.";
          };

          locations = mkOption {
            type = types.attrsOf (types.submodule {
              options = {
                extraConfig = mkOption {
                  type = types.str;
                  description = "Extra configuration for the location.";
                  default = "";
                };

                allowLan = mkOption {
                  type = types.bool;
                  default = false;
                };

                proxyWebsockets = mkOption {
                  type = types.bool;
                  default = false;
                };

                host = mkOption {
                  type = types.str;
                  description = "The host for the location.";
                  default = "127.0.0.1";
                };

                port = mkOption {
                  type = types.int;
                  description = "The port number for the location.";
                };

                allow = mkOption {
                  type = types.listOf types.str;
                  default = [ ];
                  description = "IP address or CIDR block to allow.";
                };

                path = mkOption {
                  type = types.str;
                  default = "";
                };

                allowWAN = mkOption {
                  type = types.bool;
                  default = false;
                  description = "If set to false, deny all WAN traffic.";
                };
              };
            });
            default = { };
            description = "An attribute set of location configurations.";
          };
        };
      });
      default = { };
      description = "An attribute set of domain configurations.";
    };
  };

  # TODO: move to nginx
  config = {
    services.nginx.virtualHosts = mapAttrs
      (domain: conf: {
        forceSSL = true;
        enableACME = true;
        locations = mapAttrs
          (path: location: {
            proxyPass = "http://${location.host}:${toString location.port}${location.path}";
            proxyWebsockets = location.proxyWebsockets;
            extraConfig = ''
              ${concatMapStringsSep "\n" (allowCIDR: "allow ${allowCIDR};") location.allow}
              ${optionalString location.allowLan ''allow ${config.architect.networks."lan".net};''}
              ${optionalString (!location.allowWAN) "deny all;"}
            '' + location.extraConfig;
          })
          conf.locations;
      })
      config.architect.vhost;
  };
}