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

let
  ghcCompiler = (import ../Bild/Constants.nix).ghcCompiler;
  ports = import ../Cloud/Ports.nix;
in {
  # Use the systemd-boot EFI boot loader.
  boot.loader.systemd-boot.enable = true;
  boot.loader.efi.canTouchEfiVariables = true;
  boot.enableContainers = true;

  powerManagement.enable = false;

  time.timeZone = "America/New_York";

  fonts.fonts = with pkgs; [
    google-fonts mononoki source-code-pro fantasque-sans-mono hack-font
    fira fira-code fira-code-symbols
  ];

  environment.systemPackages = [
    pkgs.nvtop #
    pkgs.k3s
    pkgs.wemux
    pkgs.tmux
    pkgs.wireguard-tools
  ];

  nixpkgs = {
    config = {
      allowUnfree = true;
      allowBroken = true;
    };
  };

  hardware = {
    opengl.enable = true;
    pulseaudio = {
      enable = true;
      extraConfig = ''
        load-module module-loopback
      '';
    };
  };

  #hardware.nvidia.nvidiaPersistenced = true;

  programs.bash.enableCompletion = true;
  programs.command-not-found.enable = true;
  programs.gnupg.agent.enable = true;
  programs.gnupg.agent.enableSSHSupport = true;
  programs.mosh.enable = true;

  virtualisation.docker.enable = true;
  virtualisation.docker.liveRestore = false;
  virtualisation.libvirtd.enable = false;
  virtualisation.virtualbox.host.enable = false;
  virtualisation.virtualbox.host.headless = false;
  virtualisation.virtualbox.host.addNetworkInterface = false;
  virtualisation.virtualbox.guest.enable = false;
  virtualisation.virtualbox.guest.x11 = false;

  services.my-hoogle.enable = true;
  services.my-hoogle.port = ports.hoogle;
  services.my-hoogle.home = "//hoogle.simatime.com";
  services.my-hoogle.packages = pkgset: lib.attrsets.attrVals (import ../Bild/Deps/Haskell.nix) pkgset;
  services.my-hoogle.haskellPackages = pkgs.haskell.packages.${ghcCompiler};
  services.my-hoogle.host = "0.0.0.0";

  services.eternal-terminal.enable = true;

  services.k3s.enable = false;
  services.k3s.role = "server";

  services.syncthing.enable = true;
  services.syncthing.guiAddress = "127.0.0.1:${toString ports.syncthing-gui}";
  services.syncthing.openDefaultPorts = true;
  services.syncthing.systemService = true;

  services.tor.enable = true;
  services.tor.client.enable = true;
  services.tor.relay.role = "bridge";
  services.tor.settings.ORPort = ports.tor;
  services.tor.settings.Nickname = "ydeee3q1cjo83tsuqcz";
  services.tor.settings.AccountingMax = "10 GBytes";
  services.tor.settings.AccountingStart = "month 1 1:00";
  services.tor.settings.ContactInfo = "ContactInfo pgp:66A6AD150399D970DCA4C4E6C8218B7D0BFDECCD ciissversion:2";

  services.bitcoind.mainnet.enable = true;
  services.bitcoind.mainnet.dataDir = "/mnt/campbell/bitcoind-mainnet/data";
  services.bitcoind.mainnet.configFile = "/mnt/campbell/bitcoind-mainnet/bitcoin.conf";
  services.bitcoind.mainnet.prune = 10000;

  services.pcscd.enable = true;
  services.logind.lidSwitch = "ignore";
  services.logind.extraConfig = "IdleAction=ignore";

  services.deluge.enable = true;
  services.deluge.openFilesLimit = 10240;
  services.deluge.web.enable = true;

  services.printing.enable = true;

  services.murmur.enable = true;
  services.murmur.registerName = "simatime";
  services.murmur.password = "simatime";
  services.murmur.port = ports.murmur;

  services.xserver.enable = true;
  services.xserver.autorun = true;
  services.xserver.layout = "us";
  services.xserver.xkbOptions = "caps:ctrl_modifier";
  services.xserver.videoDrivers = [ "nvidia" ];
  services.xserver.serverFlagsSection = ''
    Option "BlankTime" "0"
    Option "StandbyTime" "0"
    Option "SuspendTime" "0"
    Option "OffTime" "0"
  '';
  services.xserver.displayManager.sddm.enable = true;
  services.xserver.displayManager.sddm.enableHidpi = true;
  # Some of these have conflicting definitions, which might be the source of my
  # problems with the display. Start here for debugging.
  #services.xserver.displayManager.session.manage = "desktop";
  #services.xserver.displayManager.session.name = "home-manager";
  #services.xserver.displayManager.session.start = ''
  #  ${pkgs.runtimeShell} $HOME/.hm-xsession &
  #  waitPID=$!
  #'';
  #services.xserver.desktopManager.kodi.enable = false;
  #services.xserver.desktopManager.plasma5.enable = false;
  services.xserver.desktopManager.xterm.enable = true;
  services.xserver.windowManager.xmonad.enable = true;
  services.xserver.libinput.enable = true;
  services.xserver.libinput.touchpad.tapping = true;
  services.xserver.modules = [ pkgs.xf86_input_wacom ];
  services.xserver.wacom.enable = true;

  services.jupyter.enable = true;
  services.jupyter.port = ports.jupyter;
  services.jupyter.ip = "*";
  users.users.jupyter.group = "jupyter";
  users.groups.jupyter = {};
  services.jupyter.password = "'argon2:$argon2id$v=19$m=10240,t=10,p=8$nvQhgk+htbIYi961YYAf1w$ekpwiTT5L4+OAods0K7EDw'";
  services.jupyter.kernels.python3 = let
    env = (pkgs.python3.withPackages (p: with p; [
      ipykernel pandas scikitlearn numpy matplotlib sympy ipywidgets
    ]));
  in {
    displayName = "py3";
    argv = [
      "${env.interpreter}"
      "-m"
      "ipykernel_launcher"
      "-f"
      "{connection_file}"
    ];
    language = "python";
    # error: must be of type 'null or path'
    #logo32 = "${env.sitePackages}/ipykernel/resources/logo-32x32.png";
    #logo64 = "${env.sitePackages}/ipykernel/resources/logo-64x64.png";
  };

  # previously emby
  services.jellyfin.enable = true;
  services.jellyfin.user = "jellyfin";
  services.jellyfin.group = "jellyfin";

  services.minidlna.enable = true;
  services.minidlna.settings.notify_interval = 60;
  services.minidlna.settings.friendly_name = "Sima Media";
  services.minidlna.settings.media_dir = [
    "V,/mnt/campbell/ben/youtube"
    "A,/mnt/campbell/ben/music"
    "V,/mnt/campbell/ben/torrents/done"
  ];

  services.vnstat.enable = true;

  documentation.enable = true;
  documentation.dev.enable = true;
  documentation.doc.enable = true;
  documentation.info.enable = true;
  documentation.man.enable = true;
  documentation.nixos.enable = true;

  nix.settings.auto-optimise-store = true;
  nix.settings.cores = 0; # use all available cores
  # Since this is the dev machine, we can turn these on at the expense
  # of extra disk space.
  nix.extraOptions = ''
    keep-outputs = true
    keep-derivations = true
  '';
  # 1 job * 2 cores = 2 maximum cores used at any one time
  nix.settings.max-jobs = 1;
  nix.sshServe.enable = true;
  nix.sshServe.keys = lib.trivial.pipe ../Keys/Ben.pub [
    builtins.readFile
    (lib.strings.splitString "\n")
    (lib.filter (s: s != ""))
  ];
  nix.settings.trusted-users = [ "root" "ben" ];

  # This value determines the NixOS release with which your system is to be
  # compatible, in order to avoid breaking some software such as database
  # servers. You should change this only after NixOS release notes say you
  # should.
  system.stateVersion = "20.09"; # Did you read the comment?

  # TODO: is this still necessary? Check nixpkgs upstream
  users.users.jupyter.isSystemUser = true;
}