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

let
  ports = import ../Cloud/Ports.nix;
in {
  networking = {
    nameservers = [ "1.1.1.1" "8.8.8.8" ];
    hostName = "lithium";
    hosts = {
      "::1" = [ "localhost" "ipv6-localhost" "ipv6-loopback" ];
    };

    firewall = {
      allowedTCPPorts = [
        22 8000 8443 443 # standard ports
        500 10000 # no idea
        ports.jellyfin
        ports.delugeWeb
        ports.murmur
        ports.mpd
        ports.mpd-stream
        ports.tor
        ports.et
        ports.bitcoind
        ports.jupyter
      ];
      allowedTCPPortRanges = [
        ports.torrents
        ports.httpdev
      ];
      allowedUDPPorts = [ ports.murmur ports.et ];
      allowedUDPPortRanges = [
        ports.torrents
      ];
      checkReversePath = false;
    };

    # The global useDHCP flag is deprecated, therefore explicitly set to false here.
    # Per-interface useDHCP will be mandatory in the future, so this generated config
    # replicates the default behaviour.
    useDHCP = false;
    interfaces.enp1s0.useDHCP = true;
    interfaces.wlp0s20f0u4.useDHCP = true;
  };

  # 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.wemux
    pkgs.tmux
  ];

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

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

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

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

  services = {
    my-hoogle = {
      enable = true;
      port = ports.hoogle;
      home = "//hoogle.simatime.com";
      packages = import ../Bild/Deps/Haskell.nix;
      haskellPackages = pkgs.haskell.packages.ghc884;
      host = "0.0.0.0";
    };

    eternal-terminal = {
      enable = true;
    };
    tor = {
      enable = true;
      client.enable = true;
      relay = {
        enable = true;
        role = "bridge";
        port = ports.tor;
        nickname = "ydeee3q1cjo83tsuqcz";
        accountingMax = "10 GBytes";
        accountingStart = "month 1 1:00";
        contactInfo = "ContactInfo pgp:66A6AD150399D970DCA4C4E6C8218B7D0BFDECCD ciissversion:2";
      };
    };

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

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

    deluge = {
      enable = true;
      openFilesLimit = 10240;
      web.enable = true;
    };

    printing.enable = true;

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

    xserver = {
      enable = true;
      autorun = true;
      layout = "us";
      xkbOptions = "caps:ctrl_modifier";
      serverFlagsSection = ''
        Option "BlankTime" "0"
        Option "StandbyTime" "0"
        Option "SuspendTime" "0"
        Option "OffTime" "0"
      '';
      displayManager = {
        sddm = {
          enable = true;
          enableHidpi = true;
        };
        #startx.enable = true;
        session = [
          {
            manage = "desktop";
            name = "home-manager";
            start = ''
              ${pkgs.runtimeShell} $HOME/.hm-xsession &
              waitPID=$!
            '';
          }
        ];
      };
      desktopManager = {
        #kodi.enable = false;
        #plasma5.enable = false;
        xterm.enable = true;
      };
      windowManager = {
        xmonad.enable = true;
      };
      libinput = {
        enable = true;
        tapping = true;
      };
      modules = [ pkgs.xf86_input_wacom ];
      wacom.enable = true;
    };

    jupyter = {
      enable = true;
      port = ports.jupyter;
      ip = "*";
      password = "'argon2:$argon2id$v=19$m=10240,t=10,p=8$nvQhgk+htbIYi961YYAf1w$ekpwiTT5L4+OAods0K7EDw'";
      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";
        };
      };
    };

    jellyfin = { # previously emby
      enable = true;
      user = "jellyfin";
      group = "jellyfin";
    };

    minidlna = {
      enable = true;
      announceInterval = 60;
      friendlyName = "Sima Media";
      mediaDirs = [
        "V,/mnt/campbell/ben/youtube"
        "A,/mnt/campbell/ben/music"
        "V,/mnt/campbell/ben/torrents/done"
      ];
    };

    vnstat.enable = true;

    postgresql = {
      enable = true;
      package = pkgs.postgresql_10;
      authentication = ''
        local all pprjam md5
        local all pprjam_test md5
      '';
      enableTCPIP = true;
    };
    redis = {
      enable = true;
    };
  };

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

  nix = {
    autoOptimiseStore = true;
    buildCores = 0; # use all available cores
    # Since this is the dev machine, we can turn these on at the expense
    # of extra disk space.
    extraOptions = ''
      keep-outputs = true
      keep-derivations = true
    '';
    # 1 job * 2 cores = 2 maximum cores used at any one time
    maxJobs = 1;
    sshServe = {
      enable = true;
      keys = lib.trivial.pipe ../Keys/Ben.pub [
        builtins.readFile
        (lib.strings.splitString "\n")
        (lib.filter (s: s != ""))
      ];
    };
    trustedUsers = [ "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: upstream this
  users.users.jupyter.isSystemUser = true;
}