#!/usr/bin/env bash
set -euo pipefail

root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "${root}"

netboot_root="${EVERY_CHANNEL_NETBOOT_ROOT:-tmp/netboot}"
tftp_dir="${netboot_root}/tftp"
netboot_hostname="${EVERY_CHANNEL_NETBOOT_HOSTNAME:-boot.every.channel}"
http_port="${EVERY_CHANNEL_NETBOOT_HTTP_PORT:-8080}"
ipxe_repo="${EVERY_CHANNEL_NETBOOT_IPXE_REPO:-https://github.com/ipxe/ipxe.git}"
ipxe_ref="${EVERY_CHANNEL_NETBOOT_IPXE_REF:-}"
output_name="${EVERY_CHANNEL_NETBOOT_IPXE_FILENAME:-ec-ipxe.efi}"
use_docker="${EVERY_CHANNEL_NETBOOT_IPXE_USE_DOCKER:-auto}"
docker_image="${EVERY_CHANNEL_NETBOOT_IPXE_DOCKER_IMAGE:-ubuntu:24.04}"
docker_platform="${EVERY_CHANNEL_NETBOOT_IPXE_DOCKER_PLATFORM:-linux/amd64}"
chain_token="${EVERY_CHANNEL_NETBOOT_CHAIN_TOKEN:-}"

need_cmd() {
  local name="$1"
  if ! command -v "${name}" >/dev/null 2>&1; then
    echo "error: required command not found: ${name}" >&2
    exit 2
  fi
}

validate_chain_token() {
  local value="$1"
  if [[ -z "${value}" ]]; then
    return 0
  fi
  if [[ ! "${value}" =~ ^[A-Za-z0-9._~-]{16,128}$ ]]; then
    echo "error: EVERY_CHANNEL_NETBOOT_CHAIN_TOKEN must match [A-Za-z0-9._~-]{16,128}" >&2
    exit 2
  fi
}

validate_chain_token "${chain_token}"

tmp_dir="$(mktemp -d)"
cleanup() {
  rm -rf "${tmp_dir}"
}
trap cleanup EXIT

repo_dir="${tmp_dir}/ipxe"
embed_script="${tmp_dir}/embed.ipxe"
build_output="${tmp_dir}/ipxe.efi"

chain_url="http://${netboot_hostname}:${http_port}/netboot.ipxe"
if [[ -n "${chain_token}" ]]; then
  chain_url="${chain_url}?token=${chain_token}"
fi

cat > "${embed_script}" <<EOF
#!ipxe
dhcp
chain ${chain_url} || shell
EOF

bool_norm() {
  local raw
  raw="$(printf '%s' "${1:-}" | tr '[:upper:]' '[:lower:]')"
  case "${raw}" in
    ''|auto) echo "auto" ;;
    true|1|yes|y|on) echo "true" ;;
    false|0|no|n|off) echo "false" ;;
    *)
      echo "error: invalid boolean value '${1}'" >&2
      exit 2
      ;;
  esac
}

build_native() {
  need_cmd git
  need_cmd make
  if ! command -v cc >/dev/null 2>&1 && ! command -v gcc >/dev/null 2>&1; then
    echo "error: required C compiler not found (need cc or gcc)" >&2
    return 1
  fi
  if ! command -v objcopy >/dev/null 2>&1; then
    echo "error: required tool not found: objcopy" >&2
    return 1
  fi
  git clone --depth 1 "${ipxe_repo}" "${repo_dir}" >/dev/null
  if [[ -n "${ipxe_ref}" ]]; then
    git -C "${repo_dir}" fetch --depth 1 origin "${ipxe_ref}" >/dev/null
    git -C "${repo_dir}" checkout -q FETCH_HEAD
  fi
  make -C "${repo_dir}/src" -s "bin-x86_64-efi/ipxe.efi" "EMBED=${embed_script}"
  cp -f "${repo_dir}/src/bin-x86_64-efi/ipxe.efi" "${build_output}"
}

build_docker() {
  need_cmd docker
  docker run --rm \
    --platform "${docker_platform}" \
    -v "${tmp_dir}:/work" \
    -e IPXE_REPO="${ipxe_repo}" \
    -e IPXE_REF="${ipxe_ref}" \
    -w /work \
    "${docker_image}" \
    bash -lc '
      set -euo pipefail
      apt-get update >/dev/null
      DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
        ca-certificates git make gcc binutils perl mtools >/dev/null
      git clone --depth 1 "${IPXE_REPO}" ipxe >/dev/null
      if [ -n "${IPXE_REF}" ]; then
        git -C ipxe fetch --depth 1 origin "${IPXE_REF}" >/dev/null
        git -C ipxe checkout -q FETCH_HEAD
      fi
      make -C ipxe/src -s "bin-x86_64-efi/ipxe.efi" "EMBED=/work/embed.ipxe"
    '
  cp -f "${tmp_dir}/ipxe/src/bin-x86_64-efi/ipxe.efi" "${build_output}"
}

use_docker="$(bool_norm "${use_docker}")"
build_ok="false"
if [[ "${use_docker}" != "true" ]]; then
  if build_native; then
    build_ok="true"
  fi
fi
if [[ "${build_ok}" != "true" ]]; then
  if [[ "${use_docker}" == "false" ]]; then
    exit 2
  fi
  build_docker
fi

mkdir -p "${tftp_dir}"
cp -f "${build_output}" "${tftp_dir}/${output_name}"

if command -v sha256sum >/dev/null 2>&1; then
  sha256sum "${tftp_dir}/${output_name}" > "${tftp_dir}/${output_name}.sha256"
elif command -v shasum >/dev/null 2>&1; then
  shasum -a 256 "${tftp_dir}/${output_name}" > "${tftp_dir}/${output_name}.sha256"
fi

echo "ok: built embedded iPXE binary: ${tftp_dir}/${output_name}"
echo "ok: chains to ${chain_url}"
if [[ -n "${chain_token}" ]]; then
  echo "ok: chain token enabled"
fi
echo "hint: in UniFi set DHCP boot filename to ${output_name}"
