# channel="nixos-small"
# Edit this configuration file to define what should be installed on
# your system. Help is available in the configuration.nix(5) man page, on
# https://search.nixos.org/options and in the NixOS manual (`nixos-help`).

let
  domains =
    let
      domain = "push-f.com";
    in
    {
      personalWebsite = domain;
      tailscaleControlServer = "tailscale.${domain}";
      gitWebsite = "git.${domain}";
      matrixServer = "matrix.${domain}";
    };
  acmeEmail = "martin@push-f.com";
in
{ config, lib, pkgs, ... }:

{
  imports = [
    ./tente-hardware-configuration.nix
    ./sanix.nix
    ./parts/server.nix
    ./parts/basics.nix
  ];

  # Use the GRUB 2 boot loader.
  boot.loader.grub.enable = true;
  # boot.loader.grub.efiSupport = true;
  # boot.loader.grub.efiInstallAsRemovable = true;
  # boot.loader.efi.efiSysMountPoint = "/boot/efi";
  # Define on which hard drive you want to install Grub.
  boot.loader.grub.device = "/dev/sda"; # or "nodev" for efi only

  networking.hostName = "tente"; # Define your hostname.
  # Pick only one of the below networking options.
  # networking.wireless.enable = true;  # Enables wireless support via wpa_supplicant.
  networking.networkmanager.enable = true;  # Easiest to use and most distros use this by default.

  # Set your time zone.
  time.timeZone = "Europe/Vienna";

  # Select internationalisation properties.
  # i18n.defaultLocale = "en_US.UTF-8";
  # console = {
  #   font = "Lat2-Terminus16";
  #   keyMap = "us";
  #   useXkbConfig = true; # use xkb.options in tty.
  # };

  # Enable the X11 windowing system.
  # services.xserver.enable = true;

  users.users.martin = {
    isNormalUser = true;
    extraGroups = [
      "wheel" # Enable ‘sudo’ for the user.
      "www-data"
    ];
    packages = with pkgs; [
    ];
  };

  # List packages installed in system profile. To search, run:
  # $ nix search wget
   environment.systemPackages = with pkgs; [
     vim # Do not forget to add an editor to edit configuration.nix! The Nano editor is also installed by default.
     wget
   ];

  # Some programs need SUID wrappers, can be configured further or are
  # started in user sessions.
  # programs.mtr.enable = true;
  # programs.gnupg.agent = {
  #   enable = true;
  #   enableSSHSupport = true;
  # };

  # Open ports in the firewall.
  networking.firewall.allowedTCPPorts = [
    # Enabling openssh automatically opens its port in the firewall.
    # For all other services we need to manually list the ports here.
    80 443
  ];
  networking.firewall.allowedUDPPorts = [];

  users.groups.www-data = {};

  systemd.tmpfiles.rules = [
    "d /srv/www 2770 root www-data -"
  ];

  services = {
    gitolite = {
      enable = true;
      adminPubkey = ""; # TODO: submit PR to nixpkgs to make this option optional
      user = "git";
      group = "git";
      dataDir = "/srv/gitolite";
      extraGitoliteRc = ''
        $RC{UMASK} = 0027;
        $RC{GIT_CONFIG_KEYS} = 'cgit.* gitweb.*';

        # not working for some reason? still getting `FATAL: git config 'gitweb.description' not allowed` if gitweb.* is omitted in GIT_CONFIG_KEYS
        # push( @{$RC{ENABLE}}, 'cgit' ); # update description files instead of gitweb.description config
      '';
    };

    nginx = {
      enable = true;
      group = "www-data";
    };

    headscale = {
      enable = true;
      port = 8080;
      # TODO: make dataDir configurable and set it to /srv/
      settings = {
        server_url = "https://${domains.tailscaleControlServer}";
        dns = { base_domain = "tailnet"; };
      };
    };

    nginx.virtualHosts.${domains.tailscaleControlServer} = {
      enableACME = true;
      forceSSL = true;
      locations."/" = {
        proxyPass = "http://localhost:${toString config.services.headscale.port}";
        proxyWebsockets = true;
      };
    };

    postgresql = {
      enable = true;
      authentication = pkgs.lib.mkOverride 10 ''
        #type database  DBuser  auth-method
        local sameuser  all     peer
      '';
    };

    matrix-synapse = {
      enable = true;
      settings = {
        server_name = domains.personalWebsite;
      };
    };

    nginx.virtualHosts.${domains.matrixServer} = {
      enableACME = true;
      forceSSL = true;

      # TODO: add locations."/" with some message

      # Forward all Matrix API calls to the synapse Matrix homeserver. A trailing slash
      # *must not* be used here.
      locations."/_matrix".proxyPass = "http://127.0.0.1:8008";
      # Forward requests for e.g. SSO and password-resets.
      locations."/_synapse/client".proxyPass = "http://127.0.0.1:8008";
    };

    nginx.virtualHosts.${domains.personalWebsite} =
      let
        mkWellKnown = data: ''
          default_type application/json;
          add_header Access-Control-Allow-Origin *;
          return 200 '${builtins.toJSON data}';
        '';
      in
      {
        enableACME = true;
        forceSSL = true;
        root = "/srv/www/${domains.personalWebsite}";

        locations."= /.well-known/matrix/server".extraConfig = mkWellKnown {
          "m.server" = "${domains.matrixServer}:443";
        };
        locations."= /.well-known/matrix/client".extraConfig = mkWellKnown {
          "m.homeserver" = { base_url = "https://${domains.matrixServer}"; };
        };
      };

    nginx.virtualHosts.${domains.gitWebsite} = {
      enableACME = true;
      forceSSL = true;
    };

    cgit.main = {
      enable = true;
      # running as the gitolite user because otherwise cloning a repo via cgit fails with:
      #   fatal: detected dubious ownership in repository
      user = config.services.gitolite.user;
      group = config.services.gitolite.group;
      nginx.virtualHost = domains.gitWebsite;
      scanPath = "${config.services.gitolite.dataDir}/repositories";
      settings = {
        remove-suffix = 1;
        enable-git-config = 1;
        root-title = "push-f.com repositories";
        root-desc = "My various repositories.";
        enable-index-owner = 0;
        source-filter = "${pkgs.cgit}/lib/cgit/filters/syntax-highlighting.py";
        clone-prefix = "https://${domains.gitWebsite}";
      };
    };
  };

  security.acme = {
    acceptTerms = true; # https://letsencrypt.org/repository/
    defaults.email = acmeEmail;
  };

  # Copy the NixOS configuration file and link it from the resulting system
  # (/run/current-system/configuration.nix). This is useful in case you
  # accidentally delete configuration.nix.
  # system.copySystemConfiguration = true;

  # This option defines the first version of NixOS you have installed on this particular machine,
  # and is used to maintain compatibility with application data (e.g. databases) created on older NixOS versions.
  #
  # Most users should NEVER change this value after the initial install, for any reason,
  # even if you've upgraded your system to a new NixOS release.
  #
  # This value does NOT affect the Nixpkgs version your packages and OS are pulled from,
  # so changing it will NOT upgrade your system - see https://nixos.org/manual/nixos/stable/#sec-upgrading for how
  # to actually do that.
  #
  # This value being lower than the current NixOS release does NOT mean your system is
  # out of date, out of support, or vulnerable.
  #
  # Do NOT change this value unless you have manually inspected all the changes it would make to your configuration,
  # and migrated your data accordingly.
  #
  # For more information, see `man configuration.nix` or https://nixos.org/manual/nixos/stable/options#opt-system.stateVersion .
  system.stateVersion = "24.11"; # Did you read the comment?

}