{ config, lib, pkgs, timeZone, ... }:
let
  srvConfig = config.serverConfig;
in
{
  options.serverConfig= {
    userName = lib.mkOption {
      type = lib.types.str;
      description = "Main username for system";
    };
    hostName = lib.mkOption {
      type = lib.types.str;
      description = "Hostname for system";
    };
    hostId = lib.mkOption {
      type = lib.types.str;
      description = "Host ID";
    };
    email = lib.mkOption {
      type = lib.types.str;
      description = "Email for server box";
    };
    sshEnable = lib.mkOption {
      default = false;
      description = "Whether to enable ssh server";
    };
    nfsEnable = lib.mkOption {
      default = false;
    };
    nfsRoot = lib.mkOption {
      default = "/nfs_export";
      type = lib.types.str;
    };
    nfsExports = lib.mkOption {
      default = [];
      description = "List of file paths provided as strings to the nfs exports";
    };
    nfsIpExport = lib.mkOption {
      type = lib.types.str;
      description = "Where to export the shares to i.e. 192.168.0.0/24 (export to local network)";
    };
    syncthingEnable = lib.mkOption {
      default = false;
      description = "Whether to enable syncThing host on this machine";
    };
    caldavEnable = lib.mkOption {
      default = false;
      description = "Enable the caldav server service (radicale)";
    };
    printerSharingEnable = lib.mkOption {
      default = false;
      description = "Setups up avahi and printer services to expose local printer to network";
    };
  };

  imports = [
    ./modules/user/main_user.nix
    ./modules/services/dufs.nix
  ];
  
  config = {
    # Enable flakes feature
    nix.settings.experimental-features = [
      "nix-command" "flakes"
    ];

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

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

    time.timeZone = timeZone;
 
    main_user = {
      enable = true;
      userName = srvConfig.userName;
      isDesktopUser = false;
    };

    environment.systemPackages = with pkgs; [
      docker
      docker-compose
      zsh
    ];

    programs.zsh.enable = true;

    services.openssh = lib.mkIf srvConfig.sshEnable {
      enable = true;
    };

    # nfs options breakdown: link for export options https://linux.die.net/man/5/exports
    # rw - default read write
    # sync - wait until requests are saved to disk to respond to clients, safer but slower
    # no_subtree_check - 
    services.nfs.server = lib.mkIf srvConfig.nfsEnable {
      enable = true;
      exports = ''
       ${srvConfig.nfsRoot} ${srvConfig.nfsIpExport}(rw,fsid=root,no_subtree_check)
       ${lib.concatMapStringsSep "\n" (n: "${srvConfig.nfsRoot}${n} ${srvConfig.nfsIpExport}(rw,sync,no_subtree_check,all_squash,anongid=105,anonuid=1005)") srvConfig.nfsExports}
     '';
    };
    # nfs port TODO make dependant on option enabled
    # 2049 - nfs
    # 8384 - syncthing
    # 5352 - caldav server radicale
    networking.firewall.allowedTCPPorts = [ 80 2049 5232 8384 ];

    users.groups.kage = {
      gid = 105;
    };
    users.users.kage = {
      uid = 1005;
      isSystemUser = true;
      initialPassword = "password";
      description = "user to manage nfs and syncthing tasks";
      group = "kage";
      extraGroups = [
        "users"
      ];
    };

    services.syncthing = lib.mkIf srvConfig.syncthingEnable {
      enable = true;
      user = "kage";
      group = "users";
      dataDir = "${srvConfig.nfsRoot}/kage/syncthing";
      configDir = "${srvConfig.nfsRoot}/kage/.config/syncthing";
      # overrideDevices = true;     # overrides any devices added or deleted through the WebUI
      # overrideFolders = true;     # overrides any folders added or deleted through the WebUI
      openDefaultPorts = true;
      relay.enable = true;
      guiAddress = "0.0.0.0:8384";
      # settings = {
      #   devices = {
      #     # "supernote" = { id = "DEVICE-ID-GOES-HERE"; };
      #     # "pixel" = { id = "DEVICE-ID-GOES-HERE2"; };
      #     # "winmax" = { id = "id3"; };
      #     # "nix-box" = { id = "id4"; };
      #   };
      #   folders = {
      #     "supernote" = {         # Name of folder in Syncthing, also the folder ID
      #       path = "${srvConfig.nfsRoot}/kage/syncthing/supernote";    # Which folder to add to Syncthing
      #       # devices = [ "supernote" "pixel" ];      # Which devices to share the folder with
      #     };
      #     "web" = {         # Name of folder in Syncthing, also the folder ID
      #       path = "${srvConfig.nfsRoot}/kage/syncthing/web";    # Which folder to add to Syncthing
      #       # devices = [ "supernote" "pixel" "winmax" "nix-box" ];      # Which devices to share the folder with
      #     };
      #   };
      # };
    };

    services.radicale = lib.mkIf srvConfig.caldavEnable {
      enable = true;
      settings = {
        # Run server port 5232
        server = {
          hosts = [ "0.0.0.0:5232" "[::]:5232" ];
        };
        auth = {
          type = "htpasswd";
          htpasswd_filename = "/var/lib/radicale/users";
          htpasswd_encryption = "bcrypt";
        };
        storage = {
          filesystem_folder = "/var/lib/radicale/collections";
        };
      };
    };

    # DUFS file server configuration
    services.dufs = {
      enable = true;
      openFirewall = true;
      user = "kage";
      group = "users";

      # Public read-only instance
      publicInstance = {
        enable = true;
        port = 5000;
        allowSearch = true;
      };

      # Private read-write instance with authentication
      privateInstance = {
        enable = true;
        port = 5001;
        allowUpload = true;
        allowDelete = true;
        allowSearch = true;
        # Read-write users
        users = [
          # Generate password hash with: mkpasswd -m sha-512
          # These are temporary passwords and should be changed
          {
            username = "nate";
            passwordHash = "$6$eIqVeCL9q5GlN.Em$xm7RxNcGfArYFBprmnggt1zzDf.HluKwXcG9LsJNCK6.vnKGmQDb5b7h7g81tWY7jIDdPsgLu0jiTzbz1lFIC0";  # password
          }
        ];
        # Read-only users
        readonlyUsers = [
          {
            username = "guest";
            passwordHash = "$6$.Ot.4AWNRpx0LJ1s$M01RpAJ.VZWJfDrTlali.P0Fhnn0Ji.uP/fIdgZP0ly64g8AzeGb6/2C9dbKmnARdVV9M12mLmU6ENmUbR/ym1";  # guest
          }
          {
            username = "readonly";
            passwordHash = "$6$3Z5KK8mIbxN2tZR4$eCOpbwAKAk6CKMZWgWddgJaQyTDUkYzB0T8tNXfSUQkUL2A/QEXoEONcPaZnF/jfem9qB..Snm2xR/7GTkyVg.";  # readonly
          }
        ];
      };
    };

    services.avahi = lib.mkIf srvConfig.printerSharingEnable {
      enable = true;
      nssmdns4 = true;
      openFirewall = true;
      publish = {
        enable = true;
        userServices = true;
      };
    };

    services.printing = lib.mkIf srvConfig.printerSharingEnable {
      enable = true;
      drivers = [ pkgs.brlaser ];
      listenAddresses = [ "*:631" ];
      allowFrom = [ "all" ];
      browsing = true;
      # browserAddress = "192.168.1.169:631";
      defaultShared = true;
      openFirewall = true;
    };

    systemd.timers."pixel-backups" = {
      wantedBy = [ "timers.target" ];
        timerConfig = {
          OnCalendar = "daily";
        };
    };

    systemd.services."pixel-backups" = {
      script = ''
        # Move files older than 90 days to the backups file
        find /nfs_export/kage/syncthing/pixel_images/ -type f -mtime +90 | xargs -I {} mv {} /nfs_export/kage/Personal/Nate/Phone_Images
      '';
      serviceConfig = {
        Type = "oneshot";
        User = "root";
      };
    };
    
    # networking.firewall.allowedTCPPorts = [ ... ];
    # networking.firewall.allowedUDPPorts = [ ... ];

    system.stateVersion = "23.11"; # Did you read the comment?
  };
}
