{ pkgs, config, ... }:

# 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
#
# ! use lvm snapshots to do rollback !

let

  hostInterface = "enp3s0";
  hostAddress = "192.168.100.10";
  containerAddress = "192.168.100.11";
  nextcloudUid = 1000;
  borg_backup_folder = "/media/syncthing/nextcloud_backup/robi";

in
{


  # Host Setup
  # ==========

  # give containers internet access
  networking.nat.enable = true;
  networking.nat.internalInterfaces = [ "ve-nextcloud" ];
  networking.nat.externalInterface = hostInterface;

  # don't let networkmanager manger container network
  networking.networkmanager.unmanaged = [ "interface-name:ve-*" ];

  # open ports for logging
  #networking.firewall.interfaces."ve-nextcloud".allowedTCPPorts =
  #  [ 5044 12304 12305 ];
  #networking.firewall.interfaces."ve-nextcloud".allowedUDPPorts =
  #  [ 5044 12304 12305 ];

  # host nginx
  # ----------

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

  services.nginx = {
    enable = true;
    recommendedProxySettings = true;
    virtualHosts = {
      "nextcloud.ingolf-wagner.de" = {
        forceSSL = true;
        enableACME = true;
        locations = {
          "/" = {
            proxyPass = "http://${containerAddress}";
            extraConfig = ''
              sub_filter "http://nextcloud.ingolf-wagner.de" "https://nextcloud.ingolf-wagner.de";
              # 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;";
          };
          #"~ .(?:css|js|svg|gif)$" = {
          #  proxyPass = "http://${containerAddress}$request_uri";
          #  extraConfig = ''
          #    expires 6M;         # Cache-Control policy borrowed from `.htaccess`
          #    access_log off;     # Optional: Don't log access to assets
          #    sub_filter "http://nextcloud.ingolf-wagner.de" "https://nextcloud.ingolf-wagner.de";
          #    sub_filter "nextcloud.workhorse.private" "nextcloud.ingolf-wagner.de";
          #    # used for view/edit office file via Office Online Server
          #    client_max_body_size 0;
          #  '';
          #};
          #"~ .woff2?$" = {
          #  proxyPass = "http://${containerAddress}$request_uri";
          #  extraConfig = ''
          #    expires 7d;         # Cache-Control policy borrowed from `.htaccess`
          #    access_log off;     # Optional: Don't log access to assets
          #    sub_filter "http://nextcloud.ingolf-wagner.de" "https://nextcloud.ingolf-wagner.de";
          #    sub_filter "nextcloud.workhorse.private" "nextcloud.ingolf-wagner.de";
          #    # used for view/edit office file via Office Online Server
          #    client_max_body_size 0;
          #  '';
          #};
        };
      };
    };
  };

  sops.secrets.nextcloud_database_password.owner = "nextcloud";
  sops.secrets.nextcloud_root_password.owner = "nextcloud";

  users.users.nextcloud = {
    isSystemUser = true;
    uid = nextcloudUid;
    group = "nextcloud";
  };
  users.groups.nextcloud = { };


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

    # mount host folders
    bindMounts = {
      rootpassword = {
        hostPath = "/run/secrets/nextcloud_root_password";
        mountPoint = "/run/secrets/nextcloud_root_password";
        isReadOnly = true;
      };
      databasepassword = {
        hostPath = "/run/secrets/nextcloud_database_password";
        mountPoint = "/run/secrets/nextcloud_database_password";
        isReadOnly = true;
      };

      home = {
        # make sure this folder exist on the host
        hostPath = toString "/var/lib/nextcloud";
        mountPoint = "/var/lib/nextcloud";
        isReadOnly = false;
      };
      db = {
        # make sure this folder exist on the host
        hostPath = toString "/var/lib/nextcloud_mysql";
        mountPoint = "/var/lib/mysql";
        isReadOnly = false;
      };
      media = {
        #mountPoint = toString config.services.syncthing.folders.media.path;
        #hostPath = toString config.services.syncthing.folders.media.path;
        mountPoint = "/media/syncthing/media";
        hostPath = "/media/media";
        isReadOnly = true;
      };
    };

    # container network setup
    # see also nating on host system.
    privateNetwork = true;
    hostAddress = hostAddress;
    localAddress = containerAddress;


    autoStart = true;

    config = { config, pkgs, lib, ... }: {

      # 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";

      system.stateVersion = "21.05";

      users.users.nextcloud.uid = nextcloudUid;

      services.nginx = {
        # Use recommended settings
        recommendedGzipSettings = lib.mkDefault true;
        recommendedOptimisation = lib.mkDefault true;
        recommendedProxySettings = lib.mkDefault true;
        recommendedTlsSettings = lib.mkDefault true;
      };

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

      # 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 = pkgs.mysql;
        # 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;
        location = "/var/lib/nextcloud/database_backups";
      };
      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 = pkgs.php73;
        phpOptions = ''
          opcache.revalidate_freq = 10
        '';
      };

      # nextcloud setup
      services.nextcloud = {
        enable = true;
        package = pkgs.nextcloud28;
        autoUpdateApps.enable = true;
        # nginx.enable = true;
        # enableBrokenCiphersForSSE = false; # see https://github.com/NixOS/nixpkgs/pull/198470
        hostName = "nextcloud.ingolf-wagner.de";
        logLevel = 2;
        https = true;
        config = {
          adminpassFile = "/run/secrets/nextcloud_root_password";
          overwriteProtocol = "https";
          trustedProxies = [ "144.76.13.147" hostAddress ];
          dbtype = "mysql";
          dbpassFile = "/run/secrets/nextcloud_database_password";
          dbport = 3306;
          defaultPhoneRegion = "DE";
        };
      };
    };
  };


  # Backup Config
  # -------------
  #backup.dirs = [
  #  "/home/nextcloud/config"
  #  "/home/nextcloud/database_backups" # created by mysqlBackup
  #];

  # Backup Files
  # ------------
  services.borgbackup.jobs = {
    "nextcloud-to-media" = {
      repo = borg_backup_folder;
      # make sure syncthing is capable of reading the files
      postHook = ''
        chown -R syncthing:syncthing ${borg_backup_folder}
      '';
      compression = "lz4";
      paths = [
        "/var/lib/nextcloud/data/tina/files"
        "/var/lib/nextcloud/data/palo/files"
        "/var/lib/nextcloud/data/palo-windows/files"
      ];
      doInit = true;
      encryption = {
        mode = "repokey-blake2";
        passCommand = "cat ${config.sops.secrets.backup_repository_passphrase.path}";
      };
      startAt = "0/3:00:00";
      prune.keep = {
        within = "2d"; # Keep all backups in the last 10 days.
        daily = 10; # Keep 10 additional end of day archives
        weekly = 8; # Keep 8 additional end of week archives.
        month = 8; # Keep 8 additional end of month archives.
      };
    };
  };

}