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

let
  cfg = config.services.every-channel.netboot;
  scriptsRoot = ../..;

  boolString = v: if v then "true" else "false";

  mkExport = name: value: "export ${name}=${lib.escapeShellArg value}";

  optionalExport = name: value:
    if value == null then "" else mkExport name value;

  optionalFileExport = name: path:
    if path == null then ""
    else ''
      if [[ ! -r ${lib.escapeShellArg path} ]]; then
        echo "error: required file is not readable: ${path}" >&2
        exit 2
      fi
      export ${name}="$(tr -d '\\r\\n' < ${lib.escapeShellArg path})"
    '';

  stageToolchain = with pkgs; [
    bash
    coreutils
    curl
    gawk
    gnugrep
    gnused
    gnutar
    gzip
    python3
  ];

  ipxeToolchain = with pkgs; [
    git
    gnumake
    gcc
    binutils
    perl
    mtools
    docker-client
  ];
in
{
  options.services.every-channel.netboot = {
    enable = lib.mkEnableOption "every.channel persistent netboot stage/serve services";

    listenIP = lib.mkOption {
      type = lib.types.str;
      example = "10.20.30.2";
      description = "IP address bound for TFTP/HTTP on the provisioning VLAN.";
    };

    interface = lib.mkOption {
      type = lib.types.str;
      example = "enp3s0";
      description = "Network interface name on the provisioning VLAN.";
    };

    hostname = lib.mkOption {
      type = lib.types.str;
      default = "boot.every.channel";
      description = "Boot server hostname advertised to DHCP/iPXE clients.";
    };

    rootDir = lib.mkOption {
      type = lib.types.str;
      default = "/var/lib/every-channel-netboot";
      description = "Persistent root directory containing staged HTTP and TFTP artifacts.";
    };

    httpPort = lib.mkOption {
      type = lib.types.port;
      default = 8080;
      description = "HTTP port used for kernel/initrd/netboot script serving.";
    };

    tftpBootFilename = lib.mkOption {
      type = lib.types.str;
      default = "ec-ipxe.efi";
      description = "Filename served via TFTP (DHCP option 67 in UniFi-only mode).";
    };

    chainTokenFile = lib.mkOption {
      type = lib.types.nullOr lib.types.str;
      default = null;
      example = "/run/agenix/every-channel-netboot-chain-token";
      description = "Optional file containing netboot chain token passed to stage/serve scripts.";
    };

    httpAllowedCIDRs = lib.mkOption {
      type = lib.types.listOf lib.types.str;
      default = [ ];
      example = [ "10.20.30.0/24" ];
      description = "Optional CIDR allowlist for HTTP artifact serving.";
    };

    openFirewall = lib.mkOption {
      type = lib.types.bool;
      default = true;
      description = "Open firewall ports for TFTP/HTTP (and ProxyDHCP ports when enabled).";
    };

    stageOnBoot = lib.mkOption {
      type = lib.types.bool;
      default = true;
      description = "Start the stage oneshot service during boot before serving.";
    };

    release = {
      host = lib.mkOption {
        type = lib.types.str;
        default = "https://git.every.channel";
        description = "Forge host used to fetch netboot release assets.";
      };

      repo = lib.mkOption {
        type = lib.types.str;
        default = "every-channel/every.channel";
        description = "Forge repository containing netboot release assets.";
      };

      tag = lib.mkOption {
        type = lib.types.nullOr lib.types.str;
        default = null;
        description = "Optional release tag to stage; defaults to latest release.";
      };

      localTarball = lib.mkOption {
        type = lib.types.nullOr lib.types.str;
        default = null;
        description = "Optional local netboot tarball path; bypasses release API download when set.";
      };

      tokenFile = lib.mkOption {
        type = lib.types.nullOr lib.types.str;
        default = null;
        description = "Optional file containing Forge API token for private release access.";
      };

      verifyChecksums = lib.mkOption {
        type = lib.types.bool;
        default = true;
        description = "Verify staged release tarball using SHA256SUMS.txt when available.";
      };
    };

    ipxe = {
      buildEmbedded = lib.mkOption {
        type = lib.types.bool;
        default = true;
        description = "Build embedded iPXE (ec-ipxe.efi) before staging artifacts.";
      };

      path = lib.mkOption {
        type = lib.types.nullOr lib.types.str;
        default = null;
        description = "Optional prebuilt iPXE EFI binary path; used when buildEmbedded is false.";
      };

      allowRemoteDownload = lib.mkOption {
        type = lib.types.bool;
        default = false;
        description = "Allow remote iPXE URL download during staging. Disabled by default.";
      };

      sha256 = lib.mkOption {
        type = lib.types.nullOr lib.types.str;
        default = null;
        description = "Optional SHA256 digest expected for selected iPXE EFI binary.";
      };

      repo = lib.mkOption {
        type = lib.types.str;
        default = "https://github.com/ipxe/ipxe.git";
        description = "iPXE source repository used for embedded EFI builds.";
      };

      ref = lib.mkOption {
        type = lib.types.nullOr lib.types.str;
        default = null;
        description = "Optional git ref/commit for iPXE build reproducibility.";
      };

      useDocker = lib.mkOption {
        type = lib.types.enum [ "auto" "true" "false" ];
        default = "auto";
        description = "Container fallback mode for iPXE builds (auto/true/false).";
      };

      dockerImage = lib.mkOption {
        type = lib.types.str;
        default = "ubuntu:24.04";
        description = "Docker image used when iPXE build runs in container mode.";
      };

      dockerPlatform = lib.mkOption {
        type = lib.types.str;
        default = "linux/amd64";
        description = "Docker platform used for containerized iPXE build.";
      };
    };

    proxyDhcp = {
      enable = lib.mkOption {
        type = lib.types.bool;
        default = false;
        description = "Enable dnsmasq ProxyDHCP chainloading mode.";
      };

      subnet = lib.mkOption {
        type = lib.types.nullOr lib.types.str;
        default = null;
        example = "10.20.30.0/24";
        description = "ProxyDHCP subnet (required when proxyDhcp.enable is true).";
      };
    };
  };

  config = lib.mkIf cfg.enable {
    assertions = [
      {
        assertion = cfg.proxyDhcp.enable -> cfg.proxyDhcp.subnet != null;
        message = "services.every-channel.netboot.proxyDhcp.subnet must be set when proxyDhcp.enable is true";
      }
      {
        assertion = cfg.ipxe.buildEmbedded || cfg.ipxe.path != null || cfg.ipxe.allowRemoteDownload;
        message = "Set ipxe.buildEmbedded=true, or provide ipxe.path, or allow ipxe.allowRemoteDownload=true";
      }
    ];

    systemd.tmpfiles.rules = [
      "d ${cfg.rootDir} 0750 root root -"
      "d ${cfg.rootDir}/http 0750 root root -"
      "d ${cfg.rootDir}/tftp 0750 root root -"
    ];

    systemd.services.every-channel-netboot-ipxe = lib.mkIf cfg.ipxe.buildEmbedded {
      description = "every.channel netboot embedded iPXE build";
      after = [ "network-online.target" ];
      wants = [ "network-online.target" ];
      wantedBy = lib.mkIf cfg.stageOnBoot [ "multi-user.target" ];
      path = stageToolchain ++ ipxeToolchain;
      serviceConfig = {
        Type = "oneshot";
        RemainAfterExit = true;
      };
      script = ''
        set -euo pipefail

        ${mkExport "EVERY_CHANNEL_NETBOOT_ROOT" cfg.rootDir}
        ${mkExport "EVERY_CHANNEL_NETBOOT_HOSTNAME" cfg.hostname}
        ${mkExport "EVERY_CHANNEL_NETBOOT_HTTP_PORT" (toString cfg.httpPort)}
        ${mkExport "EVERY_CHANNEL_NETBOOT_IPXE_FILENAME" cfg.tftpBootFilename}
        ${mkExport "EVERY_CHANNEL_NETBOOT_IPXE_REPO" cfg.ipxe.repo}
        ${optionalExport "EVERY_CHANNEL_NETBOOT_IPXE_REF" cfg.ipxe.ref}
        ${mkExport "EVERY_CHANNEL_NETBOOT_IPXE_USE_DOCKER" cfg.ipxe.useDocker}
        ${mkExport "EVERY_CHANNEL_NETBOOT_IPXE_DOCKER_IMAGE" cfg.ipxe.dockerImage}
        ${mkExport "EVERY_CHANNEL_NETBOOT_IPXE_DOCKER_PLATFORM" cfg.ipxe.dockerPlatform}
        ${optionalFileExport "EVERY_CHANNEL_NETBOOT_CHAIN_TOKEN" cfg.chainTokenFile}

        ${scriptsRoot}/scripts/netboot-build-ipxe.sh
      '';
    };

    systemd.services.every-channel-netboot-stage = {
      description = "every.channel netboot artifact stage";
      requires = lib.optionals cfg.ipxe.buildEmbedded [ "every-channel-netboot-ipxe.service" ];
      after = [ "network-online.target" ] ++ lib.optionals cfg.ipxe.buildEmbedded [ "every-channel-netboot-ipxe.service" ];
      wants = [ "network-online.target" ] ++ lib.optionals cfg.ipxe.buildEmbedded [ "every-channel-netboot-ipxe.service" ];
      wantedBy = lib.mkIf cfg.stageOnBoot [ "multi-user.target" ];
      path = stageToolchain;
      serviceConfig = {
        Type = "oneshot";
        RemainAfterExit = true;
      };
      script = ''
        set -euo pipefail

        ${mkExport "EVERY_CHANNEL_NETBOOT_ROOT" cfg.rootDir}
        ${mkExport "EVERY_CHANNEL_NETBOOT_HOSTNAME" cfg.hostname}
        ${mkExport "EVERY_CHANNEL_NETBOOT_HTTP_PORT" (toString cfg.httpPort)}
        ${mkExport "EVERY_CHANNEL_FORGE_HOST" cfg.release.host}
        ${mkExport "EVERY_CHANNEL_FORGE_REPO" cfg.release.repo}
        ${optionalExport "EVERY_CHANNEL_NETBOOT_RELEASE_TAG" cfg.release.tag}
        ${optionalExport "EVERY_CHANNEL_NETBOOT_TARBALL" cfg.release.localTarball}
        ${mkExport "EVERY_CHANNEL_NETBOOT_VERIFY_RELEASE_CHECKSUMS" (boolString cfg.release.verifyChecksums)}
        ${mkExport "EVERY_CHANNEL_NETBOOT_ALLOW_REMOTE_IPXE" (boolString cfg.ipxe.allowRemoteDownload)}
        ${mkExport "EVERY_CHANNEL_IPXE_EFI_FILENAME" cfg.tftpBootFilename}
        ${optionalExport "EVERY_CHANNEL_IPXE_EFI_SHA256" cfg.ipxe.sha256}
        ${optionalFileExport "EVERY_CHANNEL_FORGE_TOKEN" cfg.release.tokenFile}
        ${optionalFileExport "EVERY_CHANNEL_NETBOOT_CHAIN_TOKEN" cfg.chainTokenFile}

        ${lib.optionalString cfg.ipxe.buildEmbedded (mkExport "EVERY_CHANNEL_IPXE_EFI_PATH" "${cfg.rootDir}/tftp/${cfg.tftpBootFilename}")}
        ${lib.optionalString (!cfg.ipxe.buildEmbedded && cfg.ipxe.path != null) (mkExport "EVERY_CHANNEL_IPXE_EFI_PATH" cfg.ipxe.path)}

        ${scriptsRoot}/scripts/netboot-stage.sh
      '';
    };

    systemd.services.every-channel-netboot = {
      description = "every.channel netboot HTTP + TFTP service";
      requires = [ "every-channel-netboot-stage.service" ];
      after = [ "network-online.target" "every-channel-netboot-stage.service" ];
      wants = [ "network-online.target" "every-channel-netboot-stage.service" ];
      wantedBy = lib.mkIf cfg.stageOnBoot [ "multi-user.target" ];
      path = stageToolchain ++ [ pkgs.dnsmasq ];
      serviceConfig = {
        Type = "simple";
        Restart = "always";
        RestartSec = "5s";
      };
      script = ''
        set -euo pipefail

        ${mkExport "EVERY_CHANNEL_NETBOOT_ROOT" cfg.rootDir}
        ${mkExport "EVERY_CHANNEL_NETBOOT_LISTEN_IP" cfg.listenIP}
        ${mkExport "EVERY_CHANNEL_NETBOOT_INTERFACE" cfg.interface}
        ${mkExport "EVERY_CHANNEL_NETBOOT_HOSTNAME" cfg.hostname}
        ${mkExport "EVERY_CHANNEL_NETBOOT_HTTP_PORT" (toString cfg.httpPort)}
        ${mkExport "EVERY_CHANNEL_NETBOOT_PROXY_DHCP" (boolString cfg.proxyDhcp.enable)}
        ${optionalExport "EVERY_CHANNEL_NETBOOT_PROXY_SUBNET" cfg.proxyDhcp.subnet}
        ${mkExport "EVERY_CHANNEL_NETBOOT_TFTP_BOOT_FILENAME" cfg.tftpBootFilename}
        ${mkExport "EVERY_CHANNEL_NETBOOT_HTTP_ALLOWED_CIDRS" (lib.concatStringsSep "," cfg.httpAllowedCIDRs)}
        ${optionalFileExport "EVERY_CHANNEL_NETBOOT_CHAIN_TOKEN" cfg.chainTokenFile}

        ${scriptsRoot}/scripts/netboot-serve.sh
      '';
    };

    networking.firewall.allowedTCPPorts = lib.mkIf cfg.openFirewall [ cfg.httpPort ];
    networking.firewall.allowedUDPPorts = lib.mkIf cfg.openFirewall (
      [ 69 ] ++ lib.optionals cfg.proxyDhcp.enable [ 67 4011 ]
    );
  };
}
