{ config, lib, nixos, pkgs, ssh-public-keys, zentralwerk, ... }:

# this file contains default configuration that may be turned on depending on other config settings.
# options should go to modules.

{
  assertions = [
    {
      assertion = config.system.replaceRuntimeDependencies == [];
      message = "system.replaceRuntimeDependencies causes hydra to build the system at evaluation time. It must be removed!";
    }
    {
      assertion = lib.versions.major pkgs.ceph.version != 16;
      message = "Please pin ceph to major version 16!";
    }
    {
      assertion = lib.versions.majorMinor pkgs.mediawiki.version != 1.39;
      # https://www.mediawiki.org/wiki/Version_lifecycle
      message = "Please keep mediawiki on LTS versions which is required by the LDAP extension";
    }
  ];

  boot = {
    cleanTmpDir = true;
    kernel.sysctl = {
      "net.ipv4.tcp_congestion_control" = "bbr";
    };
    # recommend to turn off, only on by default for backwards compatibility
    zfs.forceImportRoot = false;
  };

  c3d2 = {
    addBinaryCache = true;
    addKnownHosts = true;
    sshKeys = ssh-public-keys;
  };

  documentation.nixos.enable = false;

  environment = {
    gnome.excludePackages = with pkgs; with gnome; [
      baobab
      cheese
      epiphany # we are using firefox or chromium and requires second webkitgtk
      gnome-calendar
      gnome-contacts
      gnome-maps
      gnome-music
      gnome-photos
      gnome-weather
      orca
      simple-scan
      totem
      yelp # less webkitgtk's
    ];
    noXlibs = !config.services.xserver.enable;
    systemPackages = with pkgs; [
      bmon
      curl
      dig
      ethtool
      fd
      git
      htop
      iotop
      mtr
      pv
      ripgrep
      screen
      tcpdump
      tree
      vim
      wget
    ];
  };

  hardware.enableRedistributableFirmware = lib.mkDefault true;

  i18n = {
    defaultLocale = "en_US.UTF-8";
    supportedLocales = [
      "en_US.UTF-8/UTF-8"
      "de_DE.UTF-8/UTF-8"
    ];
  };

  nix = {
    deleteChannels = true;
    deleteUserProfiles = true;
    gc = {
      automatic = lib.mkDefault true;
      dates = "06:00";
      options = "--delete-older-than 21d";
      randomizedDelaySec = "6h";
    };
    nixPath = [
      "nixpkgs=${builtins.unsafeDiscardStringContext nixos}"
      "nixos=${builtins.unsafeDiscardStringContext nixos}"
      "nixos-config=/you/shall/deploy/from/the/flake"
    ];
    registry.nixpkgs.flake = nixos;
    settings = {
      builders-use-substitutes = true; # TODO: move
      connect-timeout = 20;
      experimental-features = "nix-command flakes";
      fallback = true;
      trusted-public-keys = [
        "nix-cache.hq.c3d2.de:KZRGGnwOYzys6pxgM8jlur36RmkJQ/y8y62e52fj1ps="
      ];
      # don't self feed hydra
      substituters = lib.mkIf (config.networking.hostName != "hydra") (
        lib.mkBefore [ "https://nix-cache.hq.c3d2.de" ]
      );
    };
  };

  nixpkgs.config.allowUnfreePredicate = pkg: builtins.elem (pkgs.lib.getName pkg) [
    "drone.io"
    "drone-runner-ssh"
    "elasticsearch" # mastodon
    "factorio-headless"
  ];

  # trust sandro to set good defaults in nixos-modules
  opinionatedDefaults = true;

  programs = {
    fzf.keybindings = true;

    git = {
      enable = true;
      # silence hints in various programs like drone
      config.init.defaultBranch = "master";
    };

    tmux = {
      enable = true;
      historyLimit = 50000;
      extraConfig = ''
        # mouse control
        set -g mouse on

        # don't clear selection on copy
        bind-key -Tcopy-mode-vi MouseDragEnd1Pane send -X copy-selection-no-clear
        bind-key -Tcopy-mode-vi y send -X copy-selection-no-clear
      '';
    };

    vim.defaultEditor = true;
  };

  security.ldap.domainComponent = [ "c3d2" "de" ];

  services = {
    gnome = {
      # less webkitgtk's
      evolution-data-server.enable = lib.mkForce false;
      gnome-initial-setup.enable = false;
    };

    nginx = {
      appendHttpConfig = ''
        log_format proxyCombined '$proxy_protocol_addr - $remote_user [$time_local] '
                                 '"$request" $status $body_bytes_sent '
                                 '"$http_referer" "$http_user_agent"';

        access_log /var/log/nginx/access.log proxyCombined;
      '';
      commonServerConfig = with zentralwerk.lib.config.site.net.serv; ''
        # https://docs.nginx.com/nginx/admin-guide/load-balancer/using-proxy-protocol/
        set_real_ip_from ${hosts4.public-access-proxy};
        set_real_ip_from ${hosts6.up4.public-access-proxy};

        real_ip_header proxy_protocol;

        proxy_set_header X-Real-IP       $proxy_protocol_addr;
        proxy_set_header X-Forwarded-For $proxy_protocol_addr;
      '';
    };

    openssh = {
      # Required for deployment and sops
      enable = true;
      passwordAuthentication = lib.mkIf (!config.c3d2.k-ot.enable) false;
      permitRootLogin = lib.mkOverride 900 "prohibit-password";
    };

    portunus = with zentralwerk.lib.config.site.net.serv; {
      domain = "auth.c3d2.de";
      internalIp4 = hosts4.auth;
      internalIp6 = hosts6.up4.auth;
      ldapPreset = true;
    };

    postgresql.upgrade = {
      extraArgs = [ "--link" ]
        ++ lib.optional (config ? microvm) "--jobs=${toString config.microvm.vcpu}";
      newPackage = pkgs.postgresql_15;
      stopServices = lib.optional config.services.nginx.enable "nginx"
        ++ lib.optional config.c3d2.hq.statistics.enable "collectd";
    };
  };

  security.acme = {
    acceptTerms = true;
    defaults = {
      email = "mail@c3d2.de";
      # letsencrypt staging server with way higher rate limits
      # server = "https://acme-staging-v02.api.letsencrypt.org/directory";
    };
  };

  # does not suceed on installation which is okay
  system.activationScripts.deleteOldSystemProfiles = lib.mkIf config.nix.gc.automatic ''
    echo "Deleting old system profiles..."
    ${config.nix.package}/bin/nix-env --profile /nix/var/nix/profiles/system --delete-generations +10 || true
  '';

  systemd = {
    services.nix-daemon.serviceConfig.KillMode = "control-group";

    # Reboot on hang
    watchdog = lib.mkIf (!config.boot.isContainer) {
      runtimeTime = "15s";
      rebootTime = "15s";
    };
  };

  time.timeZone = lib.mkDefault "Europe/Berlin";

  users.motd = builtins.readFile ./motd;

  zramSwap.enable = true;
}
