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

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

  firstDns = lib.head cfg.boot.userNet.dnsServers;
  qemuBin = "${cfg.package}/bin/qemu-system-x86_64";
  qemuImgBin = "${cfg.package}/bin/qemu-img";
  bootNetdevArg = lib.escapeShellArg "user,id=boot0,dns=${firstDns},hostname=${cfg.boot.userNet.hostname},tftp=${cfg.boot.userNet.tftpDir},bootfile=${cfg.boot.userNet.bootFilename}";
  bootDeviceArg = lib.escapeShellArg "${cfg.boot.userNet.model},netdev=boot0";
  lanNetdevArg = lib.escapeShellArg "tap,id=lan0,fd=3";
  lanDeviceArg = lib.escapeShellArg "${cfg.lan.model},netdev=lan0";
  driveArg = lib.escapeShellArg "if=virtio,format=qcow2,file=${cfg.disk.path}";
  effectiveChainUrl =
    if cfg.boot.chainUrl != null
    then cfg.boot.chainUrl
    else "http://10.0.2.2:${toString cfg.boot.http.port}/netboot.ipxe";

  bootScript = pkgs.writeText "every-channel-qemu.ipxe" ''
    #!ipxe
    dhcp
    set dns ${firstDns}
    chain ${effectiveChainUrl} || shell
  '';
  bootAsset = pkgs.ipxe.override {
    embedScript = bootScript;
    additionalTargets = {
      "bin/undionly.kpxe" = null;
    };
    firmwareBinary = "undionly.kpxe";
  };

  bootExtraArgs = lib.concatMapStringsSep "\n" (arg: "  cmd+=(${lib.escapeShellArg arg})") cfg.extraArgs;

  runner = pkgs.writeShellApplication {
    name = "every-channel-ipxe-qemu";
    runtimeInputs = [
      pkgs.coreutils
      pkgs.iproute2
      cfg.package
    ];
    text = ''
      set -euo pipefail

      state_dir=${lib.escapeShellArg cfg.stateDir}
      tftp_dir=${lib.escapeShellArg cfg.boot.userNet.tftpDir}
      boot_file=${lib.escapeShellArg cfg.boot.userNet.bootFilename}
      disk_path=${lib.escapeShellArg cfg.disk.path}
      disk_size=${lib.escapeShellArg cfg.disk.size}
      lan_ifname=${lib.escapeShellArg cfg.lan.macvtap.name}
      enable_kvm=${lib.escapeShellArg (lib.boolToString cfg.enableKvm)}
      enable_lan=${lib.escapeShellArg (lib.boolToString cfg.lan.enable)}
      serve_http=${lib.escapeShellArg (lib.boolToString cfg.boot.http.enable)}
      http_bind_ip=${lib.escapeShellArg cfg.boot.http.bindIp}
      http_port=${toString cfg.boot.http.port}
      http_root=${lib.escapeShellArg cfg.boot.http.root}

      cleanup() {
        if [[ "$enable_lan" == true ]]; then
          ip link del "$lan_ifname" 2>/dev/null || true
        fi
      }

      terminate() {
        if [[ -n "''${http_pid:-}" ]]; then
          kill "$http_pid" 2>/dev/null || true
          wait "$http_pid" 2>/dev/null || true
        fi
        if [[ -n "''${qemu_pid:-}" ]]; then
          kill "$qemu_pid" 2>/dev/null || true
          wait "$qemu_pid" 2>/dev/null || true
        fi
        exit 0
      }

      trap cleanup EXIT
      trap terminate TERM INT

      install -d -m 0755 "$state_dir" "$tftp_dir" "$(dirname "$disk_path")"
      install -m 0644 ${bootAsset}/undionly.kpxe "$tftp_dir/$boot_file"

      if [[ "$serve_http" == true ]]; then
        if [[ ! -d "$http_root" ]]; then
          echo "error: boot HTTP root not found: $http_root" >&2
          exit 1
        fi
        ${pkgs.python3}/bin/python3 ${scriptsRoot}/scripts/netboot-http-server.py \
          --bind-ip "$http_bind_ip" \
          --port "$http_port" \
          --root "$http_root" &
        http_pid=$!
      fi

      if [[ ! -f "$disk_path" ]]; then
        ${qemuImgBin} create -f qcow2 "$disk_path" "$disk_size" >/dev/null
      fi

      cmd=(
        ${lib.escapeShellArg qemuBin}
        -name ${lib.escapeShellArg cfg.name}
        -machine ${lib.escapeShellArg cfg.machine}
        -cpu ${lib.escapeShellArg cfg.cpu}
        -smp ${toString cfg.vcpus}
        -m ${toString cfg.memoryMiB}
        -nographic
        -boot ${lib.escapeShellArg cfg.boot.order}
        -serial ${lib.escapeShellArg cfg.serial}
        -device virtio-rng-pci
      )

      if [[ "$enable_kvm" == true ]]; then
        cmd+=(-enable-kvm)
      fi

      cmd+=(
        -netdev ${bootNetdevArg}
        -device ${bootDeviceArg}
      )

      if [[ "$enable_lan" == true ]]; then
        ip link del "$lan_ifname" 2>/dev/null || true
        ip link add link ${lib.escapeShellArg cfg.lan.macvtap.interface} name "$lan_ifname" type macvtap mode ${lib.escapeShellArg cfg.lan.macvtap.mode}
        ip link set "$lan_ifname" up
        tap_index="$(< /sys/class/net/$lan_ifname/ifindex)"
        exec 3<>"/dev/tap''${tap_index}"
        cmd+=(
          -netdev ${lanNetdevArg}
          -device ${lanDeviceArg}
        )
      fi

      cmd+=(
        -drive ${driveArg}
      )
${bootExtraArgs}

      "''${cmd[@]}" &
      qemu_pid=$!
      wait "$qemu_pid"
    '';
  };
in
{
  options.services.every-channel.ipxe-qemu = {
    enable = lib.mkEnableOption "every.channel iPXE/QEMU boot VM";

    package = lib.mkOption {
      type = lib.types.package;
      default = pkgs.qemu_kvm;
      description = "QEMU package providing qemu-system-x86_64 and qemu-img.";
    };

    name = lib.mkOption {
      type = lib.types.str;
      default = "every-channel-ipxe";
      description = "QEMU guest name.";
    };

    machine = lib.mkOption {
      type = lib.types.str;
      default = "q35,accel=kvm";
      description = "QEMU machine string.";
    };

    cpu = lib.mkOption {
      type = lib.types.str;
      default = "host";
      description = "QEMU CPU model.";
    };

    enableKvm = lib.mkOption {
      type = lib.types.bool;
      default = true;
      description = "Use KVM acceleration when available.";
    };

    vcpus = lib.mkOption {
      type = lib.types.ints.positive;
      default = 2;
      description = "Virtual CPU count.";
    };

    memoryMiB = lib.mkOption {
      type = lib.types.ints.positive;
      default = 4096;
      description = "Guest memory in MiB.";
    };

    serial = lib.mkOption {
      type = lib.types.str;
      default = "mon:stdio";
      description = "Serial/monitor wiring passed to QEMU.";
    };

    stateDir = lib.mkOption {
      type = lib.types.str;
      default = "/var/lib/every-channel/ipxe-qemu";
      description = "Persistent state directory for qcow2 disk and boot assets.";
    };

    disk = {
      path = lib.mkOption {
        type = lib.types.str;
        default = "${cfg.stateDir}/disk.qcow2";
        description = "Persistent qcow2 disk path.";
      };

      size = lib.mkOption {
        type = lib.types.str;
        default = "16G";
        description = "Size used when initializing the qcow2 disk.";
      };
    };

    boot = {
      order = lib.mkOption {
        type = lib.types.str;
        default = "order=n";
        description = "QEMU boot order, defaulting to network first.";
      };

      chainUrl = lib.mkOption {
        type = lib.types.nullOr lib.types.str;
        default = null;
        description = "Optional explicit iPXE chain target fetched by the guest; defaults to the local boot.http server.";
      };

      http = {
        enable = lib.mkOption {
          type = lib.types.bool;
          default = true;
          description = "Serve a host-local HTTP root for the guest netboot flow.";
        };

        bindIp = lib.mkOption {
          type = lib.types.str;
          default = "127.0.0.1";
          description = "Bind address used for the host-local boot HTTP server.";
        };

        port = lib.mkOption {
          type = lib.types.port;
          default = 8080;
          description = "Port used for the host-local boot HTTP server.";
        };

        root = lib.mkOption {
          type = lib.types.nullOr lib.types.str;
          default = null;
          description = "Directory containing kernel/initrd/netboot.ipxe served to the guest.";
        };
      };

      userNet = {
        hostname = lib.mkOption {
          type = lib.types.str;
          default = "every-channel-ipxe";
          description = "Hostname advertised on the user-mode boot network.";
        };

        dnsServers = lib.mkOption {
          type = lib.types.listOf lib.types.str;
          default = [ "1.1.1.1" ];
          description = "DNS servers used by the user-mode boot NIC; the first entry is applied.";
        };

        tftpDir = lib.mkOption {
          type = lib.types.str;
          default = "${cfg.stateDir}/tftp";
          description = "TFTP directory used by the user-mode boot NIC.";
        };

        bootFilename = lib.mkOption {
          type = lib.types.str;
          default = "undionly.kpxe";
          description = "Boot asset filename exposed on the user-mode boot NIC.";
        };

        model = lib.mkOption {
          type = lib.types.str;
          default = "e1000";
          description = "NIC model used for the boot network.";
        };
      };
    };

    lan = {
      enable = lib.mkOption {
        type = lib.types.bool;
        default = false;
        description = "Attach a second NIC to a real LAN using macvtap.";
      };

      model = lib.mkOption {
        type = lib.types.str;
        default = "virtio-net-pci";
        description = "NIC model used for the LAN attachment.";
      };

      macvtap = {
        interface = lib.mkOption {
          type = lib.types.nullOr lib.types.str;
          default = null;
          description = "Host interface used as the lower device for macvtap.";
        };

        name = lib.mkOption {
          type = lib.types.str;
          default = "ecqemu0";
          description = "macvtap link name created while the guest runs.";
        };

        mode = lib.mkOption {
          type = lib.types.enum [
            "private"
            "vepa"
            "bridge"
            "passthru"
            "source"
          ];
          default = "bridge";
          description = "macvtap mode used for the LAN attachment.";
        };
      };
    };

    extraArgs = lib.mkOption {
      type = lib.types.listOf lib.types.str;
      default = [ ];
      description = "Additional arguments appended to the QEMU command.";
    };
  };

  config = lib.mkIf cfg.enable {
    assertions = [
      {
        assertion = cfg.boot.userNet.dnsServers != [ ];
        message = "services.every-channel.ipxe-qemu.boot.userNet.dnsServers must not be empty";
      }
      {
        assertion = (!cfg.lan.enable) || (cfg.lan.macvtap.interface != null);
        message = "services.every-channel.ipxe-qemu.lan.macvtap.interface must be set when lan.enable is true";
      }
      {
        assertion = (!cfg.boot.http.enable) || (cfg.boot.http.root != null);
        message = "services.every-channel.ipxe-qemu.boot.http.root must be set when boot.http.enable is true";
      }
    ];

    environment.systemPackages = [ runner ];

    systemd.tmpfiles.rules = [
      "d ${cfg.stateDir} 0755 root root -"
      "d ${cfg.boot.userNet.tftpDir} 0755 root root -"
    ];

    systemd.services.every-channel-ipxe-qemu = {
      description = "every.channel iPXE QEMU VM";
      after = [ "local-fs.target" "network-online.target" ];
      wants = [ "network-online.target" ];
      wantedBy = [ "multi-user.target" ];
      path = [
        pkgs.coreutils
        pkgs.iproute2
        cfg.package
      ];
      serviceConfig = {
        Type = "simple";
        ExecStart = "${runner}/bin/every-channel-ipxe-qemu";
        Restart = "always";
        RestartSec = 5;
        WorkingDirectory = cfg.stateDir;
      };
    };
  };
}
