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

{
  imports =
    [
      ./hardware-configuration.nix
      ../common/configuration.nix
    ];

  hardware = {
    cpu.intel.updateMicrocode = true;
    enableAllFirmware = true;

    opengl = {
      enable = true;
      driSupport = true;
      extraPackages = with pkgs; [
        intel-media-driver
        vaapiIntel
        vaapiVdpau
        libvdpau-va-gl
        intel-compute-runtime
      ];
    };
  };

  boot = {
    kernelModules = [ "coretemp" "nct6775" ];

    extraModprobeConfig = ''
      options qla2xxx qlini_mode="disabled"
      options zfs l2arc_rebuild_enabled=1
    '';

    loader = {
      systemd-boot.enable = true;
      efi.canTouchEfiVariables = true;
    };

    kernel.sysctl = {
      "fs.inotify.max_user_watches" = 204800;
    };

    supportedFilesystems = [ "zfs" ];
    zfs.extraPools = [ "docs_12t_z1" ];
  };

  networking = {
    useDHCP = false;
    interfaces.eno1.useDHCP = true;

    interfaces.enp1s0.useDHCP = false;
    interfaces.enp1s0.ipv4.addresses = [{
      address = "10.2.0.2";
      prefixLength = 24;
    }];

    hostName = "nas";
    hostId = "c9e40f42";

    nat = {
      enable = true;
      externalInterface = "enp1s0";
      internalInterfaces = [ "wg0" ];
    };

    firewall = {
      enable = true;

      allowedTCPPorts = [
        22      # ssh
        80      # http
        139     # smb
        443     # https
        445     # smb
        8096    # jellyfin
        9091    # transmission webui
        19999   # netdata
        22000   # syncthing sync
        51415   # transmission
        51820   # wireguard
      ];

      allowedUDPPorts = [
        21027   # syncthing discovery
        22000   # syncthing sync
        51415   # transmission
        51820   # wireguard
      ];
    };

    wireguard.interfaces.wg0 = {
      ips = [ "10.100.0.1/32" ];
      listenPort = 51820;
      privateKeyFile = "/home/sijmen/wireguard-keys/private";

      postSetup = ''
        ${pkgs.iptables}/bin/iptables -t nat -A POSTROUTING -s 10.100.0.0/24 -o eth0 -j MASQUERADE
      '';

      postShutdown = ''
        ${pkgs.iptables}/bin/iptables -t nat -D POSTROUTING -s 10.100.0.0/24 -o eth0 -j MASQUERADE
      '';

      peers = [
        {
          # thinkpad
          publicKey = "Y2X8mT+LCXkjLjzRBcdglIKLYu68kvf5K0nKTEOWdGE=";
          allowedIPs = [ "10.100.0.2/32" ];
        }

        {
          # framework
          publicKey = "csvOi6DK6b9zh0JCGIe8z25ePmayY7Hihm5Ur2/aIyo=";
          allowedIPs = [ "10.100.0.4/32" ];
        }
      ];
    };
  };

  i18n.defaultLocale = "en_US.UTF-8";

  users.users.sijmen = {
    isNormalUser = true;
    extraGroups = [ "wheel" "nextcloud" ];
  };

  nixpkgs.config.allowUnfree = true;

  programs.msmtp = {
    enable = true;
    setSendmail = true;
    accounts = {
      default = {
        auth = true;
        tls = true;
        port = 587;
        host = "smtp.soverin.net";
        user = "me@sijmenschoon.nl";
        passwordeval = "pass show email/personal-nas";
      };
    };
  };

  security.acme = {
    acceptTerms = true;
    defaults.email = "me@sijmenschoon.nl";
  };

  services.jellyfin.enable = true;
  services.thermald.enable = true;

  services.nginx = {
    enable = true;

    # Use recommended settings
    recommendedGzipSettings = true;
    recommendedOptimisation = true;
    recommendedProxySettings = true;
    recommendedTlsSettings = true;

    # Only allow PFS-enabled ciphers with AES256
    sslCiphers = "AES256+EECDH:AES256+EDH:!aNULL";

    clientMaxBodySize = "1000G";

    # Setup Nextcloud virtual host to listen on ports
    virtualHosts = {
      "cloud.sijmenschoon.nl" = {
        forceSSL = true;
        enableACME = true;
        extraConfig = ''
          proxy_read_timeout 600;
          proxy_connect_timeout 60;
          proxy_send_timeout 600;
        '';
      };
    };
  };

  services.redis.servers."".enable = true;

  services.nextcloud = {
    enable = true;
    hostName = "cloud.sijmenschoon.nl";
    https = true;
    autoUpdateApps.enable = true;
    autoUpdateApps.startAt = "05:00:00";
    maxUploadSize = "1000G";
    package = pkgs.nextcloud24;

    caching = {
      redis = true;
    };

    config = {
      overwriteProtocol = "https";

      # Nextcloud PostegreSQL database configuration, recommended over using SQLite
      dbtype = "pgsql";
      dbuser = "nextcloud";
      dbhost = "/run/postgresql"; # nextcloud will add /.s.PGSQL.5432 by itself
      dbname = "nextcloud";
      dbpassFile = "/var/nextcloud-db-pass";

      adminpassFile = "/var/nextcloud-admin-pass";
      adminuser = "admin";

      extraTrustedDomains = [
        "cloud.sijman.nl"
        "192.168.1.123"
      ];
      defaultPhoneRegion = "NL";
    };
  };

  services.postgresql = {
    enable = true;
    ensureDatabases = [ "nextcloud" ];
    ensureUsers = [
      {
        name = "nextcloud";
        ensurePermissions."DATABASE nextcloud" = "ALL PRIVILEGES";
      }
      {
        name = "netdata";
        ensurePermissions."DATABASE nextcloud" = "ALL PRIVILEGES";
      }
    ];

    settings = {
      shared_buffers = "8192MB";
    };
  };

  services.fwupd.enable = true;

  services.netdata = {
    enable = true;
    python.extraPackages = ps: [
      ps.psycopg2
    ];
  };

  services.smartd = {
    enable = true;
    extraOptions = [
      "-A /var/log/smartd/"
      "-i 600"
    ];
    notifications.mail = {
      enable = true;
      sender = "nas@sijman.nl";
      recipient = "nas@sijman.nl";
      mailer = "/run/current-system/sw/bin/msmtp --read-envelope-from -t";
    };
  };

  services.nfs.server = {
    enable = true;
    exports = ''
      /mnt/docs   192.168.0.0/24(rw,sync)
      /mnt/backup 192.168.0.0/24(rw,sync)
    '';
  };

  services.samba = {
    enable = true;
    securityType = "user";
    extraConfig = ''
      workgroup = WORKGROUP
      server string = nas
      netbios name = nas
      security = user
      hosts allow = 192.168.1.0/24, 10.2.0.0/24, 10.100.0.0/24
      guest account = nobody

      client min protocol = SMB3
      client max protocol = SMB3
      restrict anonymous = 2
      encrypt passwords = true
    '';

    shares = {
      docs = {
        path = "/mnt/docs";
        "valid users" = "@nextcloud";
        "force user" = "nextcloud";
        "force group" = "+nextcloud";

        public = "no";
        browseable = "yes";
        writable = "yes";

        "read only" = "no";

        "create mask" = "0664";
        "directory mask" = "2775";
        "force create mode" = "0664";
        "force directory mode" = "2775";
      };

      backup = {
        path = "/mnt/backup";
        "valid users" = "sijmen";
        "force user" = "nextcloud";
        "force group" = "+nextcloud";

        public = "no";
        browseable = "yes";
        writable = "yes";

        "read only" = "no";

        "create mask" = "0644";
        "directory mask" = "2755";
        "force create mode" = "0644";
        "force directory mode" = "2755";
      };
    };
  };

  services.borgmatic = {
    enable = true;
    settings = {
      location.repositories = [ "/mnt/backup/borg" ];
      location.source_directories = [ "/mnt/docs" ];
      location.patterns = [ "- /mnt/docs/fileio.bin" ];
      retention.keep_daily = 7;
      retention.keep_weekly = 4;
      retention.keep_monthly = 3;
    };
  };

  services.syncthing = {
    dataDir = "/mnt/docs/users/sijmen";
    configDir = "/home/sijmen/.config/syncthing";
    guiAddress = "0.0.0.0:8384";
  };

  services.transmission = {
    enable = true;

    user = "nextcloud";  # TODO make this its own user maybe
    group = "nextcloud";

    settings = {
      peer-port = 51415;
      download-dir = "/mnt/docs/media/Downloads";
      rpc-bind-address = "0.0.0.0";
      rpc-whitelist-enabled = false;
    };
  };

  systemd = {
    services.jellyfin.serviceConfig.PrivateDevices = lib.mkForce false;

    services."nextcloud-setup" = {
      requires = ["postgresql.service"];
      after = ["postgresql.service"];
    };

    services."set-smr-timeout" = {
      description = "Set command timeout for SMR drives to 180 seconds";
      wantedBy = [ "multi-user.target" ];
      after = [ "mnt-backup.mount" ];
      serviceConfig = {
        Type = "oneshot";
        RemainAfterExit = true;
        ExecStart = "${pkgs.stdenv.shell} -c 'echo 180 > /sys/block/$(basename $(readlink -f /dev/disk/by-id/ata-ST2000DM008-2FR102_WFL3W3SZ))/device/timeout'";
      };
    };

    timers.backup = {
      wantedBy = [ "timers.target" ];
      partOf = [ "backup.service" ];
      timerConfig.OnCalendar = "daily";
    };

    services.backup = {
      serviceConfig.Type = "oneshot";
      path = [ pkgs.mount pkgs.umount pkgs.borgmatic pkgs.hdparm ];
      script = ''
        mount /mnt/backup
        borgmatic --verbosity 1 --files
        umount /mnt/backup
        sync
        hdparm -y /dev/disk/by-id/{ata-WDC_WD10EARS-00MVWB0_WD-WCAZA0318253,ata-WDC_WD10EARS-00MVWB0_WD-WCAZA0338594,ata-ST2000VN004-2E4164_Z522Z7XT,ata-ST2000DM008-2FR102_WFL3W3SZ,ata-WDC_WD10EZEX-22RKKA0_WD-WCC1S3934917,ata-SAMSUNG_HD103SJ_S246J9BZC23280}
      '';
    };
  };

  system.stateVersion = "21.05";
}