{ lib, ... }:

let
  inherit (lib)
    mkDefault
    mkEnableOption
    mkIf
    mkOption
    types
    ;
in
{
  isNotEmptyStr = str: builtins.isString str && str != "";

  mkMailIntegrationOption = service: {
    enable = mkEnableOption "Mail integration for ${service}.";
    smtpHost = mkOption {
      type = types.str;
      default = "localhost";
      description = "SMTP host for sending emails.";
    };
  };

  mkReverseProxyOption = service: subdomain: {
    enable = mkEnableOption "Nginx reverse proxy for ${service}.";
    subdomain = mkOption {
      type = types.str;
      default = subdomain;
      description = "Subdomain for Nginx virtual host. Leave empty for root domain.";
    };
    forceSSL = mkOption {
      type = types.bool;
      default = true;
      description = "Force SSL for Nginx virtual host.";
    };
  };

  mkUrl =
    {
      fqdn,
      ssl ? false,
      port ? null,
      path ? "",
      ...
    }:
    let
      protocol = if ssl then "https" else "http";
      portPart = if port != null then ":${toString port}" else "";
      pathPart = if path != "" then "/${path}" else "";
    in
    "${protocol}://${fqdn}${portPart}${pathPart}";

  mkVirtualHost =
    {
      address ? "127.0.0.1",
      port ? null,
      socketPath ? null,
      location ? "/",
      ssl ? false,
      proxyWebsockets ? true,
      recommendedProxySettings ? true,
      extraConfig ? "",
      ...
    }:
    let
      target =
        if port != null then
          "http://${address}:${builtins.toString port}"
        else if socketPath != null then
          "http://unix:${socketPath}"
        else
          null;
    in
    {
      enableACME = ssl;
      forceSSL = ssl;

      locations = mkIf (target != null) {
        "${location}" = {
          proxyPass = mkDefault target;
          inherit proxyWebsockets recommendedProxySettings extraConfig;
        };
      };
    };
}
