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

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

TARGET_ARCH="${TARGET_ARCH:-}"
IMAGE_TAG="${IMAGE_TAG:-}"
BUILDER_IMAGE="${BUILDER_IMAGE:-rust:1-bookworm}"
RUNTIME_IMAGE="${RUNTIME_IMAGE:-debian:bookworm-slim}"
OUT_DIR="${OUT_DIR:-}"
DOCKERFILE="${DOCKERFILE:-$REPO_ROOT/docker/ours-rp-runtime.Dockerfile}"
BUILDER_NAME="${BUILDER_NAME:-default}"
INSTALL_BINFMT="${INSTALL_BINFMT:-1}"
SAVE_IMAGE="${SAVE_IMAGE:-1}"
LOAD_IMAGE="${LOAD_IMAGE:-1}"

usage() {
  cat <<'USAGE'
Usage:
  scripts/docker/build_docker_runtime_image.sh --arch amd64|arm64 [options]

Options:
  --arch <arch>       Target architecture: amd64|arm64
  --image <tag>       Docker image tag (default: ours-rp-runtime-<arch>:<git8>)
  --out-dir <path>    Directory for docker save tar.gz (default: target/<arch>-docker)
  --dockerfile <path> Dockerfile path
  --builder <name>    buildx builder name
  --builder-image <tag>
                      Builder base image (default: rust:1-bookworm)
  --runtime-image <tag>
                      Runtime base image (default: debian:bookworm-slim)
  --no-binfmt         Do not install binfmt/qemu for cross-architecture builds
  --no-save           Build image but do not docker save it
  --no-load           Use buildx output tar instead of --load
  -h, --help          Show this help
USAGE
}

normalize_arch() {
  case "$1" in
    amd64|x86_64)
      printf 'amd64\n'
      ;;
    arm64|aarch64)
      printf 'arm64\n'
      ;;
    *)
      return 1
      ;;
  esac
}

safe_tag_name() {
  printf '%s' "$1" | tr '/:' '--'
}

local_base_image_tag() {
  local role="$1"
  local arch="$2"
  local source_image="$3"
  printf 'ours-rp-base-%s-%s:%s\n' "$role" "$arch" "$(safe_tag_name "$source_image")"
}

platform_for_arch() {
  printf 'linux/%s\n' "$1"
}

default_image_tag() {
  local arch="$1"
  local commit_short="$2"
  printf 'ours-rp-runtime-%s:%s\n' "$arch" "$commit_short"
}

require_command() {
  command -v "$1" >/dev/null 2>&1 || {
    echo "missing required command: $1" >&2
    exit 2
  }
}

host_arch() {
  local raw_arch
  raw_arch="$(uname -m)"
  normalize_arch "$raw_arch" || {
    echo "unsupported host architecture: $raw_arch" >&2
    exit 2
  }
}

while [[ $# -gt 0 ]]; do
  case "$1" in
    --arch)
      TARGET_ARCH="$(normalize_arch "$2")" || {
        echo "unsupported target architecture: $2" >&2
        exit 2
      }
      shift 2
      ;;
    --image)
      IMAGE_TAG="$2"
      shift 2
      ;;
    --out-dir)
      OUT_DIR="$2"
      shift 2
      ;;
    --dockerfile)
      DOCKERFILE="$2"
      shift 2
      ;;
    --builder)
      BUILDER_NAME="$2"
      shift 2
      ;;
    --builder-image)
      BUILDER_IMAGE="$2"
      shift 2
      ;;
    --runtime-image)
      RUNTIME_IMAGE="$2"
      shift 2
      ;;
    --no-binfmt)
      INSTALL_BINFMT=0
      shift
      ;;
    --no-save)
      SAVE_IMAGE=0
      shift
      ;;
    --no-load)
      LOAD_IMAGE=0
      shift
      ;;
    -h|--help)
      usage
      exit 0
      ;;
    *)
      echo "unknown option: $1" >&2
      usage >&2
      exit 2
      ;;
  esac
done

[[ -n "$TARGET_ARCH" ]] || {
  echo "--arch is required" >&2
  usage >&2
  exit 2
}

SOURCE_COMMIT_FULL="$(git -C "$REPO_ROOT" rev-parse HEAD 2>/dev/null || echo unknown)"
SOURCE_COMMIT_SHORT="$(git -C "$REPO_ROOT" rev-parse --short=8 HEAD 2>/dev/null || echo unknown)"
SOURCE_DIRTY="false"
if [[ -n "$(git -C "$REPO_ROOT" status --short 2>/dev/null)" ]]; then
  SOURCE_DIRTY="true"
fi
BUILD_TIMESTAMP_UTC="$(date -u +%Y-%m-%dT%H:%M:%SZ)"

if [[ -z "$IMAGE_TAG" ]]; then
  default_revision="$SOURCE_COMMIT_SHORT"
  if [[ "$SOURCE_DIRTY" == "true" ]]; then
    default_revision="${default_revision}-dirty"
  fi
  IMAGE_TAG="$(default_image_tag "$TARGET_ARCH" "$default_revision")"
fi
if [[ -z "$OUT_DIR" ]]; then
  OUT_DIR="$REPO_ROOT/target/${TARGET_ARCH}-docker"
fi

require_command docker
mkdir -p "$OUT_DIR"

target_platform="$(platform_for_arch "$TARGET_ARCH")"
local_host_arch="$(host_arch)"
builder_platform="$(platform_for_arch "$local_host_arch")"
builder_source_image="$BUILDER_IMAGE"
runtime_source_image="$RUNTIME_IMAGE"
builder_local_image="$(local_base_image_tag builder "$local_host_arch" "$builder_source_image")"
runtime_local_image="$(local_base_image_tag runtime "$TARGET_ARCH" "$runtime_source_image")"

if [[ "$INSTALL_BINFMT" == "1" && "$local_host_arch" != "$TARGET_ARCH" ]]; then
  echo "installing binfmt/qemu for $TARGET_ARCH"
  docker run --rm --privileged tonistiigi/binfmt --install "$TARGET_ARCH"
fi

# Pulling through the Docker daemon uses its configured proxy. Buildx then consumes
# these architecture-pinned local aliases without issuing separate registry metadata
# requests for the Dockerfile FROM instructions.
echo "pulling builder base image: $builder_source_image ($builder_platform)"
docker pull --platform "$builder_platform" "$builder_source_image"
docker tag "$builder_source_image" "$builder_local_image"
echo "pulling runtime base image: $runtime_source_image ($target_platform)"
docker pull --platform "$target_platform" "$runtime_source_image"
docker tag "$runtime_source_image" "$runtime_local_image"
BUILDER_IMAGE="$builder_local_image"
RUNTIME_IMAGE="$runtime_local_image"

if [[ "$BUILDER_NAME" != "default" ]] && ! docker buildx inspect "$BUILDER_NAME" >/dev/null 2>&1; then
  docker buildx create --name "$BUILDER_NAME" --driver docker-container --use >/dev/null
else
  docker buildx use "$BUILDER_NAME" >/dev/null
fi
docker buildx inspect --bootstrap >/dev/null

metadata_path="$OUT_DIR/$(safe_tag_name "$IMAGE_TAG").build-metadata.json"
tar_path="$OUT_DIR/$(safe_tag_name "$IMAGE_TAG").tar.gz"
build_log="$OUT_DIR/$(safe_tag_name "$IMAGE_TAG").build.log"

echo "building $target_platform image: $IMAGE_TAG"
echo "repo: $REPO_ROOT"
echo "dockerfile: $DOCKERFILE"
echo "builder_source_image: $builder_source_image"
echo "runtime_source_image: $runtime_source_image"
echo "builder_local_image: $BUILDER_IMAGE"
echo "runtime_local_image: $RUNTIME_IMAGE"
echo "source_commit: $SOURCE_COMMIT_FULL"
echo "source_dirty: $SOURCE_DIRTY"
echo "build_timestamp_utc: $BUILD_TIMESTAMP_UTC"
start_epoch="$(date +%s)"

if [[ "$LOAD_IMAGE" == "1" ]]; then
  docker buildx build \
    --platform "$target_platform" \
    --builder "$BUILDER_NAME" \
    --pull=false \
    --load \
    --build-arg BUILDKIT_INLINE_CACHE=1 \
    --build-arg "BUILDER_IMAGE=$BUILDER_IMAGE" \
    --build-arg "RUNTIME_IMAGE=$RUNTIME_IMAGE" \
    --build-arg "SOURCE_COMMIT=$SOURCE_COMMIT_FULL" \
    --build-arg "SOURCE_DIRTY=$SOURCE_DIRTY" \
    --build-arg "BUILD_TIMESTAMP_UTC=$BUILD_TIMESTAMP_UTC" \
    --metadata-file "$metadata_path" \
    -t "$IMAGE_TAG" \
    -f "$DOCKERFILE" \
    "$REPO_ROOT" 2>&1 | tee "$build_log"
else
  raw_tar_path="$OUT_DIR/$(safe_tag_name "$IMAGE_TAG").tar"
  docker buildx build \
    --platform "$target_platform" \
    --builder "$BUILDER_NAME" \
    --pull=false \
    --output "type=docker,dest=$raw_tar_path" \
    --build-arg BUILDKIT_INLINE_CACHE=1 \
    --build-arg "BUILDER_IMAGE=$BUILDER_IMAGE" \
    --build-arg "RUNTIME_IMAGE=$RUNTIME_IMAGE" \
    --build-arg "SOURCE_COMMIT=$SOURCE_COMMIT_FULL" \
    --build-arg "SOURCE_DIRTY=$SOURCE_DIRTY" \
    --build-arg "BUILD_TIMESTAMP_UTC=$BUILD_TIMESTAMP_UTC" \
    --metadata-file "$metadata_path" \
    -t "$IMAGE_TAG" \
    -f "$DOCKERFILE" \
    "$REPO_ROOT" 2>&1 | tee "$build_log"
  gzip -f "$raw_tar_path"
  tar_path="${raw_tar_path}.gz"
fi

elapsed_secs=$(( $(date +%s) - start_epoch ))

if [[ "$SAVE_IMAGE" == "1" && "$LOAD_IMAGE" == "1" ]]; then
  echo "saving image to $tar_path"
  docker save "$IMAGE_TAG" | gzip -c > "$tar_path"
fi

tar_sha256=""
if [[ -f "$tar_path" ]]; then
  tar_sha256="$(sha256sum "$tar_path" | awk '{print $1}')"
fi

{
  echo "image=$IMAGE_TAG"
  echo "platform=$target_platform"
  echo "arch=$TARGET_ARCH"
  echo "builder_image=$builder_source_image"
  echo "runtime_image=$runtime_source_image"
  echo "builder_local_image=$BUILDER_IMAGE"
  echo "runtime_local_image=$RUNTIME_IMAGE"
  echo "elapsed_secs=$elapsed_secs"
  echo "metadata=$metadata_path"
  echo "tar=$tar_path"
  echo "tar_size_bytes=$(wc -c < "$tar_path" 2>/dev/null || echo 0)"
  echo "tar_sha256=$tar_sha256"
  echo "source_commit=$SOURCE_COMMIT_FULL"
  echo "source_commit_short=$SOURCE_COMMIT_SHORT"
  echo "source_dirty=$SOURCE_DIRTY"
  echo "build_timestamp_utc=$BUILD_TIMESTAMP_UTC"
  echo "git_commit=$SOURCE_COMMIT_FULL"
  echo "git_status_count=$(git -C "$REPO_ROOT" status --short 2>/dev/null | wc -l | tr -d ' ')"
  echo "built_at_utc=$BUILD_TIMESTAMP_UTC"
} > "$OUT_DIR/$(safe_tag_name "$IMAGE_TAG").build-summary.env"

echo "build complete: elapsed=${elapsed_secs}s tar=$tar_path"
