{ pkgs, lib, config, inputs, hostName, ... }:
let
  domain = "sourcephile.fr";
  port = toString config.services.nebula.networks.${domain}.listen.port;
  iface = config.services.nebula.networks.${domain}.tun.device;
  IPv4Prefix = "10.0.0";
in
{
  environment.systemPackages = with pkgs; [ nebula ];
  systemd.services."nebula@${domain}" = {
    reloadIfChanged = false;
    stopIfChanged = false;
    serviceConfig.LoadCredentialEncrypted = [
      "${hostName}.key:${builtins.path { path = inputs.self + "/hosts/${hostName}/nebula/${domain}/${hostName}.key.cred"; }}"
    ];
  };
  install.target = lib.mkDefault "\"\${NIXOS_TARGET:-root@${config.networking.hostName}.sp}\"";
  networking.hosts = {
    "${IPv4Prefix}.1" = [ "mermet.sp" ];
    "${IPv4Prefix}.2" = [ "losurdo.sp" ];
    "${IPv4Prefix}.3" = [ "oignon.sp" ];
    "${IPv4Prefix}.4" = [ "patate.sp" ];
    "${IPv4Prefix}.5" = [ "carotte.sp" ];
    "${IPv4Prefix}.6" = [ "aubergine.sp" ];
    "${IPv4Prefix}.7" = [ "courge.sp" ];
    "${IPv4Prefix}.8" = [ "blackberry.sp" ];
    "${IPv4Prefix}.9" = [ "pumpkin.sp" ];
  };
  services.nebula.networks.${domain} = {
    enable = true;
    ca = lib.mkDefault (builtins.path { path = inputs.self + "/domains/${domain}/nebula/ca.crt"; });
    cert = lib.mkDefault (builtins.path { path = inputs.self + "/hosts/${hostName}/nebula/${domain}/${hostName}.crt"; });
    key = "/run/credentials/nebula@${domain}.service/${hostName}.key";
    listen.host = lib.mkDefault "0.0.0.0";
    tun.device = lib.mkDefault "neb-sourcephile";
    staticHostMap = {
      "${IPv4Prefix}.1" = [ "mermet.${domain}:10001" ];
      "${IPv4Prefix}.2" = [ "losurdo.${domain}:10002" ];
    };
    lighthouses = [
      "${IPv4Prefix}.1"
      "${IPv4Prefix}.2"
    ];
    relays = [
      "${IPv4Prefix}.1"
    ];
    firewall = {
      inbound = [
        { port = "any"; proto = "icmp"; groups = [ "sourcephile" "intra" ]; }
      ];
      outbound = [
        { port = "any"; proto = "icmp"; groups = [ "sourcephile" "intra" ]; }
      ];
    };
    settings = {
      firewall = {
        conntrack = {
          tcp_timeout = "12m";
          udp_timeout = "3m";
          default_timeout = "10m";
        };
      };
      logging = {
        level = lib.mkDefault "info";
      };
      pki.disconnect_invalid = true;
      preferred_ranges = [
        "192.168.0.0/16"
      ];
      #cipher = "chachapoly";
      /*
      stats = {
        type = "prometheus";
        listen = "127.0.0.1:8080";
        path = "/metrics";
        namespace = "prometheusns";
        subsystem = "nebula";
        interval = "10s";
        message_metrics = false;
        lighthouse_metrics = false;
      };
      */
    };
  };
  networking.nftables.ruleset = ''
    table inet filter {
      chain input-lan {
        udp dport ${port} counter accept comment "Nebula ${domain}"
      }
      chain output-lan {
        udp sport ${port} counter accept comment "Nebula ${domain}"
      }
      chain input-net {
        udp dport ${port} counter accept comment "Nebula ${domain}"
      }
      chain output-net {
        udp sport ${port} counter accept comment "Nebula ${domain}"
      }
      chain input-${iface} {
        tcp dport ssh counter accept comment "SSH"
        udp dport 60000-60100 counter accept comment "Mosh"
      }
      chain output-${iface} {
        tcp dport ssh counter accept comment "SSH"
        udp dport 60000-60100 counter accept comment "Mosh"
      }
      chain input {
        iifname ${iface} jump input-${iface} comment "MUST be before the address-based jumps to input-lan"
        iifname ${iface} log level warn prefix "input-${iface}: " counter drop
      }
      chain output {
        oifname ${iface} jump output-${iface}
        oifname ${iface} log level warn prefix "output-${iface}: " counter drop
      }
    }
  '' + lib.optionalString config.services.printing.enable ''
    table inet filter {
      chain output-${iface} {
        tcp dport { ipp, ipps } counter accept comment "printing: IPP"
      }
    }
  '' + lib.optionalString config.hardware.sane.enable ''
    table inet filter {
      chain output-${iface} {
        tcp dport sane-port counter accept comment "sane-net: SANE"
      }
    }
  '';
  networking.networkmanager.unmanaged = [ iface ];
  services.fail2ban.ignoreIP = [
    "${IPv4Prefix}.1" # mermet.sp
    "${IPv4Prefix}.2" # losurdo.sp
    "${IPv4Prefix}.3" # oignon.sp
    "${IPv4Prefix}.9" # pumpkin.sp
  ];
}