{
  config,
  lib,
  pkgs,
  ...
}: let
  cfg = config.hive.nextcloud-instance;
in {
  options.hive.nextcloud-instance = {
    enable = lib.mkEnableOption "Enable the Nextcloud instance";

    instanceFQDN = lib.mkOption {
      type = lib.types.str;
      example = "nextcloud.example.com";
      description = "Fully qualified domain name of the Nextcloud instance";
    };

    ssl = lib.mkOption {
      type = lib.types.bool;
      default = true;
      description = "Use SSL and auto-update certificates";
    };

    adminPasswordFile = lib.mkOption {
      type = lib.types.path;
      example = "/etc/nc-admin-pass.txt";
      description = "Path to the file containing the Nextcloud admin password";
    };
  };

  config = lib.mkIf cfg.enable {
    services.nextcloud = {
      # Instance
      enable = true;
      package = pkgs.nextcloud31;
      hostName = cfg.instanceFQDN;
      https = cfg.ssl;
      configureRedis = true;

      # DB
      config.dbtype = "pgsql";
      config.dbhost = "/run/postgresql";
      config.adminpassFile = cfg.adminPasswordFile;

      #Mail
      settings = {
        mail_smtpmode = "sendmail";
        mail_sendmailmode = "pipe";
      };

      # Apps
      extraAppsEnable = true;
      extraApps = {
        inherit
          (config.services.nextcloud.package.packages.apps)
          calendar
          contacts
          maps
          tasks
          ;
        drop_account = pkgs.fetchNextcloudApp {
          sha256 = "sha256-AAWAR5i8moGlyGMaNqJwQPqPAHqWvIf4mvZ4U0dfg/A=";
          url = "https://packages.framasoft.org/projects/nextcloud-apps/drop-account/drop_account-2.7.1.tar.gz";
          license = "agpl3Only";
        };
      };

      # Preview settings (video may be a security risk)
      settings = {
        enable_previews = true;
        enabledPreviewProviders = [
          "OC\\Preview\\BMP"
          "OC\\Preview\\GIF"
          "OC\\Preview\\JPEG"
          "OC\\Preview\\Krita"
          "OC\\Preview\\MarkDown"
          "OC\\Preview\\MP3"
          "OC\\Preview\\OpenDocument"
          "OC\\Preview\\PNG"
          "OC\\Preview\\TXT"
          "OC\\Preview\\XBitmap"
          "OC\\Preview\\Movie"
          "OC\\Preview\\MP4"
          "OC\\Preview\\AVI"
          "OC\\Preview\\MKV"
        ];
        preview_ffmpeg_path = "${pkgs.ffmpeg}/bin/ffmpeg";
      };
    };

    # Fallback server with only 403
    services.nginx.virtualHosts.${config.networking.domain} = lib.mkDefault {
      default = true;
      locations."/".return = 403;
      forceSSL = cfg.ssl;
      enableACME = cfg.ssl;
    };

    # Webserver setup with optional SSL
    services.nginx.virtualHosts.${cfg.instanceFQDN} =
      if cfg.ssl
      then {
        forceSSL = true;
        enableACME = true;
      }
      else {
        listen = [
          {
            addr = "0.0.0.0";
            port = 80;
          }
        ];
      };
    security.acme = lib.mkIf cfg.ssl {
      acceptTerms = true;
      defaults.email = "jonas.roeger+acme@gmail.com";
    };
    networking.firewall.allowedTCPPorts = [80] ++ lib.optional cfg.ssl 443;

    # DB setup
    services.postgresql = {
      enable = true;
      ensureDatabases = ["nextcloud"];
      ensureUsers = [
        {
          name = "nextcloud";
          ensureDBOwnership = true;
        }
      ];
    };
  };
}
