{
  pkgs,
  lib,
  config,
  factsGenerator,
  components,
  inputs,
  ...
}:

# don't forget the database backup before upgrading
# -------------------------------------------------
# https://docs.nextcloud.com/server/stable/admin_manual/maintenance/backup.html
# https://docs.nextcloud.com/server/stable/admin_manual/maintenance/upgrade.html

let
  # todo : let nextcloud run as media, this would make this part easier.
  nextcloudUid = config.ids.uids.transmission;
  nextcloudGid = config.ids.gids.transmission;
  nextcloudPort = 9080;
  nextcloudHostName = "nextcloud.ingolf-wagner.de";

  phpPackage = pkgs.php83;
  nextcloudPackage = pkgs.nextcloud30;
  mySQLPackage = pkgs.mariadb;
in
{

  networking.firewall.allowedTCPPorts = [
    80
    443
  ];
  networking.firewall.allowedUDPPorts = [
    80
    443
  ];

  healthchecks.http.nextcloud = {
    url = "https://nextcloud.ingolf-wagner.de/login";
    expectedContent = "Login";
    notExpectedContent = "upgrade";
  };

  services.nginx = {
    enable = true;
    recommendedProxySettings = true;
    virtualHosts = {
      "${nextcloudHostName}" = {
        forceSSL = true;
        enableACME = true;
        locations = {
          "/" = {
            proxyPass = "http://localhost:${toString nextcloudPort}";
            extraConfig = ''
              sub_filter "http://${nextcloudHostName}" "https://${nextcloudHostName}";
              # used for view/edit office file via Office Online Server
              client_max_body_size 0;
              proxy_buffering off;  # to download files bigger than 1GB
            '';
          };
          "= /.well-known/carddav" = {
            priority = 210;
            extraConfig = "return 301 $scheme://$host/remote.php/dav;";
          };
          "= /.well-known/caldav" = {
            priority = 210;
            extraConfig = "return 301 $scheme://$host/remote.php/dav;";
          };
        };
      };
    };
  };

  clan.core.facts.services.nextcloud_root = factsGenerator.password {
    service = "nextcloud";
    name = "root";
  };
  clan.core.facts.services.nextcloud_database = factsGenerator.password {
    service = "nextcloud";
    name = "database";
  };

  # Container Setup
  # ===============
  #
  # running:
  # * nextcloud (php)
  # * mysql
  containers.nextcloud = {

    bindMounts = {
      rootpassword = {
        hostPath = config.clan.core.facts.services.nextcloud_root.secret."nextcloud.root".path;
        mountPoint = "/run/secrets/nextcloud.root.intput";
        isReadOnly = true;
      };
      databasepassword = {
        hostPath = config.clan.core.facts.services.nextcloud_database.secret."nextcloud.database".path;
        mountPoint = "/run/secrets/nextcloud.database.input";
        isReadOnly = true;
      };
      share = {
        hostPath = config.services.syncthing.settings.folders.share.path;
        mountPoint = "/media/share";
        isReadOnly = true;
      };
    };

    privateNetwork = false;
    autoStart = true;

    config =
      { config, lib, ... }:
      {
        nixpkgs.pkgs = pkgs;
        imports = [
          inputs.nix-topology.nixosModules.default
          inputs.telemetry.nixosModules.container-telemetry-non-private-network
        ];
        system.stateVersion = "23.11";
        services.logrotate.checkConfig = false; # because uid 3000 does not exist in here

        # Configuring nameservers for containers is currently broken.
        # Therefore in some cases internet connectivity can be broken inside the containers.
        # A temporary workaround is to manually write the /etc/nixos/resolv.conf file like this:
        #environment.etc."resolv.conf".text = "nameserver 8.8.8.8";

        systemd.tmpfiles.settings.nextcloud = {
          "/run/secrets/nextcloud.root"."C+" = {
            user = "nextcloud";
            group = "nextcloud";
            mode = "400";
            argument = "/run/secrets/nextcloud.root.input";
          };
          "/run/secrets/nextcloud.database"."C+" = {
            user = "nextcloud";
            group = "nextcloud";
            mode = "400";
            argument = "/run/secrets/nextcloud.database.input";
          };
        };

        users.users.nextcloud.uid = nextcloudUid;
        users.groups.nextcloud = {
          gid = nextcloudGid;
          members = [ "nextcloud" ];
        };

        services.nginx = {
          defaultListen = [
            {
              addr = "0.0.0.0";
              port = nextcloudPort;
            }
          ];
          # Use recommended settings
          recommendedGzipSettings = lib.mkDefault true;
          recommendedOptimisation = lib.mkDefault true;
          recommendedProxySettings = lib.mkDefault true;
          recommendedTlsSettings = lib.mkDefault true;
        };

        # nextcloud database
        # ==================
        #
        # set user password:
        # -----------------
        # #> mysql
        # mysql> ALTER USER 'nextcloud'@'localhost' IDENTIFIED BY 'nextcloud-password';
        #
        # recreate database:
        # ------------------
        # mysql> DROP DATABASE nextcloud;
        # mysql> CREATE DATABASE nextcloud;
        #
        # migration:
        # ----------
        # nextcloud-occ db:convert-type --all-apps mysql nextcloud 127.0.0.1 nextcloud
        #
        # 4-byte stuff:
        # -------------
        # https://docs.nextcloud.com/server/18/admin_manual/configuration_database/mysql_4byte_support.html
        # if you do this don't forget --default-character-set=utf8mb4 for mysqldump
        services.mysql = {
          enable = true;
          package = mySQLPackage;
          # https://nixos.org/manual/nixos/stable/release-notes.html#sec-release-20.09-incompatibilities
          ensureDatabases = [ "nextcloud" ];
          ensureUsers = [
            {
              name = "nextcloud";
              ensurePermissions = {
                "nextcloud.*" = "ALL PRIVILEGES";
              };
            }
          ];
          settings.mysqld = {
            innodb_large_prefix = true;
            innodb_file_format = "barracuda";
            innodb_file_per_table = 1;
            innodb_read_only_compressed = 0;
          };
        };

        # Backup database
        # ---------------
        services.mysqlBackup = {
          enable = true;
          databases = config.services.mysql.ensureDatabases;
          singleTransaction = true;
        };
        systemd.services."mysql-backup".serviceConfig = {
          ExecStartPre = [ "+/run/current-system/sw/bin/nextcloud-occ maintenance:mode --on" ];
          ExecStopPost = [ "+/run/current-system/sw/bin/nextcloud-occ maintenance:mode --off" ];
        };

        # in php
        services.phpfpm = {
          phpPackage = phpPackage;
          phpOptions = ''
            opcache.revalidate_freq = 10
          '';
        };

        # nextcloud setup
        services.nextcloud = {
          enable = true;
          package = nextcloudPackage;
          autoUpdateApps.enable = true;
          hostName = nextcloudHostName;
          https = true;
          settings = {
            overwriteprotocol = "https";
            default_phone_region = "DE";
            loglevel = 2;
          };
          config = {
            adminpassFile = "/run/secrets/nextcloud.root";
            #overwriteProtocol = "https";
            dbtype = "mysql";
            dbpassFile = "/run/secrets/nextcloud.database";
            dbhost = "localhost:3306";
          };
        };
      };
  };

}