{ config, lib, pkgs, ... }:
{
  imports =
    [ # Include the results of the hardware scan.
      ./hardware-configuration.nix
    ];

  nixpkgs.config.allowUnfree = true;

  # Use the systemd-boot EFI boot loader.
  boot.loader.systemd-boot.enable = true;
  boot.loader.efi.canTouchEfiVariables = true;

  networking.hostName = "${hostname}"; # Define your hostname.

  time.timeZone = "Australia/Melbourne";

  # List packages installed in system profile. To search, run:
  # $ nix search wget
  # environment.systemPackages = with pkgs; [
  #   vim # Do not forget to add an editor to edit configuration.nix! The Nano editor is also installed by default.
  #   wget
  # ];

  # Some programs need SUID wrappers, can be configured further or are
  # started in user sessions.
  # programs.mtr.enable = true;
  # programs.gnupg.agent = {
  #   enable = true;
  #   enableSSHSupport = true;
  # };

  # List services that you want to enable:
  services = {
    nomad = {
      enable = true;
      enableDocker = true;
      dropPrivileges = false;
      settings = {
        datacenter = "jaglan-beta";
        server = {
          enabled = true;
%{if bootstrap ~}
          bootstrap_expect = 1;
%{endif ~}
        };
        client = {
          enabled = true;
          preferred_address_family = "ipv4";
%{if cpu_total_compute != null ~}
          cpu_total_compute = ${cpu_total_compute};
%{endif ~}
%{if node_class != null ~}
          node_class = "${node_class}";
%{endif ~}
          host_volume = {
%{ for volume in host_volumes ~}
            ${volume} = {
              path = "/opt/${volume}";
              read_only = false;
            };
%{ endfor ~}
          };
          cni_path = "$${pkgs.cni-plugins}/bin";
        };
        plugin.docker.config.allow_privileged = true;
      };
      extraPackages = with pkgs; [
        cni-plugins
        consul
      ];
    };
    consul = {
      enable = true;
      webUi = true;
      interface.bind = "${bind_interface}";
      interface.advertise = "${bind_interface}";
      forceAddrFamily = "ipv4";
      extraConfig  = {
        client_addr = "{{ GetPrivateInterfaces | exclude \"type\" \"ipv6\" | join \"address\" \" \" }} {{ GetAllInterfaces | include \"flags\" \"loopback\" | join \"address\" \" \" }}";
%{if bootstrap ~}
        bootstrap_expect = 1;
%{endif ~}
        server = true;
        retry_join = [
          "jaglan-beta-m01"
          "jaglan-beta-m02"
          "jaglan-beta-m03"
          "jaglan-beta-m04"
          "jaglan-beta-m05"
          "jaglan-beta-m20"
          "jaglan-beta-m21"
          "jaglan-beta-m22"
        ];
        datacenter = "jaglan-beta";
        connect.enabled = true;
        ports.grpc = 8502;
      };
    };
    openssh = {
      enable = true;
      settings.PermitRootLogin = "yes";
    };
  };

  systemd.tmpfiles.rules = [
    # Fix issue where nomad needs alloc_mounts to be writable
    "d /var/lib/alloc_mounts 0755 root root -"
%{ for volume in host_volumes ~}
    # Create a directory for ${volume} to store its data
    "d /opt/${volume} 0755 root root -"
%{ endfor ~}
  ];

  # Open ports in the firewall. 80/443 are for HTTP/HTTPS (terraform), 464X are the default ports for Nomad, 830X are the default ports for Consul.
  networking.firewall.allowedTCPPorts = [ 80 443 8081 4646 4647 4648 8300 8301 8500 ];
  networking.firewall.allowedUDPPorts = [ 8301 ];

  # Ensure Docker daemon is available (Nomad enableDocker only configures Nomad, does not guarantee docker service)
  virtualisation.docker.enable = true;

%{if node_class == "latte-panda-n150" ~}
  # Enable Intel iGPU (N150 UHD Graphics) for OpenVINO / VA-API workloads running in Docker
  hardware.graphics = {
    enable = true;
    extraPackages = with pkgs; [
      intel-media-driver   # VA-API (iHD)
      intel-compute-runtime # OpenCL / oneAPI
    ];
  };

%{endif ~}
  # Proper systemd service definition for macvlan network creation
  systemd.services.docker-macvlan-network = {
    description = "Ensure macvlan Docker network exists";
    after = [ "network-online.target" "docker.service" ];
    wants = [ "network-online.target" "docker.service" ];
    wantedBy = [ "multi-user.target" ];
    serviceConfig = {
      Type = "oneshot";
    };
    # Provide required binaries in PATH
    path = [ pkgs.docker pkgs.bash pkgs.coreutils pkgs.iproute2 pkgs.gnugrep ];
    script = ''
      set -euo pipefail
      NET_NAME=macvlan
      if docker network inspect "$NET_NAME" >/dev/null 2>&1; then
        echo "Docker network $NET_NAME already exists"
        exit 0
      fi
      echo "Creating Docker macvlan network $NET_NAME on interface ${bind_interface}"
      # We intentionally do NOT use --ip-range here to avoid allocating the
      # same reserved pool on every host (which could lead to collisions if
      # multiple macvlan containers are started across nodes). Instead, we
      # give critical services (like UniFi) an explicit static IP via the
      # Nomad job (Docker static assignment) and rely on manual DHCP
      # reservations to prevent conflicts.
      #
      # If you later need multiple macvlan-assigned containers per host,
      # consider one of these strategies:
      #  1. Per-host distinct network name + ip-range slice (macvlan-m01, ...)
      #  2. Parameterize an ip-range per host in Terraform and template here
      #  3. Keep a registry of allocated static IPs in Consul KV / Nomad vars
      docker network create -d macvlan \
        --subnet=192.168.1.0/24 \
        --gateway=192.168.1.1 \
        -o parent=${bind_interface} \
        "$NET_NAME"
      echo "Docker macvlan network $NET_NAME created"
    '';
    restartIfChanged = false; # Don't rerun just because comment changed
  };

  # Copy the NixOS configuration file and link it from the resulting system
  # (/run/current-system/configuration.nix). This is useful in case you
  # accidentally delete configuration.nix.
  system.copySystemConfiguration = true;
 
  # Defines the initial NixOS version for compatibility with older application data.
  # Do NOT change this value after installation without careful consideration.
  system.stateVersion = "24.11"; # Did you read the comment?
}
