# Edit this configuration file to define what should be installed on
# your system.  Help is available in the configuration.nix(5) man page
# and in the NixOS manual (accessible by running ‘nixos-help’).
{
  inputs,
  hostname,
  lib,
  mylib,
  config,
  pkgs,
  ...
}: {
  imports = [
    # Import the host-specific system config
    ./${hostname}

    ./cachix.nix
  ];

  # Enable flakes
  nix = {
    package = pkgs.nixVersions.stable;
    extraOptions = ''
      experimental-features = nix-command flakes
    '';

    settings.trusted-users = ["root" "christoph"];

    # Keep nix-shell from garbage collection for direnv (keep-outputs + keep-derivations)
    # NOTE: nix-direnv use nix or use flake should do this automatically
    # keep-outputs = true
    # keep-derivations = true

    # Auto garbage-collect and optimize store
    gc.automatic = true;
    gc.options = "--delete-older-than 5d";
    settings.auto-optimise-store = true;
    optimise.automatic = true;

    # This will add your inputs as registries, making operations with them (such
    # as nix shell nixpkgs#name) consistent with your flake inputs.
    # (Registry contains flakes)
    registry = lib.mapAttrs' (n: v: lib.nameValuePair n {flake = v;}) inputs;
  };

  # Bootloader/Kernel stuff
  boot = {
    kernelPackages = pkgs.linuxPackages_zen;
    kernelParams = ["mitigations=off"];

    # plymouth.enable = true;
    loader.systemd-boot.enable = true;
    loader.systemd-boot.configurationLimit = 5;
    loader.systemd-boot.editor = false;
    loader.systemd-boot.consoleMode = "max";
    loader.efi.canTouchEfiVariables = true;
    loader.efi.efiSysMountPoint = "/boot/efi";

    # Make /tmp volatile
    tmpOnTmpfs = true;
  };

  security = {
    protectKernelImage = true;
    rtkit.enable = true;
    polkit.enable = true;

    sudo.enable = true;
    sudo.extraRules = [
      {
        users = ["christoph"];
        commands = [
          # Launch gamemode without password because it is annoying
          # {
          #   command = "/etc/profiles/per-user/christoph/bin/gamemoderun";
          #   options = [ "SETENV" "NOPASSWD" ];
          # }
          # {
          #   command = "${pkgs.gamemode}/libexec/cpugovctl";
          #   options = [ "SETENV" "NOPASSWD" ];
          # }

          # We allow running flatpak without password so flatpaks can be installed from the hm config (needs sudo)
          {
            command = "/run/current-system/sw/bin/flatpak";
            options = ["SETENV" "NOPASSWD"];
          }
        ];
      }
    ];
  };

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

  # Select internationalisation properties.
  i18n.defaultLocale = "en_US.UTF-8";

  i18n.extraLocaleSettings = {
    LC_ADDRESS = "de_DE.UTF-8";
    LC_IDENTIFICATION = "de_DE.UTF-8";
    LC_MEASUREMENT = "de_DE.UTF-8";
    LC_MONETARY = "de_DE.UTF-8";
    LC_NAME = "de_DE.UTF-8";
    LC_NUMERIC = "de_DE.UTF-8";
    LC_PAPER = "de_DE.UTF-8";
    LC_TELEPHONE = "de_DE.UTF-8";
    LC_TIME = "de_DE.UTF-8";
  };

  # https://github.com/NixOS/nixpkgs/issues/179486
  i18n.supportedLocales = ["en_US.UTF-8/UTF-8" "de_DE.UTF-8/UTF-8"];

  # TODO: Other ports (tcp/udp/ssh...)?
  # Open ports in the firewall.
  networking = {
    # Gets inherited from flake in nixos mylib
    hostName = hostname; # Define your hostname.

    # wireless.enable = true;  # Enables wireless support via wpa_supplicant.

    # Configure network proxy if necessary
    # proxy.default = "http://user:password@proxy:port/";
    # proxy.noProxy = "127.0.0.1,localhost,internal.domain";

    # Enable networking
    networkmanager.enable = true;

    firewall.enable = true;
    firewall.allowedTCPPorts = [];
    firewall.allowedTCPPortRanges = [];

    firewall.allowedUDPPorts = [
      18000 # Anno 1800
      24727 # AusweisApp2
    ];
    firewall.allowedUDPPortRanges = [];
  };

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

    # Startx replaces the displaymanager so default (lightdm) isn't used, start to shell
    # Sadly using this with gnome-session doesn't really work
    # displayManager.startx.enable = true;

    # Plasma
    # TODO: Had problems with wayland last time, hopefully I get it to work now
    displayManager.sddm.enable = true;
    desktopManager.plasma5.enable = true;
    desktopManager.plasma5.runUsingSystemd = true;

    # Gnome (Wayland)
    # NOTE: Not a fan of the overly simplistic nature, also made problems with the audio devices...
    # displayManager.gdm.enable = true;
    # I had problems with gdm defaulting to X11, after I added this it stopped although I don't know if this
    # was the sole reason
    # displayManager.defaultSession = "gnome";
    # displayManager.gdm.wayland = true; # This is actually the default
    # desktopManager.gnome.enable = true;

    wacom.enable = true;

    # Enable touchpad support (enabled default in most desktopManager).
    libinput.enable = true;
  };

  # XDG
  # NOTE: I think only the fitting portal is required
  xdg.portal = {
    enable = true;
    extraPortals = with pkgs; [
      # xdg-desktop-portal-wlr # For wlroots based desktops
      xdg-desktop-portal-kde # Comes with Plasma
      # xdg-desktop-portal-gtk # Comes with Gnome
      # xdg-desktop-portal-gnome # Comes with Gnome
    ];
    # gtkUsePortal = true; # Deprecated, don't use (gdm takes ages to load and other fishy stuff)
  };

  # Enable sound with pipewire.
  sound.enable = false; # Alsa, seems to conflict with PipeWire
  hardware.pulseaudio.enable = false; # Get off my lawn
  services.pipewire = {
    enable = true;
    alsa.enable = true;
    alsa.support32Bit = true;
    pulse.enable = true;
    jack.enable = false; # TODO: Was needed for low latency but probably not anymore (?) as Bitwig supports Pipewire now

    wireplumber.enable = true; # Probably the default
    media-session.enable = false;
  };

  fonts = {
    enableDefaultFonts = true; # Some default fonts for unicode coverage
    fontDir.enable = true; # Puts fonts to /run/current-system/sw/share/X11/fonts

    # Font packages go here
    # NOTE: Don't do this with HomeManager as I need the fonts in the fontdir for flatpak apps
    fonts = with pkgs; [
      # Mono fonts
      victor-mono
      jetbrains-mono
      source-code-pro
      (pkgs.nerdfonts.override {fonts = ["VictorMono"];})

      # Chinese fonts
      source-han-mono
      source-han-sans
      source-han-serif
      noto-fonts-cjk-sans
      noto-fonts-cjk-serif
      wqy_zenhei
      wqy_microhei

      # Sans/Serif fonts
      cantarell-fonts
      source-sans-pro
      source-serif-pro
      noto-fonts
      noto-fonts-extra
      noto-fonts-emoji

      # Emacs fonts
      emacs-all-the-icons-fonts
      material-design-icons

      # Some fonts from an old emacs config, not longer used
      # etBook
      # overpass
    ];

    # TODO: Check if this works
    # TODO: Conflicts with kde?
    # fontconfig = {
    #   enable = true;
    #   defaultFonts = {
    #     serif = [ "Source Han Serif Regular" ];
    #     sansSerif = [ "Source Han Sans Regular" ];
    #     monospace = [ "Source Han Mono Regular" ];
    #   };
    # };
  };

  # Define a user account. Don't forget to set a password with ‘passwd’.
  users.users.christoph = {
    isNormalUser = true;
    description = "Christoph";
    extraGroups = [
      "networkmanager"
      "wheel"
      "audio"
      "pipewire"
      "realtime"
      "gamemode"
      "docker"
      "adbusers"
      "scanner"
      "lp"
      "libvirtd"
    ];
    shell = pkgs.fish; # TODO: Is this needed if programs.fish.enable = true?
    # We do this with HomeManager
    packages = with pkgs; [];
  };

  # Generate a list of installed system packages in /etc/current-system-packages
  environment.etc."current-system-packages".text = let
    packages = builtins.map (p: "${p.name}") config.environment.systemPackages;
    sortedUnique = builtins.sort builtins.lessThan (lib.unique packages);
    formatted = builtins.concatStringsSep "\n" sortedUnique;
  in
    formatted;

  # We want these packages to be available even when no user profile is active
  # Empty since we basically only need git + editor which is enabled below
  environment.systemPackages = with pkgs; [
    killall
  ];

  # NOTE: Gnome
  # TODO: Identify all the crap
  # Remove these packages that come by default with GNOME
  # environment.gnome.excludePackages = with pkgs.gnome; [
  #   # epiphany # gnome webbrowser, could be good with new version
  #   gnome-maps
  #   gnome-contacts
  # ];

  # NOTE: Plasma
  # TODO: Identify all the crap
  environment.plasma5.excludePackages = with pkgs.libsForQt5; [
  ];

  # It is preferred to use the module (if it exists) over environment.systemPackages, as some extra configs are applied.
  # I would prefer to use HomeManager for some of these but the modules don't exist (yet)
  programs = {
    adb.enable = true;
    dconf.enable = true; # NOTE: Also needed for Plasma Wayland (GTK theming)
    fish.enable = true;
    git.enable = true;
    kdeconnect.enable = true; # Use this instead of HM for firewall setup
    neovim.enable = true;
    starship.enable = true;
    thefuck.enable = true;
    xwayland.enable = true;
  };

  # List services that you want to enable:
  services = {
    # Enable CUPS to print documents.
    # TODO: Printing (driver etc.)
    printing.enable = true;
    avahi.enable = true; # Network printers
    avahi.nssmdns = true;

    # Enable the OpenSSH daemon.
    openssh.enable = true;

    # Trims the journal if too large
    journald.extraConfig = ''
      SystemMaxUse=50M
    '';

    acpid.enable = true;
    dbus.enable = true;
    flatpak.enable = true; # Not quite the nix style but useful for bottles/proprietary stuff/steam/gaming
    fstrim.enable = true; # SSD
    fwupd.enable = true; # Device firmware (I don't think I have any supported devices)
    locate.enable = true; # Periodically update index
    ntp.enable = true; # Clock sync
    packagekit.enable = true; # KDE Discover/Gnome Software
    udev = {
      packages = with pkgs; [
        usb-blaster-udev-rules
      ];
    };

    # TODO: Find a way to organize this better as it's split from the Gnome module, Gnome system module?
    gnome.gnome-keyring.enable = true; # TODO: Is probably also needed for Plasma (some apps require it)
    # gnome.sushi.enable = true;
    # gnome.gnome-settings-daemon.enable = true;
    # gnome.gnome-online-accounts.enable = true; # Probably Gnome enables this
  };

  virtualisation = {
    docker = {
      enable = true;
      autoPrune.enable = true;
    };

    libvirtd.enable = true;

    # NOTE: Pretty unusable as NVidia hardware acceleration is not supported...
    # Follow steps from https://nixos.wiki/wiki/WayDroid
    # waydroid. enable = true;
    # lxd.enable = true;
  };

  # NOTE: Current system was installed on 22.05, do not change
  # This value determines the NixOS release from which the default
  # settings for stateful data, like file locations and database versions
  # on your system were taken. It‘s perfectly fine and recommended to leave
  # this value at the release version of the first install of this system.
  # Before changing this value read the documentation for this option
  # (e.g. man configuration.nix or on https://nixos.org/nixos/options.html).
  system.stateVersion = "22.05"; # Did you read the comment?
}
