{ lib, config, ... }:

let
  inherit (builtins) toString;
  inherit (lib) mkOption mkEnableOption mkForce;
  inherit (lib.types) types;

in
{
  imports = [
    ./garage.nix
    ./mastodon.nix
    ./pixelfed.nix
    ./peertube.nix
  ];

  options = {
    fediversity = {
      enable = mkEnableOption "the collection of services bundled under Fediversity";

      domain = mkOption {
        type = types.str;
        description = ''
          root domain for the Fediversity services

          For instance, if this option is set to `foo.example.com`, then
          Pixelfed might be under `pixelfed.foo.example.com`.
        '';
      };

      mastodon.enable = mkEnableOption "default Fediversity Mastodon configuration";
      pixelfed.enable = mkEnableOption "default Fediversity Pixelfed configuration";
      peertube.enable = mkEnableOption "default Fediversity PeerTube configuration";

      temp = mkOption {
        description = "options that are only used while developing; should be removed eventually";
        default = { };
        type = types.submodule {
          options = {
            cores = mkOption {
              description = "number of cores; should be obtained from NixOps4";
              type = types.int;
            };

            peertubeSecretsFile = mkOption {
              description = "should it be provided by NixOps4? or maybe we should just ask for a main secret from which to derive all the others?";
              type = types.path;
            };
          };
        };
      };

      internal = mkOption {
        description = "options that are only meant to be used internally; change at your own risk";
        default = { };
        type = types.submodule {
          options = {
            garage = {
              api = {
                domain = mkOption {
                  type = types.str;
                  default = "s3.garage.${config.fediversity.domain}";
                };
                port = mkOption {
                  type = types.int;
                  default = 3900;
                };
                url = mkOption {
                  type = types.str;
                  default = "http://${config.fediversity.internal.garage.api.domain}:${toString config.fediversity.internal.garage.api.port}";
                };
              };

              rpc = {
                port = mkOption {
                  type = types.int;
                  default = 3901;
                };
              };

              web = {
                rootDomain = mkOption {
                  type = types.str;
                  default = "web.garage.${config.fediversity.domain}";
                };
                internalPort = mkOption {
                  type = types.int;
                  default = 3902;
                };
                domainForBucket = mkOption {
                  type = types.functionTo types.str;
                  default = bucket: "${bucket}.${config.fediversity.internal.garage.web.rootDomain}";
                };
                urlForBucket = mkOption {
                  type = types.functionTo types.str;
                  default = bucket: "http://${config.fediversity.internal.garage.web.domainForBucket bucket}";
                };
              };
            };

            ## REVIEW: Do we want to recreate options under
            ## `fediversity.internal` or would we rather use the options from
            ## the respective services? See Taeer's comment:
            ## https://git.fediversity.eu/taeer/simple-nixos-fediverse/pulls/22#issuecomment-124
            pixelfed.domain = mkOption {
              type = types.str;
              default = "pixelfed.${config.fediversity.domain}";
            };
            mastodon.domain = mkOption {
              type = types.str;
              default = "mastodon.${config.fediversity.domain}";
            };
            peertube.domain = mkOption {
              type = types.str;
              default = "peertube.${config.fediversity.domain}";
            };
          };
        };
      };
    };
  };

  config = {
    ## FIXME: This should clearly go somewhere else; and we should have a
    ## `staging` vs. `production` setting somewhere.
    security.acme = {
      acceptTerms = true;
      defaults.email = "nicolas.jeannerod+fediversity@moduscreate.com";
      # defaults.server = "https://acme-staging-v02.api.letsencrypt.org/directory";
    };

    ## NOTE: For a one-machine deployment, this removes the need to provide an
    ## `s3.garage.<domain>` domain. However, this will quickly stop working once
    ## we go to multi-machines deployment.
    fediversity.internal.garage.api.domain = mkForce "s3.garage.localhost";
  };
}