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

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

# Candidate-producing entry points set this before sourcing common.sh. Keep the
# default at the historical complete Apple scope for internal helper scripts,
# but reject reordered, duplicated, or otherwise ambiguous platform sets.
beam_vlckit_platforms=${BEAM_VLCKIT_PLATFORMS:-ios,tvos}
case "$beam_vlckit_platforms" in
  ios)
    beam_vlckit_default_output_basename=output-ios
    ;;
  tvos)
    beam_vlckit_default_output_basename=inventory-tvos
    ;;
  ios,tvos)
    beam_vlckit_default_output_basename=output-apple
    ;;
  *)
    echo "ERROR: BEAM_VLCKIT_PLATFORMS must be ios, tvos, or ios,tvos" >&2
    exit 1
    ;;
esac
export BEAM_VLCKIT_PLATFORMS="$beam_vlckit_platforms"

beam_vlckit_output_basename=${BEAM_VLCKIT_OUTPUT_BASENAME:-$beam_vlckit_default_output_basename}
case "$beam_vlckit_platforms:$beam_vlckit_output_basename" in
  ios:output-ios|ios:calibration-ios|tvos:inventory-tvos|ios,tvos:output-apple) ;;
  *)
    echo "ERROR: unsafe output basename for $beam_vlckit_platforms: $beam_vlckit_output_basename" >&2
    exit 1
    ;;
esac

# pins.env contains assignments only. Reject shell syntax before sourcing it so
# a release job never executes an accidentally added command.
beam_pins_file="$beam_vlckit_tool_dir/pins.env"
if [[ ! -f "$beam_pins_file" ]]; then
  echo "missing VLCKit pin file: $beam_pins_file" >&2
  exit 1
fi
if ! awk '
  /^[[:space:]]*($|#)/ { next }
  /^[A-Z][A-Z0-9_]*=[A-Za-z0-9._:,+@\/-]+$/ { next }
  { bad=1; print "invalid pins.env line " NR ": " $0 > "/dev/stderr" }
  END { exit bad ? 1 : 0 }
' "$beam_pins_file"; then
  exit 1
fi
# shellcheck disable=SC1090
source "$beam_pins_file"

beam_vlckit_work_dir=${BEAM_VLCKIT_WORK_DIR:-$beam_mobile_dir/build/vlckit-apple-candidate}
beam_vlckit_build_root=$BEAM_CANONICAL_BUILD_ROOT
beam_vlckit_source_parent="$beam_vlckit_build_root/source"
beam_vlckit_source_dir="$beam_vlckit_source_parent/VLCKit"
beam_vlckit_source_metadata="$beam_vlckit_source_parent/metadata/SOURCE-MANIFEST.txt"
beam_vlckit_staging_dir="$beam_vlckit_work_dir/$beam_vlckit_output_basename.staging"
beam_vlckit_output_dir="$beam_vlckit_work_dir/$beam_vlckit_output_basename"
beam_vlckit_canonical_lock_dir="${beam_vlckit_build_root}.operation.lock"
beam_vlckit_canonical_lock_owned=0

beam_die() {
  echo "ERROR: $*" >&2
  exit 1
}

beam_require_command() {
  command -v "$1" >/dev/null 2>&1 || beam_die "required command is missing: $1"
}

beam_sha256() {
  shasum -a 256 "$1" | awk '{print $1}'
}

beam_platform_selected() {
  case ",$beam_vlckit_platforms," in
    *",$1,"*) return 0 ;;
    *) return 1 ;;
  esac
}

beam_free_gib() {
  python3 - "$1" <<'PY'
import shutil
import sys
print(shutil.disk_usage(sys.argv[1]).free // (1024 ** 3))
PY
}

beam_assert_work_dir() {
  local resolved_parent
  mkdir -p "$beam_vlckit_work_dir"
  resolved_parent=$(cd "$(dirname "$beam_vlckit_work_dir")" && pwd -P)
  case "$resolved_parent/$(basename "$beam_vlckit_work_dir")" in
    "$beam_mobile_dir"/build/*) ;;
    *) beam_die "BEAM_VLCKIT_WORK_DIR must be beneath $beam_mobile_dir/build" ;;
  esac
  case "$beam_vlckit_build_root" in
    /private/tmp/beam-vlckit-apple-[0-9]*-beam.*) ;;
    *) beam_die "unsafe canonical Apple build root: $beam_vlckit_build_root" ;;
  esac
  [[ ! -L "$beam_vlckit_build_root" ]] || beam_die "canonical build root must not be a symlink"
  mkdir -p "$beam_vlckit_build_root"
}

beam_acquire_canonical_lock() {
  local owner_file="$beam_vlckit_canonical_lock_dir/owner"
  local existing_owner
  if [[ -n ${BEAM_VLCKIT_CANONICAL_LOCK_TOKEN:-} ]]; then
    [[ -d "$beam_vlckit_canonical_lock_dir" && -f "$owner_file" ]] || \
      beam_die "inherited canonical lock is missing: $beam_vlckit_canonical_lock_dir"
    existing_owner=$(<"$owner_file")
    [[ "$existing_owner" == "$BEAM_VLCKIT_CANONICAL_LOCK_TOKEN" ]] || \
      beam_die "inherited canonical lock token does not match its owner"
    return
  fi
  if ! mkdir "$beam_vlckit_canonical_lock_dir" 2>/dev/null; then
    existing_owner=unknown
    [[ ! -f "$owner_file" ]] || existing_owner=$(<"$owner_file")
    beam_die "canonical Apple build root is locked by $existing_owner: $beam_vlckit_canonical_lock_dir"
  fi
  beam_vlckit_canonical_lock_owned=1
  BEAM_VLCKIT_CANONICAL_LOCK_TOKEN="beam-$$-${RANDOM}"
  export BEAM_VLCKIT_CANONICAL_LOCK_TOKEN
  printf '%s\n' "$BEAM_VLCKIT_CANONICAL_LOCK_TOKEN" > "$owner_file"
}

beam_release_canonical_lock() {
  local owner_file="$beam_vlckit_canonical_lock_dir/owner"
  local existing_owner
  [[ $beam_vlckit_canonical_lock_owned == 1 ]] || return 0
  if [[ -f "$owner_file" ]]; then
    existing_owner=$(<"$owner_file")
    [[ "$existing_owner" == "$BEAM_VLCKIT_CANONICAL_LOCK_TOKEN" ]] || \
      beam_die "refusing to release a canonical lock owned by another process"
    rm -f "$owner_file"
  fi
  rmdir "$beam_vlckit_canonical_lock_dir" 2>/dev/null || \
    beam_die "canonical lock contains unexpected payload: $beam_vlckit_canonical_lock_dir"
  beam_vlckit_canonical_lock_owned=0
}
