{ config, lib, pkgs, serverCfg }:
let 
  mkRouterName = { subdomain, subpath ? null }:
    if subpath != null
    then "${subdomain}-${lib.strings.sanitizeDerivationName subpath}"
    else subdomain;
  getOr = attrs: path: default: lib.attrByPath path default attrs;
  mkTmpfsOption = size: "--tmpfs=/tmp:rw,noexec,nosuid,size=${size}";
  mkAuthentikLabels =
    { subdomain
    , subpath ? null
    , routerName ? mkRouterName { inherit subdomain subpath; }
    , middleware ? "authentik"
    }:
    lib.optionalAttrs (serverCfg.containers ? authentik) {
      "traefik.http.routers.${routerName}.middlewares" = middleware;
    };
  contBuilder =
    { image ? null, imageStream ? null, imageFile ? null
    , secret ? null
    , subdomain ? null, subpath?null, port ? null
    , authentik ? false
    , tmpfs ? false
    , tmpfsSize ? "512m"
    , extraEnv ? { }, extraLabels ? { }, extraOptions ? [ ]
    , overrides ? { }
    }:
    let 
      routerName = mkRouterName { inherit subdomain subpath; };
      base = {
      image = if imageStream != null then "${imageStream.imageName}:${imageStream.imageTag}" 
              else if imageFile != null then "${imageFile.imageName}:${imageFile.imageTag}" else image;
      imageStream = imageStream;
      imageFile = imageFile;

      environmentFiles = if secret!=null then [ config.sops.secrets."${lib.toUpper secret}".path ] else [];
      environment = {
        TZ = config.time.timeZone;
      } // extraEnv;

      labels = (if subdomain!=null then ({
        "traefik.enable" = "true";
        "traefik.http.routers.${routerName}.entrypoints" = "web-secure";
        "traefik.http.routers.${routerName}.rule" = if subpath != null 
          then "Host(`${subdomain}.${serverCfg.domain}`) && PathPrefix(`/${subpath}`)"
          else "Host(`${subdomain}.${serverCfg.domain}`)";
        "traefik.http.routers.${routerName}.tls" = "true";
      } // lib.optionalAttrs (port!=null) {
        "traefik.http.services.${routerName}.loadbalancer.server.port" = toString port;
      }) else {
        "traefik.enable" = "false";
      })
      // lib.optionalAttrs authentik (mkAuthentikLabels { inherit subdomain subpath routerName; })
      // extraLabels;

      extraOptions = [
        "--add-host=host.containers.internal:host-gateway"
      ]
      ++ lib.optional tmpfs (mkTmpfsOption tmpfsSize)
      ++ extraOptions;
    };
    in lib.recursiveUpdate base overrides;
  vmBuilder = { name, vm }: ((import "${pkgs.path}/nixos/lib/eval-config.nix" {
      system = "x86_64-linux";
      modules = [ vm.cfg
        ({ config, lib, modulesPath, ... }: {
        imports = [
          "${modulesPath}/profiles/qemu-guest.nix"
          "${modulesPath}/virtualisation/qemu-vm.nix"
        ];
        networking.hostName = name;
        networking.useDHCP = true; 
        networking.firewall.enable = false;
        services.qemuGuest.enable = true;
        system.stateVersion = "26.05"; 
        virtualisation = {
          memorySize = vm.memory or 2048;
          cores = vm.cores or 2;
          forwardPorts = let
            parsePortString = port: {
              from = "host";
              host.port = port;
              guest.port = port;
            };
          in if (vm ? portForward && vm.portForward != null) then map parsePortString vm.portForward else [];
        };})
      ];
    }).config.system.build.vm);
in {
  mkContainer = contBuilder;
  mkVm = vmBuilder;
  mkApp = name: app:
    {
      inherit name;
      requires = {
        secrets = getOr app [ "requires" "secrets" ] [ ];
        databases = getOr app [ "requires" "databases" ] [ ];
      };
      exports = {
        authentik = {
          blueprints = getOr app [ "exports" "authentik" "blueprints" ] [ ];
        };
      };
      runtime = {
        paths = getOr app [ "runtime" "paths" ] [ ];
        containers = getOr app [ "runtime" "containers" ] { };
        vm = getOr app [ "runtime" "vm" ] null;
        cron = getOr app [ "runtime" "cron" ] [ ];
        setup = {
          trigger = "";
          script = null;
          envFile = [ ];
        } // getOr app [ "runtime" "setup" ] { };
      };
    };
  mkData = { name, dir, vars?{} }: pkgs.runCommand name vars ''
    mkdir -p $out
    cp -r ${./data + "/${dir}"}/. $out/
    find $out -type f | while read file; do
      ${lib.concatStringsSep "\n" (lib.mapAttrsToList (n: v: ''
        substituteInPlace "$file" --replace "@${n}@" "${toString v}"
      '') vars)}
    done
  '';
  host = "host.containers.internal"; 
  hostIp =  if (config.virtualisation.podman.defaultNetwork.settings ? subnets) 
    then (builtins.elemAt config.virtualisation.podman.defaultNetwork.settings.subnets 0).gateway
    else "10.88.0.1"; 
}
