{ config, lib, ... }:

let
  inherit (lib) mkOption;

  inherit (lib.types)
    attrsOf
    ints
    listOf
    str
    submodule
    ;

  mkRetired =
    hosts:
    builtins.listToAttrs (
      builtins.map (name: {
        inherit name;
        value = {
          enableACME = true;
          forceSSL = true;
          locations."/".return = "301 https://${cfg.retiredHost}/${name}";
        };
      }) hosts
    );

  mkPermanent = _: globalRedirect: {
    inherit globalRedirect;

    enableACME = true;
    forceSSL = true;
  };

  mkTemporary =
    _:
    {
      to,
      code,
      location,
    }:
    {
      enableACME = true;
      forceSSL = true;

      locations.${location}.return = "${toString code} ${to}";
    };

  cfg = config.dgn-redirections;
in

{
  options.dgn-redirections = {
    permanent = mkOption {
      type = attrsOf str;
      default = { };
      description = ''
        Attribute set of redirections, for:
        { a = b; },
        a redirection from a to b will be made.
      '';
    };

    temporary = mkOption {
      type = attrsOf (submodule {
        options = {
          to = mkOption {
            type = str;
            description = "Target of the redirection";
          };
          code = mkOption {
            type = ints.between 300 399;
            default = 302;
            example = 308;
            description = ''
              HTTP status used by the redirection. Possible usecases
              include temporary (302, 307) redirects, keeping the request method and
              body (307, 308), or explicitly resetting the method to GET (303).
              See <https://developer.mozilla.org/en-US/docs/Web/HTTP/Redirections>.
            '';
          };
          location = mkOption {
            type = str;
            default = "/";
            description = "nginx-style location for the source of the redirection";
          };
        };
      });
      default = { };
      example = {
        "source.dgnum.eu" = {
          to = "https://target.dgnum.eu/path_to_page";
          code = 307;
          location = "/subpath/";
        };
      };
      description = ''
        Attribute set of temporary redirections. The attribute is the source
        domain.

        For:
        ```
        {
          "source.dgnum.eu" = {
            to = "https://target.dgnum.eu/path_to_page";
            code = 307;
          };
        }
        ```
        a 307 redirect from all the urls within the domain `source.dgnum.eu` to
        `https://target.dgnum.eu/path_to_page` will be made.
      '';
    };

    retired = mkOption {
      type = listOf str;
      default = [ ];
      description = ''
        List of retired domains, they will we redirected to `retired.dgnum.eu/$host`.
      '';
    };

    retiredHost = mkOption {
      type = str;
      default = "retired.dgnum.eu";
      description = ''
        Host used for the redirections of retired services.
      '';
    };
  };

  config = {
    services.nginx.virtualHosts =
      (builtins.mapAttrs mkPermanent cfg.permanent // builtins.mapAttrs mkTemporary cfg.temporary)
      // (mkRetired cfg.retired);
  };
}