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

usage() {
  cat <<'EOF'
Usage:
  artifact_wifi_3.sh --src <app_root> --version <x.y.z>
                     [--device-type <raspberrypi4|raspberrypi5>]...
                     [--out-dir <dir>]
                     [--artifact-name <name>]
                     [--compression <none|gzip|lzma>]
                     [--wifi-connect-version <vX.Y.Z>]

Examples:
  sudo ./artifact_wifi_3.sh --src ./PeopleTrackerDepthAI --version 2.2.10 --out-dir ./dist
  sudo ./artifact_wifi_3.sh --src ./PeopleTrackerDepthAI --version 2.2.10 --device-type raspberrypi4 --out-dir ./dist
EOF
}

# ----------------------------
# Defaults
# ----------------------------
SRC=""
VERSION=""
OUT_DIR="./dist"
ARTIFACT_NAME=""
COMPRESSION="gzip"
DEVICE_TYPES=()                 # empty => both
WIFI_CONNECT_VERSION="v4.11.84"
SYNC_CANONICAL_TO_UNC="${SYNC_CANONICAL_TO_UNC:-0}"

PORTAL_SSID_DEFAULT="VisionAI Connect"
PORTAL_PASSPHRASE_DEFAULT="mender06"   # >= 8 chars, wifi-connect requires
PORTAL_INTERFACE_DEFAULT="wlan0"

# ----------------------------
# Parse args
# ----------------------------
while [[ $# -gt 0 ]]; do
  case "$1" in
    --src) SRC="${2:-}"; shift 2;;
    --version) VERSION="${2:-}"; shift 2;;
    --out-dir|--outdir) OUT_DIR="${2:-}"; shift 2;;
    --artifact-name) ARTIFACT_NAME="${2:-}"; shift 2;;
    --compression) COMPRESSION="${2:-}"; shift 2;;
    --wifi-connect-version) WIFI_CONNECT_VERSION="${2:-}"; shift 2;;
    --device-type)
      dt="${2:-}"; shift 2
      case "$dt" in
        raspberrypi4|raspberrypi5) DEVICE_TYPES+=("$dt") ;;
        *) echo "ERROR: invalid --device-type '$dt' (use raspberrypi4 or raspberrypi5)" >&2; exit 2 ;;
      esac
      ;;
    -h|--help) usage; exit 0;;
    *) echo "Unknown arg: $1" >&2; usage; exit 2;;
  esac
done

[[ -n "$SRC" && -n "$VERSION" ]] || { echo "Missing required args." >&2; usage; exit 2; }
[[ -d "$SRC" ]] || { echo "SRC folder not found: $SRC" >&2; exit 2; }
if [[ "$WIFI_CONNECT_VERSION" == "latest" || ! "$WIFI_CONNECT_VERSION" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
  echo "ERROR: --wifi-connect-version must be an explicit pinned tag like v4.11.84 (latest is not allowed)." >&2
  exit 2
fi

command -v mender-artifact >/dev/null 2>&1 || { echo "ERROR: mender-artifact not found in PATH." >&2; exit 2; }
command -v tar >/dev/null 2>&1 || { echo "ERROR: tar not found in PATH." >&2; exit 2; }
command -v curl >/dev/null 2>&1 || { echo "ERROR: curl not found (needed at build-time to fetch wifi-connect assets)." >&2; exit 2; }
command -v gzip >/dev/null 2>&1 || { echo "ERROR: gzip not found (needed to validate .tar.gz assets)." >&2; exit 2; }

# Default device types
if [[ ${#DEVICE_TYPES[@]} -eq 0 ]]; then
  DEVICE_TYPES=(raspberrypi4 raspberrypi5)
fi

# Deduplicate device types
dedup=()
for dt in "${DEVICE_TYPES[@]}"; do
  skip=0
  for x in "${dedup[@]}"; do [[ "$x" == "$dt" ]] && skip=1 && break; done
  [[ $skip -eq 0 ]] && dedup+=("$dt")
done
DEVICE_TYPES=("${dedup[@]}")

# Validate compression
case "$COMPRESSION" in
  none|gzip|lzma) ;;
  *) echo "ERROR: invalid --compression '$COMPRESSION' (use none|gzip|lzma)" >&2; exit 2 ;;
esac

TS="$(date -u +%Y%m%d%H%M%S)"
GIT_SHA=""
if command -v git >/dev/null 2>&1 && git -C "$SRC" rev-parse --is-inside-work-tree >/dev/null 2>&1; then
  GIT_SHA="$(git -C "$SRC" rev-parse --short HEAD 2>/dev/null || true)"
fi
RELEASE_ID="${GIT_SHA:-$VERSION}-${TS}"

mkdir -p "$OUT_DIR"
[[ -n "$ARTIFACT_NAME" ]] || ARTIFACT_NAME="peoplecounter-${VERSION}"

DT_TAG="$(IFS=+; echo "${DEVICE_TYPES[*]}")"
OUT_PATH="${OUT_DIR}/peoplecounter-${VERSION}-${DT_TAG}-${TS}.mender"

WORK="$(mktemp -d)"
trap 'rm -rf "$WORK"' EXIT

echo "SRC:                 $SRC"
echo "VERSION:             $VERSION"
echo "RELEASE_ID:          $RELEASE_ID"
echo "DEV TYPES:           ${DEVICE_TYPES[*]}"
echo "WIFI_CONNECT_VERSION $WIFI_CONNECT_VERSION"
echo "OUTPUT:              $OUT_PATH"
echo "BUILD_POLICY:        build-time internet allowed only for artifact assembly"
echo "TARGET_POLICY:       install is offline-first; controlled online recovery is allowed on target"
echo "AUTO_UPDATE_POLICY:  disabled"

validate_tgz() {
  local f="$1"
  gzip -t "$f" >/dev/null 2>&1 || return 1
  tar -tzf "$f" >/dev/null 2>&1 || return 1
  return 0
}

sha256_file() {
  local f="$1"
  if command -v sha256sum >/dev/null 2>&1; then
    sha256sum "$f" | awk '{print tolower($1)}'
    return 0
  fi
  if command -v shasum >/dev/null 2>&1; then
    shasum -a 256 "$f" | awk '{print tolower($1)}'
    return 0
  fi
  if command -v openssl >/dev/null 2>&1; then
    openssl dgst -sha256 "$f" | awk '{print tolower($NF)}'
    return 0
  fi
  return 1
}

# Case-insensitive glob existence check for wheel filename validation.
glob_exists_ci() {
  local pattern="$1"
  local had_nocaseglob=0
  shopt -q nocaseglob && had_nocaseglob=1
  shopt -s nocaseglob
  compgen -G "$pattern" >/dev/null 2>&1
  local rc=$?
  if [[ "$had_nocaseglob" -eq 1 ]]; then
    shopt -s nocaseglob
  else
    shopt -u nocaseglob
  fi
  return "$rc"
}

print_wheel_candidates() {
  local wheel_dir="$1"
  echo "INFO: candidate wheel files in ${wheel_dir}:" >&2
  if [[ ! -d "$wheel_dir" ]]; then
    echo "INFO: wheel directory missing: ${wheel_dir}" >&2
    return 0
  fi
  (
    cd "$wheel_dir" >/dev/null 2>&1 || exit 0
    ls -1 *.whl 2>/dev/null || ls -1 2>/dev/null || true
  ) | sed '/^[[:space:]]*$/d' >&2
}

NUMPY_POLICY_VERSION="1.26.4"
NUMPY_POLICY_SPEC="numpy==${NUMPY_POLICY_VERSION}"
OPENCV_HEADLESS_POLICY_VERSION="4.8.1.78"
OPENCV_HEADLESS_POLICY_SPEC="opencv-python-headless==${OPENCV_HEADLESS_POLICY_VERSION}"
LOCKFILE_NAME="requirements.lock.txt"
LOCKFILE_REL_PATH="deploy/python-assets/${LOCKFILE_NAME}"
ROOT_LOCKFILE_NAME="requirements.lock.txt"
LOCK_POLICY_NAME="root-canonical-deploy-linux-target"
PYTHON_SUPPORTED_ARCHES="aarch64-cp312"
PYTHON_UNSUPPORTED_ARCHES="armv7-cp312"
PYTHON_ARMV7_FAILURE_POLICY="install-refuse"
PYTHON_ARMV7_BLOCKER="depthai==2.30.0.0"
PIP_EXTRA_INDEX_URL="https://www.piwheels.org/simple"
PYTHON312_PINNED_VERSION="3.12.13"
PY312_STANDALONE_TAG="20260303"
PY312_STANDALONE_FULL_FILE="cpython-3.12.13+20260303-aarch64-unknown-linux-gnu-install_only.tar.gz"
PY312_STANDALONE_STRIPPED_FILE="cpython-3.12.13+20260303-aarch64-unknown-linux-gnu-install_only_stripped.tar.gz"
PY312_STANDALONE_FULL_URL="https://github.com/astral-sh/python-build-standalone/releases/download/${PY312_STANDALONE_TAG}/${PY312_STANDALONE_FULL_FILE}"
PY312_STANDALONE_STRIPPED_URL="https://github.com/astral-sh/python-build-standalone/releases/download/${PY312_STANDALONE_TAG}/${PY312_STANDALONE_STRIPPED_FILE}"
PY312_STANDALONE_SUMS_URL="https://github.com/astral-sh/python-build-standalone/releases/download/${PY312_STANDALONE_TAG}/SHA256SUMS"
RUNTIME_PREFIX_PREFERRED="/data/peoplecounter/runtime"
CANONICAL_SCRIPT_WIN='C:\Users\PC-DPETRUSCA\Documents\depthai_main_github\PeopleTrackerDepthAI\artifact_wifi_3.sh'
CANONICAL_SCRIPT_UNC='\\10.5.6.251\smb_truenas\Public\Entrance Counter\Official manuals\artifact_wifi_3.sh'

sync_canonical_script_to_unc() {
  local ps_cmd=""
  local ps_cmd_runner=""
  local -a ps_args=()
  if [[ "${SYNC_CANONICAL_TO_UNC}" != "1" ]]; then
    echo ">>> BUILD_STAGE_SYNC: optional UNC sync disabled (set SYNC_CANONICAL_TO_UNC=1 to enable)."
    return 0
  fi

  if command -v pwsh >/dev/null 2>&1; then
    ps_cmd_runner="pwsh"
  elif command -v powershell.exe >/dev/null 2>&1; then
    ps_cmd_runner="powershell.exe"
  else
    echo "WARNING: neither pwsh nor powershell.exe is available; skipping optional UNC sync." >&2
    return 0
  fi

  ps_cmd="$(cat <<PSS
\$ErrorActionPreference='Stop'
\$src='${CANONICAL_SCRIPT_WIN}'
\$dst='${CANONICAL_SCRIPT_UNC}'
if (-not (Test-Path -LiteralPath \$src)) { throw \"Canonical script not found: \$src\" }
\$dstDir = Split-Path -Parent \$dst
if (-not (Test-Path -LiteralPath \$dstDir)) { throw \"UNC parent directory not found: \$dstDir\" }
Copy-Item -LiteralPath \$src -Destination \$dst -Force
\$srcHash = (Get-FileHash -Algorithm SHA256 -LiteralPath \$src).Hash.ToLowerInvariant()
\$dstHash = (Get-FileHash -Algorithm SHA256 -LiteralPath \$dst).Hash.ToLowerInvariant()
if (\$srcHash -ne \$dstHash) { throw \"Hash mismatch after sync: \$srcHash != \$dstHash\" }
Write-Output \"canonical_sync_sha256=\$srcHash\"
PSS
)"

  if [[ "$ps_cmd_runner" == "pwsh" ]]; then
    ps_args=(-NoProfile -NonInteractive -Command "$ps_cmd")
  else
    ps_args=(-NoProfile -NonInteractive -ExecutionPolicy Bypass -Command "$ps_cmd")
  fi

  echo ">>> BUILD_STAGE_SYNC: syncing canonical script to UNC path via ${ps_cmd_runner}"
  if ! "$ps_cmd_runner" "${ps_args[@]}"; then
    echo "WARNING: optional canonical script sync to UNC failed; build artifact remains valid." >&2
    return 0
  fi
  return 0
}

# ----------------------------
# Download wifi-connect assets at BUILD TIME (device can be offline)
# ----------------------------
ASSETS_DIR="$WORK/wifi-connect-assets"
mkdir -p "$ASSETS_DIR"

base="https://github.com/balena-os/wifi-connect/releases"
partial="download/${WIFI_CONNECT_VERSION}"

bin_aarch64="wifi-connect-aarch64-unknown-linux-gnu.tar.gz"
bin_armv7="wifi-connect-armv7-unknown-linux-gnueabihf.tar.gz"
ui_tgz="wifi-connect-ui.tar.gz"

echo ">>> BUILD_STAGE_WIFI_ASSETS: downloading pinned wifi-connect assets (build-time internet allowed)"
curl -fL --retry 3 --retry-delay 2 -o "$ASSETS_DIR/$bin_aarch64" "$base/$partial/$bin_aarch64"
curl -fL --retry 3 --retry-delay 2 -o "$ASSETS_DIR/$bin_armv7"  "$base/$partial/$bin_armv7"
curl -fL --retry 3 --retry-delay 2 -o "$ASSETS_DIR/$ui_tgz"      "$base/$partial/$ui_tgz"

# Validate archives properly
for f in "$ASSETS_DIR/$bin_aarch64" "$ASSETS_DIR/$bin_armv7" "$ASSETS_DIR/$ui_tgz"; do
  if ! validate_tgz "$f"; then
    echo "ERROR: archive is not a valid .tar.gz: $f" >&2
    exit 2
  fi
done

# Validate expected binary content (UI layout can change, so we DON'T enforce index.html here)
if ! tar -tzf "$ASSETS_DIR/$bin_aarch64" | grep -qE '(^|/)wifi-connect$'; then
  echo "ERROR: $bin_aarch64 does not contain wifi-connect binary" >&2
  exit 2
fi
if ! tar -tzf "$ASSETS_DIR/$bin_armv7" | grep -qE '(^|/)wifi-connect$'; then
  echo "ERROR: $bin_armv7 does not contain wifi-connect binary" >&2
  exit 2
fi

# ----------------------------
# Copy source -> payload
# ----------------------------
PAYLOAD_DIR="$WORK/payload"
mkdir -p "$PAYLOAD_DIR"

if command -v rsync >/dev/null 2>&1; then
  rsync -a --delete \
    --exclude ".git/" --exclude "dist/" --exclude "build/" --exclude ".venv/" --exclude "venv/" \
    --exclude "__pycache__/" --exclude ".mypy_cache/" --exclude ".pytest_cache/" --exclude ".cache/" \
    --exclude "node_modules/" --exclude "*.mender" --exclude "data/" --exclude "logs/" \
    "$SRC"/ "$PAYLOAD_DIR"/
else
  (
    cd "$SRC"
    tar -cf - \
      --exclude-vcs \
      --exclude='./dist' --exclude='./build' --exclude='./.venv' --exclude='./venv' \
      --exclude='./__pycache__' --exclude='./.mypy_cache' --exclude='./.pytest_cache' \
      --exclude='./.cache' --exclude='./node_modules' --exclude='./*.mender' \
      --exclude='./data' --exclude='./logs' \
      .
  ) | ( cd "$PAYLOAD_DIR"; tar -xf - )
fi

bundle_python_assets() {
  local payload="$1"
  local src="$2"
  local py_assets="$payload/deploy/python-assets"
  local wheels_root="$py_assets/wheels"
  local wheelhouse_target="aarch64-cp312"
  local wheels_dir="$wheels_root/$wheelhouse_target"
  local req_file="$payload/requirements.txt"
  local root_lock_file="$payload/$ROOT_LOCKFILE_NAME"
  local req_download_file="$py_assets/requirements.download.txt"
  local lock_file="$py_assets/$LOCKFILE_NAME"
  local prebuilt_tar="$py_assets/prebuilt-venv.tar.gz"
  local py312_ver_file="$py_assets/python-3.12-version.txt"
  local py312_standalone_full_tgz="$py_assets/python312-standalone-aarch64-full.tar.gz"
  local py312_standalone_full_sha_file="$py_assets/python312-standalone-aarch64-full.sha256"
  local py312_standalone_stripped_tgz="$py_assets/python312-standalone-aarch64-stripped.tar.gz"
  local py312_standalone_stripped_sha_file="$py_assets/python312-standalone-aarch64-stripped.sha256"
  local py312_standalone_sums_file="$WORK/python312-standalone-SHA256SUMS"
  local py312_version="$PYTHON312_PINNED_VERSION"
  local py312_standalone="no"
  local py312_standalone_full="no"
  local py312_standalone_stripped="no"
  local py312_standalone_full_sha=""
  local py312_standalone_stripped_sha=""
  local build_py=""
  local candidate=""
  local wheel_count="0"
  local wheelhouse_required_ok="no"
  local lock_sha256=""
  local lock_entry_count="0"
  local root_lock_sha256=""
  local root_lock_entry_count="0"
  local -a required_exact_wheels=(
    "numpy-${NUMPY_POLICY_VERSION}-*.whl"
    "opencv_python_headless-${OPENCV_HEADLESS_POLICY_VERSION}-*.whl"
    "depthai-2.30.0.0-*.whl"
    "depthai_sdk-1.9.1.1-*.whl"
    "pyturbojpeg-1.6.4-*.whl"
  )
  local -a required_exact_lock_specs=(
    "numpy==${NUMPY_POLICY_VERSION}"
    "opencv-python-headless==${OPENCV_HEADLESS_POLICY_VERSION}"
    "depthai==2.30.0.0"
    "depthai-sdk==1.9.1.1"
    "pyturbojpeg==1.6.4"
  )

  [[ -s "$req_file" ]] || {
    echo "ERROR: requirements.txt missing or empty in payload: $req_file" >&2
    exit 2
  }
  [[ -s "$root_lock_file" ]] || {
    echo "ERROR: root requirements lock missing or empty in payload: $root_lock_file" >&2
    exit 2
  }

  mkdir -p "$wheels_dir"

  has_required_exact_wheels() {
    local pattern=""
    for pattern in "${required_exact_wheels[@]}"; do
      if ! glob_exists_ci "$wheels_dir/$pattern"; then
        echo "ERROR: missing required pinned wheel pattern: $pattern" >&2
        print_wheel_candidates "$wheels_dir"
        return 1
      fi
    done
    return 0
  }

  has_required_exact_lock_specs() {
    local spec=""
    for spec in "${required_exact_lock_specs[@]}"; do
      if ! grep -q -E "^${spec}$" "$lock_file"; then
        echo "ERROR: lock file missing required pinned spec: $spec" >&2
        return 1
      fi
    done
    return 0
  }

  validate_lock_intent() {
    local mode="$1"
    local req_path="$2"
    local canonical_lock_path="$3"
    local deploy_lock_path="${4:-}"
    "$build_py" - "$mode" "$req_path" "$canonical_lock_path" "$deploy_lock_path" <<'PY'
import pathlib
import sys

try:
    from packaging.markers import default_environment
    from packaging.requirements import Requirement
    from packaging.utils import canonicalize_name
except Exception:
    from pip._vendor.packaging.markers import default_environment
    from pip._vendor.packaging.requirements import Requirement
    from pip._vendor.packaging.utils import canonicalize_name


def load_requirements(path: pathlib.Path):
    entries = []
    with path.open("r", encoding="utf-8") as fh:
        for line_no, raw in enumerate(fh, start=1):
            line = raw.strip()
            if not line or line.startswith("#"):
                continue
            try:
                req = Requirement(line)
            except Exception as exc:
                raise SystemExit(f"{path}:{line_no}: invalid requirement '{line}': {exc}")
            entries.append((line_no, req, line))
    return entries


def exact_locked_version(req: Requirement, label: str, raw_line: str) -> str:
    specs = list(req.specifier)
    if len(specs) != 1 or specs[0].operator != "==":
        raise SystemExit(f"{label}: lock entry must be exact-pinned: {raw_line}")
    return specs[0].version


def build_env(platform_system: str, os_name: str, sys_platform: str) -> dict[str, str]:
    env = default_environment()
    env.update(
        {
            "platform_system": platform_system,
            "os_name": os_name,
            "sys_platform": sys_platform,
            "python_version": "3.12",
            "python_full_version": "3.12.13",
            "platform_python_implementation": "CPython",
            "implementation_name": "cpython",
        }
    )
    return env


def active_locked_map(entries, env: dict[str, str], label: str) -> dict[str, str]:
    active = {}
    for _, req, raw_line in entries:
        if req.marker and not req.marker.evaluate(env):
            continue
        name = canonicalize_name(req.name)
        version = exact_locked_version(req, label, raw_line)
        existing = active.get(name)
        if existing and existing != version:
            raise SystemExit(f"{label}: conflicting active pinned versions for {name}: {existing} vs {version}")
        active[name] = version
    return active


def validate_direct_requirements(requirements, locked_map, env: dict[str, str], env_label: str, lock_label: str) -> list[str]:
    errors = []
    missing = []
    mismatched = []
    for _, req, _ in requirements:
        if req.marker and not req.marker.evaluate(env):
            continue
        name = canonicalize_name(req.name)
        actual_version = locked_map.get(name)
        if actual_version is None:
            missing.append(name)
            continue
        if req.specifier and actual_version not in req.specifier:
            mismatched.append((name, str(req.specifier), actual_version))
    if missing:
        errors.append(f"missing direct requirements in {lock_label} [{env_label}]: {','.join(sorted(set(missing)))}")
    for name, expected, actual in mismatched:
        errors.append(f"mismatch in {lock_label} [{env_label}] for {name}: expected {expected}, got {actual}")
    return errors


mode = sys.argv[1]
req_path = pathlib.Path(sys.argv[2])
root_lock_path = pathlib.Path(sys.argv[3])
deploy_lock_path = pathlib.Path(sys.argv[4]) if len(sys.argv) > 4 and sys.argv[4] else None

requirements = load_requirements(req_path)
root_lock_entries = load_requirements(root_lock_path)

linux_env = build_env("Linux", "posix", "linux")
windows_env = build_env("Windows", "nt", "win32")

errors = []
if mode == "root":
    errors.extend(
        validate_direct_requirements(
            requirements,
            active_locked_map(root_lock_entries, linux_env, f"root lock ({root_lock_path})"),
            linux_env,
            "linux-cp312",
            "root lock",
        )
    )
    errors.extend(
        validate_direct_requirements(
            requirements,
            active_locked_map(root_lock_entries, windows_env, f"root lock ({root_lock_path})"),
            windows_env,
            "windows-cp312",
            "root lock",
        )
    )
elif mode == "deploy":
    if deploy_lock_path is None:
        raise SystemExit("deploy validation requires deploy lock path")
    deploy_lock_entries = load_requirements(deploy_lock_path)
    errors.extend(
        validate_direct_requirements(
            requirements,
            active_locked_map(deploy_lock_entries, linux_env, f"deploy lock ({deploy_lock_path})"),
            linux_env,
            "linux-cp312",
            "deploy lock",
        )
    )
else:
    raise SystemExit(f"unsupported validation mode: {mode}")

if errors:
    for item in errors:
        print(item)
    raise SystemExit(1)
PY
  }

  for candidate in "$src/venv" "$src/.venv"; do
    [[ -d "$candidate" ]] || continue
    if [[ -x "$candidate/bin/python" && -f "$candidate/pyvenv.cfg" ]]; then
      echo ">>> BUILD_STAGE_PYTHON_ASSETS: found Linux-compatible prebuilt venv candidate: $candidate"
      tar -C "$candidate" -czf "$prebuilt_tar" .
      break
    fi
    if [[ -f "$candidate/Scripts/python.exe" ]]; then
      echo "WARNING: skipping Windows-style venv candidate: $candidate" >&2
      continue
    fi
    echo "WARNING: skipping non-compatible venv candidate: $candidate" >&2
  done

  if [[ -s "$prebuilt_tar" ]]; then
    echo ">>> BUILD_STAGE_PYTHON_ASSETS: included prebuilt venv archive: $prebuilt_tar"
  else
    echo ">>> BUILD_STAGE_PYTHON_ASSETS: no Linux-compatible prebuilt venv archive included."
  fi

  if command -v python3.12 >/dev/null 2>&1; then
    build_py="python3.12"
  elif command -v python3.11 >/dev/null 2>&1; then
    build_py="python3.11"
  elif command -v python3 >/dev/null 2>&1; then
    build_py="python3"
  fi

  if [[ -n "$build_py" ]]; then
    if ! validate_lock_intent "root" "$req_file" "$root_lock_file"; then
      echo "ERROR: root lock validation failed against requirements.txt direct dependency intent." >&2
      exit 2
    fi

    rm -rf "$wheels_dir"
    mkdir -p "$wheels_dir"
    local -a download_args=(
      -m pip download
      --dest "$wheels_dir"
      --platform manylinux_2_28_aarch64
      --platform manylinux2014_aarch64
      --implementation cp
      --python-version 312
      --abi cp312
      --abi abi3
      --only-binary=:all:
      --prefer-binary
      --extra-index-url "$PIP_EXTRA_INDEX_URL"
    )
    if "$build_py" -m pip --version >/dev/null 2>&1 || "$build_py" -m ensurepip --upgrade >/dev/null 2>&1; then
      echo ">>> BUILD_STAGE_WHEELHOUSE: building deterministic arm64 wheelhouse with $build_py"
      cp -f "$req_file" "$req_download_file"
      {
        echo ""
        echo "# enforced pinned policies for offline install"
        echo "$NUMPY_POLICY_SPEC"
        echo "$OPENCV_HEADLESS_POLICY_SPEC"
        echo "PyTurboJPEG==1.6.4"
      } >> "$req_download_file"

      if ! "$build_py" "${download_args[@]}" -r "$req_download_file"; then
        echo "ERROR: deterministic wheelhouse download failed for pinned dependency set." >&2
        exit 2
      fi
      rm -f "$req_download_file" >/dev/null 2>&1 || true

      if ! has_required_exact_wheels; then
        echo "ERROR: deterministic wheelhouse does not contain required pinned wheel files." >&2
        exit 2
      fi

      if ! "$build_py" - "$wheels_dir" "$lock_file" <<'PY'
import email
import pathlib
import sys
import zipfile

wheels_dir = pathlib.Path(sys.argv[1])
lock_path = pathlib.Path(sys.argv[2])
wheels = sorted(wheels_dir.glob("*.whl"))
if not wheels:
    raise SystemExit("wheelhouse is empty")

resolved = {}
for wheel in wheels:
    with zipfile.ZipFile(wheel) as zf:
        metadata_path = next((name for name in zf.namelist() if name.endswith(".dist-info/METADATA")), None)
        if not metadata_path:
            raise SystemExit(f"wheel missing METADATA: {wheel.name}")
        msg = email.message_from_bytes(zf.read(metadata_path))
    name = (msg.get("Name") or "").strip()
    version = (msg.get("Version") or "").strip()
    if not name or not version:
        raise SystemExit(f"wheel metadata missing Name/Version: {wheel.name}")
    norm_name = name.lower().replace("_", "-")
    existing = resolved.get(norm_name)
    if existing and existing != version:
        raise SystemExit(f"multiple versions present for {norm_name}: {existing} vs {version}")
    resolved[norm_name] = version

with lock_path.open("w", encoding="utf-8", newline="\n") as fh:
    for pkg in sorted(resolved):
        fh.write(f"{pkg}=={resolved[pkg]}\n")
PY
      then
        echo "ERROR: failed to build deterministic requirements lock file from wheelhouse." >&2
        exit 2
      fi

      has_required_exact_lock_specs || exit 2

      if ! validate_lock_intent "deploy" "$req_file" "$root_lock_file" "$lock_file"; then
        echo "ERROR: deploy lock validation failed against Linux target dependency intent." >&2
        exit 2
      fi

      wheelhouse_required_ok="yes"
      echo ">>> BUILD_STAGE_WHEELHOUSE_POLICY: armv7 Python assets are unsupported with current pins; blocker=${PYTHON_ARMV7_BLOCKER}"
    else
      echo "ERROR: pip unavailable for $build_py; cannot build deterministic wheelhouse." >&2
      exit 2
    fi
  else
    echo "ERROR: no python3.12/python3.11/python3 on build host; cannot build deterministic wheelhouse." >&2
    exit 2
  fi

  fetch_expected_sha_from_sums() {
    local filename="$1"
    awk -v f="$filename" '$2==f{print tolower($1); exit}' "$py312_standalone_sums_file" 2>/dev/null || true
  }

  download_and_validate_standalone_variant() {
    local label="$1"
    local url="$2"
    local output_tgz="$3"
    local output_sha_file="$4"
    local expected_sha="$5"
    local actual_sha=""

    [[ -n "$expected_sha" ]] || {
      echo "WARNING: no expected SHA256 resolved for standalone variant '$label'." >&2
      return 1
    }
    if ! curl -fL --retry 5 --retry-delay 2 -o "$output_tgz" "$url" >/dev/null 2>&1; then
      echo "WARNING: failed downloading standalone variant '$label' from $url" >&2
      rm -f "$output_tgz" "$output_sha_file" >/dev/null 2>&1 || true
      return 1
    fi
    if ! tar -tzf "$output_tgz" >/dev/null 2>&1; then
      echo "WARNING: standalone variant '$label' archive is invalid: $output_tgz" >&2
      rm -f "$output_tgz" "$output_sha_file" >/dev/null 2>&1 || true
      return 1
    fi
    actual_sha="$(sha256_file "$output_tgz" || true)"
    if [[ -z "$actual_sha" || "$actual_sha" != "$expected_sha" ]]; then
      echo "WARNING: standalone variant '$label' SHA mismatch. expected=$expected_sha actual=${actual_sha:-missing}" >&2
      rm -f "$output_tgz" "$output_sha_file" >/dev/null 2>&1 || true
      return 1
    fi
    printf '%s  %s\n' "$expected_sha" "$(basename "$output_tgz")" > "$output_sha_file"
    return 0
  }

  echo ">>> BUILD_STAGE_PYTHON_STANDALONE: downloading standalone CPython SHA256SUMS (${PY312_STANDALONE_TAG})"
  curl -fL --retry 5 --retry-delay 2 -o "$py312_standalone_sums_file" "$PY312_STANDALONE_SUMS_URL" >/dev/null 2>&1 || {
    echo "ERROR: failed to download standalone SHA256SUMS: $PY312_STANDALONE_SUMS_URL" >&2
    exit 2
  }

  py312_standalone_full_sha="$(fetch_expected_sha_from_sums "$PY312_STANDALONE_FULL_FILE")"
  py312_standalone_stripped_sha="$(fetch_expected_sha_from_sums "$PY312_STANDALONE_STRIPPED_FILE")"
  [[ -n "$py312_standalone_full_sha" && -n "$py312_standalone_stripped_sha" ]] || {
    echo "ERROR: failed to resolve standalone variant checksums from SHA256SUMS." >&2
    exit 2
  }

  echo ">>> BUILD_STAGE_PYTHON_STANDALONE: downloading standalone CPython ${PYTHON312_PINNED_VERSION} assets for arm64 (full + stripped)"
  if download_and_validate_standalone_variant "full" "$PY312_STANDALONE_FULL_URL" "$py312_standalone_full_tgz" "$py312_standalone_full_sha_file" "$py312_standalone_full_sha"; then
    py312_standalone_full="yes"
    py312_standalone="yes"
  fi
  if download_and_validate_standalone_variant "stripped" "$PY312_STANDALONE_STRIPPED_URL" "$py312_standalone_stripped_tgz" "$py312_standalone_stripped_sha_file" "$py312_standalone_stripped_sha"; then
    py312_standalone_stripped="yes"
    py312_standalone="yes"
  fi
  if [[ "$py312_standalone" != "yes" ]]; then
    echo "ERROR: both standalone CPython variants are missing/invalid after download." >&2
    exit 2
  fi

  printf '%s\n' "${py312_version}" > "$py312_ver_file"

  wheel_count="$(find "$wheels_dir" -maxdepth 1 -type f 2>/dev/null | wc -l | tr -d ' ')"
  lock_sha256="$(sha256_file "$lock_file" || true)"
  lock_entry_count="$(wc -l < "$lock_file" | tr -d ' ')"
  root_lock_sha256="$(sha256_file "$root_lock_file" || true)"
  root_lock_entry_count="$(wc -l < "$root_lock_file" | tr -d ' ')"

  [[ -n "$lock_sha256" ]] || {
    echo "ERROR: failed to compute lock file checksum: $lock_file" >&2
    exit 2
  }
  [[ -n "$root_lock_sha256" ]] || {
    echo "ERROR: failed to compute root lock checksum: $root_lock_file" >&2
    exit 2
  }

  cat > "$py_assets/manifest.txt" <<MANIFEST
build_python=${build_py:-none}
build_arch=$(uname -m 2>/dev/null || echo unknown)
offline_target_install=yes
runtime_bootstrap=standalone-only
runtime_online_fallback=controlled
forbidden_runtime_paths=curl,source-build
wifi_connect_version=${WIFI_CONNECT_VERSION}
wheel_count=${wheel_count:-0}
wheelhouse_target=${wheelhouse_target}
wheelhouse_targets=${PYTHON_SUPPORTED_ARCHES}
wheelhouse_required_ok=${wheelhouse_required_ok}
wheelhouse_lock_enforced=yes
exact_wheel_validation=yes
lock_policy=${LOCK_POLICY_NAME}
root_lockfile=${ROOT_LOCKFILE_NAME}
root_lock_sha256=${root_lock_sha256}
root_lock_entry_count=${root_lock_entry_count}
deploy_lockfile=${LOCKFILE_REL_PATH}
deploy_lock_sha256=${lock_sha256}
deploy_lock_entry_count=${lock_entry_count}
python_supported_arches=${PYTHON_SUPPORTED_ARCHES}
python_unsupported_arches=${PYTHON_UNSUPPORTED_ARCHES}
python_armv7_failure_policy=${PYTHON_ARMV7_FAILURE_POLICY}
python_armv7_blocker=${PYTHON_ARMV7_BLOCKER}
python_asset_policy=arm64-only
prebuilt_venv=$( [[ -s "$prebuilt_tar" ]] && echo yes || echo no )
py312_standalone=${py312_standalone}
py312_standalone_full=${py312_standalone_full}
py312_standalone_stripped=${py312_standalone_stripped}
py312_standalone_full_sha256=${py312_standalone_full_sha:-none}
py312_standalone_stripped_sha256=${py312_standalone_stripped_sha:-none}
py312_standalone_release_tag=${PY312_STANDALONE_TAG}
py312_standalone_preferred_order=full,stripped
runtime_prefix_preferred=${RUNTIME_PREFIX_PREFERRED}
python312_source=no
python312_version=${py312_version}
generated_at_utc=$(date -u +%Y-%m-%dT%H:%M:%SZ)
MANIFEST
}

write_generated_deploy_assets() {
  local payload="$1"
  local deploy="$payload/deploy"

  mkdir -p "$deploy/bin" "$deploy/etc-default" "$deploy/systemd" "$deploy/nm-conf"

  cat > "$deploy/bin/wifi-connect-manager.sh" <<'MANAGER'
#!/usr/bin/env bash
set -Eeuo pipefail

if [[ -f /etc/default/wifi-connect-manager ]]; then
  # shellcheck disable=SC1091
  source /etc/default/wifi-connect-manager
fi

WIFI_CONNECT_BIN="${WIFI_CONNECT_BIN:-/usr/local/bin/wifi-connect-launcher}"
CHECK_INTERVAL="${CHECK_INTERVAL:-5}"
BOOT_PORTAL_WINDOW="${BOOT_PORTAL_WINDOW:-180}"
PORTAL_READY_TIMEOUT="${PORTAL_READY_TIMEOUT:-15}"
PORTAL_RESTART_GRACE="${PORTAL_RESTART_GRACE:-20}"
PORTAL_INTERFACE="${PORTAL_INTERFACE:-wlan0}"
PORTAL_SSID="${PORTAL_SSID:-VisionAI Connect}"
PORTAL_GATEWAY="${PORTAL_GATEWAY:-192.168.42.1}"
PORTAL_LISTENING_PORT="${PORTAL_LISTENING_PORT:-80}"
RESET_FLAG="${RESET_FLAG:-/data/wifi-reset.flag}"
PID_FILE="${PID_FILE:-/run/wifi-connect-manager/wifi-connect.pid}"
LOG_TAG="wifi-connect-manager"

BOOT_DEADLINE=0
PORTAL_MISSING_SINCE=0
WIFI_STATE=""
SHUTTING_DOWN=0
MANAGER_PID="$$"

if [[ "${WIFI_CONNECT_MANAGER_SOURCE_ONLY:-0}" != "1" ]]; then
  mkdir -p "$(dirname "$PID_FILE")"
  mkdir -p /data
fi

log() {
  echo "[$LOG_TAG] $*"
  logger -t "$LOG_TAG" "$*" || true
}

nm_ready() {
  nmcli general status >/dev/null 2>&1
}

wifi_connect_exists() {
  [[ -x "$WIFI_CONNECT_BIN" ]]
}

connection_mode_by_ref() {
  local ref="${1:-}"
  local mode=""

  [[ -n "$ref" ]] || return 1
  mode="$(
    nmcli -g 802-11-wireless.mode connection show "$ref" 2>/dev/null \
      | head -n 1 \
      | tr '[:upper:]' '[:lower:]' \
      || true
  )"
  [[ -n "$mode" ]] || return 1
  printf '%s\n' "$mode"
}

list_saved_wifi_client_uuids() {
  local uuid="" type="" mode=""

  while IFS=: read -r uuid type; do
    [[ "$type" == "802-11-wireless" && -n "$uuid" ]] || continue
    mode="$(connection_mode_by_ref "$uuid" || true)"
    [[ "$mode" == "ap" ]] && continue
    printf '%s\n' "$uuid"
  done < <(nmcli -t -f UUID,TYPE connection show 2>/dev/null || true)
}

active_wifi_client_uuid() {
  local uuid="" type="" device="" mode=""

  while IFS=: read -r uuid type device; do
    [[ "$type" == "802-11-wireless" && -n "$device" && -n "$uuid" ]] || continue
    mode="$(connection_mode_by_ref "$uuid" || true)"
    [[ "$mode" == "ap" ]] && continue
    printf '%s\n' "$uuid"
    return 0
  done < <(nmcli -t -f UUID,TYPE,DEVICE connection show --active 2>/dev/null || true)

  return 1
}

delete_all_saved_wifi_clients() {
  local uuid=""

  while IFS= read -r uuid; do
    [[ -n "$uuid" ]] || continue
    log "Deleting saved Wi-Fi profile UUID: $uuid"
    nmcli connection delete uuid "$uuid" >/dev/null 2>&1 || true
  done < <(list_saved_wifi_client_uuids)
}

disconnect_wifi_devices() {
  local dev=""

  while IFS= read -r dev; do
    [[ -n "$dev" ]] || continue
    nmcli device disconnect "$dev" >/dev/null 2>&1 || true
  done < <(nmcli -t -f DEVICE,TYPE device status 2>/dev/null | awk -F: '$2=="wifi"{print $1}')
}

pid_is_numeric() {
  [[ "${1:-}" =~ ^[0-9]+$ ]]
}

pid_is_excluded() {
  local pid="${1:-}"

  pid_is_numeric "$pid" || return 0
  [[ "$pid" == "$MANAGER_PID" || "$pid" == "${BASHPID:-$MANAGER_PID}" || "$pid" == "$PPID" ]]
}

pid_is_running() {
  local pid="${1:-}"

  pid_is_numeric "$pid" || return 1
  kill -0 "$pid" 2>/dev/null
}

pid_looks_like_wifi_connect() {
  local pid="${1:-}" comm="" exe=""

  pid_is_running "$pid" || return 1
  pid_is_excluded "$pid" && return 1

  if [[ -r "/proc/$pid/comm" ]]; then
    IFS= read -r comm < "/proc/$pid/comm" || true
    [[ "$comm" == "wifi-connect" ]] && return 0
  fi

  if [[ -L "/proc/$pid/exe" ]]; then
    exe="$(readlink -f "/proc/$pid/exe" 2>/dev/null || true)"
    [[ "$exe" == */wifi-connect ]] && return 0
  fi

  if command -v ps >/dev/null 2>&1; then
    ps -p "$pid" -o comm=,args= 2>/dev/null | awk '
      {
        comm=$1
        $1=""
        sub(/^[[:space:]]+/, "", $0)
        if (comm == "wifi-connect") found=1
        else if ($0 ~ /(^|[[:space:]])\/usr\/local\/bin\/wifi-connect([[:space:]]|$)/) found=1
      }
      END { exit found ? 0 : 1 }
    '
    return $?
  fi

  return 1
}

list_wifi_connect_candidate_pids() {
  if command -v pgrep >/dev/null 2>&1; then
    pgrep -x wifi-connect 2>/dev/null || true
    return 0
  fi

  if command -v ps >/dev/null 2>&1; then
    ps -eo pid=,comm=,args= 2>/dev/null | awk '
      {
        pid=$1
        comm=$2
        $1=""
        $2=""
        sub(/^[[:space:]]+/, "", $0)
        if (comm == "wifi-connect" || $0 ~ /(^|[[:space:]])\/usr\/local\/bin\/wifi-connect([[:space:]]|$)/) {
          print pid
        }
      }
    '
  fi
}

list_wifi_connect_pids() {
  local pid=""

  while IFS= read -r pid; do
    pid="${pid//[[:space:]]/}"
    [[ -n "$pid" ]] || continue
    pid_is_numeric "$pid" || continue
    pid_is_excluded "$pid" && continue
    pid_looks_like_wifi_connect "$pid" || continue
    printf '%s\n' "$pid"
  done < <(list_wifi_connect_candidate_pids | sort -u)
}

read_valid_wifi_connect_pidfile() {
  local pid=""

  [[ -f "$PID_FILE" ]] || return 1
  pid="$(tr -d '[:space:]' < "$PID_FILE" 2>/dev/null || true)"
  pid_is_numeric "$pid" || {
    rm -f "$PID_FILE"
    return 1
  }
  pid_looks_like_wifi_connect "$pid" || {
    rm -f "$PID_FILE"
    return 1
  }

  printf '%s\n' "$pid"
}

current_wifi_connect_pid() {
  local pid=""

  pid="$(read_valid_wifi_connect_pidfile || true)"
  if [[ -n "$pid" ]]; then
    printf '%s\n' "$pid"
    return 0
  fi

  pid="$(list_wifi_connect_pids | head -n 1 || true)"
  if [[ -n "$pid" ]]; then
    printf '%s\n' "$pid" > "$PID_FILE"
    printf '%s\n' "$pid"
    return 0
  fi

  return 1
}

portal_process_running() {
  current_wifi_connect_pid >/dev/null 2>&1
}

active_portal_connection_uuid() {
  local name="" uuid="" type="" device="" mode=""

  while IFS=: read -r name uuid type device; do
    [[ "$type" == "802-11-wireless" && "$device" == "$PORTAL_INTERFACE" && -n "$uuid" ]] || continue
    mode="$(connection_mode_by_ref "$uuid" || true)"
    [[ "$mode" == "ap" ]] || continue
    printf '%s\n' "$uuid"
    return 0
  done < <(nmcli -t -f NAME,UUID,TYPE,DEVICE connection show --active 2>/dev/null || true)

  return 1
}

portal_connection_name_by_uuid() {
  local uuid="${1:-}"

  [[ -n "$uuid" ]] || return 1
  nmcli -t -f NAME,UUID connection show 2>/dev/null | awk -F: -v u="$uuid" '$2==u{print $1; exit}'
}

portal_ap_active() {
  [[ -n "$(active_portal_connection_uuid || true)" ]]
}

portal_listener_ready() {
  local listener_spec="${PORTAL_GATEWAY}:${PORTAL_LISTENING_PORT}"

  if ! command -v ss >/dev/null 2>&1; then
    return 1
  fi

  ss -H -ltnp 2>/dev/null | awk -v spec="$listener_spec" '$4 == spec {found=1} END{exit found ? 0 : 1}'
}

portal_has_any_state() {
  portal_process_running || portal_ap_active || portal_listener_ready
}

portal_running() {
  portal_has_any_state
}

cleanup_pidfile_if_dead() {
  read_valid_wifi_connect_pidfile >/dev/null 2>&1 || true
}

stop_lingering_wifi_connect() {
  local pids="" pid=""

  pids="$(list_wifi_connect_pids || true)"
  [[ -n "$pids" ]] || return 0

  log "Stopping lingering wifi-connect process(es): $pids"
  for pid in $pids; do
    kill "$pid" 2>/dev/null || true
  done

  sleep 2

  for pid in $pids; do
    kill -0 "$pid" 2>/dev/null && kill -9 "$pid" 2>/dev/null || true
  done

  rm -f "$PID_FILE"
}

stop_portal_connection() {
  local portal_uuid="" portal_name=""

  portal_uuid="$(active_portal_connection_uuid || true)"
  [[ -n "$portal_uuid" ]] || return 0

  portal_name="$(portal_connection_name_by_uuid "$portal_uuid" || true)"
  if [[ -n "$portal_name" ]]; then
    log "Stopping active portal connection: $portal_name ($portal_uuid)"
  else
    log "Stopping active portal connection UUID: $portal_uuid"
  fi

  nmcli connection down uuid "$portal_uuid" >/dev/null 2>&1 || true
}

log_socket_owners() {
  local out="" line=""

  if ! command -v ss >/dev/null 2>&1; then
    return 0
  fi

  out="$(ss -H -lunp 2>/dev/null | awk '$5 ~ /:53$/ || $5 ~ /:67$/ {print}' || true)"
  [[ -n "$out" ]] || return 0

  log "UDP listeners on :53/:67:"
  while IFS= read -r line; do
    [[ -n "$line" ]] && log "  $line"
  done <<<"$out"
}

start_portal() {
  local reason="${1:-manual}"
  local pid=""
  local waited=0

  cleanup_pidfile_if_dead

  if portal_running; then
    PORTAL_MISSING_SINCE=0
    return 0
  fi

  if portal_has_any_state; then
    log "Detected stale hotspot state. Cleaning up before relaunch."
    stop_lingering_wifi_connect
    stop_portal_connection
    rm -f "$PID_FILE"
  fi

  log "Starting wifi-connect portal (${reason})"
  "$WIFI_CONNECT_BIN" &
  echo $! > "$PID_FILE"
  PORTAL_MISSING_SINCE=0

  while (( waited < PORTAL_READY_TIMEOUT )); do
    sleep 1
    waited=$((waited + 1))

    pid="$(current_wifi_connect_pid || true)"
    if [[ -z "$pid" ]]; then
      log "wifi-connect exited before hotspot became ready."
      log_socket_owners
      rm -f "$PID_FILE"
      return 1
    fi

    if portal_ap_active || portal_listener_ready; then
      return 0
    fi
  done

  pid="$(current_wifi_connect_pid || true)"
  if [[ -n "$pid" ]]; then
    log "wifi-connect is still starting; hotspot readiness not confirmed within ${PORTAL_READY_TIMEOUT}s. Keeping it running."
    return 0
  fi

  log "wifi-connect exited before hotspot became ready."
  log_socket_owners
  rm -f "$PID_FILE"
  return 1
}

stop_portal() {
  local pid=""

  cleanup_pidfile_if_dead
  pid="$(current_wifi_connect_pid || true)"
  if [[ -n "$pid" ]]; then
    log "Stopping wifi-connect (pid=$pid)"
    kill "$pid" 2>/dev/null || true

    for _ in 1 2 3 4 5; do
      sleep 1
      if ! kill -0 "$pid" 2>/dev/null; then
        rm -f "$PID_FILE"
        break
      fi
    done

    if [[ -f "$PID_FILE" ]]; then
      kill -9 "$pid" 2>/dev/null || true
      rm -f "$PID_FILE"
    fi
  else
    stop_lingering_wifi_connect
  fi

  stop_portal_connection
  PORTAL_MISSING_SINCE=0
}

boot_elapsed_seconds() {
  local seconds=""

  if [[ -r /proc/uptime ]]; then
    seconds="$(awk '{print int($1)}' /proc/uptime 2>/dev/null || true)"
  fi

  if ! [[ "$seconds" =~ ^[0-9]+$ ]]; then
    seconds=0
  fi

  printf '%s\n' "$seconds"
}

transition_wifi_state() {
  local new_state="$1"
  local reason="${2:-}"
  local now="${3:-$(date +%s)}"
  local previous_state="${WIFI_STATE:-INIT}"
  local remaining=0
  local force=0

  if [[ "$reason" == "manual-reset" ]]; then
    force=1
  fi

  if [[ "$WIFI_STATE" == "$new_state" && "$force" -eq 0 ]]; then
    return 1
  fi

  WIFI_STATE="$new_state"
  log "state transition: ${previous_state} -> ${new_state}${reason:+ (${reason})}"

  case "$new_state" in
    BOOT_WINDOW)
      PORTAL_MISSING_SINCE=0
      if (( BOOT_DEADLINE > now )); then
        remaining=$((BOOT_DEADLINE - now))
      fi
      disconnect_wifi_devices
      if start_portal "${reason:-boot}"; then
        log "boot hotspot window active for ${remaining}s"
      else
        log "WARNING: failed to start boot hotspot"
      fi
      ;;
    IDLE)
      stop_portal
      PORTAL_MISSING_SINCE=0
      log "boot hotspot window ended; hotspot stopped"
      ;;
    *)
      log "WARNING: unknown Wi-Fi state requested: $new_state"
      return 1
      ;;
  esac

  return 0
}

handle_reset_flag() {
  local now="${1:-$(date +%s)}"

  if [[ -f "$RESET_FLAG" ]]; then
    log "Manual reset flag detected: $RESET_FLAG"
    rm -f "$RESET_FLAG" || true
    delete_all_saved_wifi_clients
    disconnect_wifi_devices
    BOOT_DEADLINE=$((now + BOOT_PORTAL_WINDOW))
    transition_wifi_state "BOOT_WINDOW" "manual-reset" "$now" || true
    return 0
  fi

  return 1
}

manager_tick() {
  local now="${1:-$(date +%s)}"
  local active_wifi_uuid=""

  cleanup_pidfile_if_dead

  if handle_reset_flag "$now"; then
    return 0
  fi

  case "$WIFI_STATE" in
    BOOT_WINDOW)
      if (( now >= BOOT_DEADLINE )); then
        log "boot window expired"
        transition_wifi_state "IDLE" "boot-window-expired" "$now" || true
        return 0
      fi

      if portal_running; then
        PORTAL_MISSING_SINCE=0
        return 0
      fi

      active_wifi_uuid="$(active_wifi_client_uuid || true)"
      if [[ -n "$active_wifi_uuid" ]]; then
        if (( PORTAL_MISSING_SINCE == 0 )); then
          PORTAL_MISSING_SINCE="$now"
          log "Wi-Fi client connection detected during boot window; leaving hotspot off"
        fi
        return 0
      fi

      if (( PORTAL_MISSING_SINCE == 0 )); then
        PORTAL_MISSING_SINCE="$now"
        log "hotspot is not active during boot window; waiting ${PORTAL_RESTART_GRACE}s before restart"
        return 0
      fi

      if (( now - PORTAL_MISSING_SINCE < PORTAL_RESTART_GRACE )); then
        return 0
      fi

      log "restarting hotspot during active boot window"
      if start_portal "boot-restart"; then
        PORTAL_MISSING_SINCE=0
      else
        PORTAL_MISSING_SINCE="$now"
      fi
      return 0
      ;;
    IDLE)
      if portal_has_any_state; then
        stop_portal
      fi
      PORTAL_MISSING_SINCE=0
      return 0
      ;;
    *)
      if (( BOOT_DEADLINE > now )); then
        transition_wifi_state "BOOT_WINDOW" "state-recovery" "$now" || true
      else
        transition_wifi_state "IDLE" "state-recovery" "$now" || true
      fi
      return 0
      ;;
  esac
}

main() {
  local now="" boot_elapsed=0 remaining=0

  if ! command -v nmcli >/dev/null 2>&1; then
    log "ERROR: nmcli is required"
    exit 1
  fi
  if ! wifi_connect_exists; then
    log "ERROR: wifi-connect launcher missing at $WIFI_CONNECT_BIN"
    exit 1
  fi

  log "Starting manager loop"

  for _ in $(seq 1 30); do
    if nm_ready; then
      break
    fi
    sleep 1
  done

  if ! nm_ready; then
    log "ERROR: NetworkManager is not ready"
    exit 1
  fi

  now="$(date +%s)"
  boot_elapsed="$(boot_elapsed_seconds)"
  if (( boot_elapsed >= BOOT_PORTAL_WINDOW )); then
    BOOT_DEADLINE="$now"
    transition_wifi_state "IDLE" "boot-window-already-expired" "$now" || true
  else
    remaining=$((BOOT_PORTAL_WINDOW - boot_elapsed))
    BOOT_DEADLINE=$((now + remaining))
    transition_wifi_state "BOOT_WINDOW" "service-start" "$now" || true
  fi

  while true; do
    now="$(date +%s)"
    manager_tick "$now"
    sleep "$CHECK_INTERVAL"
  done
}

handle_termination_signal() {
  if (( SHUTTING_DOWN == 1 )); then
    exit 0
  fi

  SHUTTING_DOWN=1
  trap 'exit 0' SIGTERM SIGINT
  log "Received termination signal"
  stop_portal
  exit 0
}

if [[ "${WIFI_CONNECT_MANAGER_SOURCE_ONLY:-0}" != "1" ]]; then
  trap 'handle_termination_signal' SIGTERM SIGINT
  main "$@"
fi
MANAGER
  cat > "$deploy/bin/wifi-prep.sh" <<'PREP'
#!/usr/bin/env bash
set -euo pipefail

if [[ -f /etc/default/wifi-connect-manager ]]; then
  # shellcheck disable=SC1091
  source /etc/default/wifi-connect-manager
fi

IF="${PORTAL_INTERFACE:-wlan0}"
COUNTRY="${WIFI_COUNTRY:-RO}"
NM_DNS_ADJUST_FLAG="${NM_DNS_ADJUST_FLAG:-/run/wifi-connect-manager/nm-dns-adjusted.flag}"
LOG_TAG="wifi-prep"

log() {
  echo "[$LOG_TAG] $*" >&2
  logger -t "$LOG_TAG" "$*" || true
}

get_nm_dns_mode() {
  local mode=""

  if command -v NetworkManager >/dev/null 2>&1; then
    mode="$(
      NetworkManager --print-config 2>/dev/null \
      | awk -F= '/^[[:space:]]*dns[[:space:]]*=/{gsub(/[[:space:]]/,"",$2);print tolower($2);exit}' \
      || true
    )"
  fi

  if [[ -z "$mode" ]]; then
    mode="$(
      grep -h -E '^[[:space:]]*dns[[:space:]]*=' /etc/NetworkManager/NetworkManager.conf /etc/NetworkManager/conf.d/*.conf 2>/dev/null \
      | tail -n 1 \
      | awk -F= '{gsub(/[[:space:]]/,"",$2);print tolower($2)}' \
      || true
    )"
  fi

  [[ -n "$mode" ]] && printf '%s\n' "$mode" || printf 'default\n'
}

wait_for_nm_ready() {
  local _

  if command -v nmcli >/dev/null 2>&1; then
    for _ in $(seq 1 30); do
      nmcli general status >/dev/null 2>&1 && return 0
      sleep 1
    done
    return 1
  fi

  if command -v systemctl >/dev/null 2>&1; then
    for _ in $(seq 1 30); do
      systemctl is-active --quiet NetworkManager.service && return 0
      sleep 1
    done
  fi

  return 0
}

maybe_adjust_nm_dns_mode() {
  local nm_dns=""

  nm_dns="$(get_nm_dns_mode)"
  log "NetworkManager dns mode before prep remediation: $nm_dns"

  if [[ "$nm_dns" == "dnsmasq" ]]; then
    if [[ -f "$NM_DNS_ADJUST_FLAG" ]]; then
      log "dns=dnsmasq remediation already attempted for this boot/startup sequence."
    elif command -v systemctl >/dev/null 2>&1; then
      mkdir -p "$(dirname "$NM_DNS_ADJUST_FLAG")"
      touch "$NM_DNS_ADJUST_FLAG" || true
      log "NetworkManager is configured with dns=dnsmasq. Restarting once to apply dns=default conf.d override."
      systemctl restart NetworkManager >/dev/null 2>&1 || true
      if ! wait_for_nm_ready; then
        log "WARNING: NetworkManager did not report ready after dns remediation restart."
      fi
    fi

    nm_dns="$(get_nm_dns_mode)"
    log "NetworkManager dns mode after prep remediation: $nm_dns"
  fi
}

if command -v rfkill >/dev/null 2>&1; then
  rfkill unblock all || true
  rm -f /var/lib/systemd/rfkill/* 2>/dev/null || true
  rfkill unblock all || true
fi

modprobe brcmfmac 2>/dev/null || true
modprobe cfg80211 2>/dev/null || true
ip link set "$IF" up 2>/dev/null || true

if command -v iw >/dev/null 2>&1; then
  iw reg set "$COUNTRY" >/dev/null 2>&1 || true
  iw dev "$IF" set power_save off >/dev/null 2>&1 || true
fi

if command -v systemctl >/dev/null 2>&1; then
  systemctl start NetworkManager >/dev/null 2>&1 || true
fi
if ! wait_for_nm_ready; then
  log "WARNING: NetworkManager did not report ready during prep."
fi

maybe_adjust_nm_dns_mode

if command -v nmcli >/dev/null 2>&1; then
  nmcli networking on >/dev/null 2>&1 || true
  nmcli radio wifi on >/dev/null 2>&1 || true
  nmcli dev set "$IF" managed yes >/dev/null 2>&1 || true

  for _ in $(seq 1 20); do
    st="$(nmcli -t -f DEVICE,STATE dev status 2>/dev/null | awk -F: -v d="$IF" '$1==d{print $2}')"
    [[ -n "$st" && "$st" != "unavailable" ]] && break
    nmcli radio wifi on >/dev/null 2>&1 || true
    ip link set "$IF" up 2>/dev/null || true
    sleep 1
  done

  st="$(nmcli -t -f DEVICE,STATE dev status 2>/dev/null | awk -F: -v d="$IF" '$1==d{print $2}')"
  if [[ "$st" == "unavailable" ]] && command -v systemctl >/dev/null 2>&1; then
    log "wlan still unavailable, restarting NetworkManager"
    systemctl restart NetworkManager >/dev/null 2>&1 || true
    if ! wait_for_nm_ready; then
      log "WARNING: NetworkManager did not report ready after wlan recovery restart."
    fi
  fi
fi

exit 0
PREP
  cat > "$deploy/bin/wifi-connect-launcher" <<'LAUNCHER'
#!/usr/bin/env bash
set -euo pipefail

ENV=/etc/default/wifi-connect-manager
[[ -f "$ENV" ]] && source "$ENV"

export PORTAL_INTERFACE="${PORTAL_INTERFACE:-wlan0}"
export PORTAL_SSID="${PORTAL_SSID:-VisionAI Connect}"
export PORTAL_PASSPHRASE="${PORTAL_PASSPHRASE:-mender06}"
export PORTAL_GATEWAY="${PORTAL_GATEWAY:-192.168.42.1}"
export PORTAL_DHCP_RANGE="${PORTAL_DHCP_RANGE:-192.168.42.2,192.168.42.254}"
export PORTAL_LISTENING_PORT="${PORTAL_LISTENING_PORT:-80}"
export WIFI_COUNTRY="${WIFI_COUNTRY:-RO}"

/usr/local/bin/wifi-prep.sh || true

ARGS=(
  --portal-interface "$PORTAL_INTERFACE"
  --portal-ssid "$PORTAL_SSID"
  --portal-gateway "$PORTAL_GATEWAY"
  --portal-dhcp-range "$PORTAL_DHCP_RANGE"
  --portal-listening-port "$PORTAL_LISTENING_PORT"
)

if [[ -n "${PORTAL_PASSPHRASE:-}" ]]; then
  ARGS+=(--portal-passphrase "$PORTAL_PASSPHRASE")
fi

if [[ -n "${WIFI_CONNECT_ARGS:-}" ]]; then
  # shellcheck disable=SC2206
  EXTRA_ARGS=($WIFI_CONNECT_ARGS)
  ARGS+=("${EXTRA_ARGS[@]}")
fi

exec /usr/local/bin/wifi-connect "${ARGS[@]}" "$@"
LAUNCHER

  cat > "$deploy/bin/wifi-reset.sh" <<'RESET'
#!/usr/bin/env bash
set -Eeuo pipefail

mkdir -p /data
touch /data/wifi-reset.flag

echo "[wifi-reset] Flag created. Restarting wifi-connect-manager.service ..."
if command -v systemctl >/dev/null 2>&1; then
  systemctl restart wifi-connect-manager.service || true
fi
echo "[wifi-reset] Done."
RESET

  cat > "$deploy/etc-default/wifi-connect-manager" <<'WENV'
WIFI_CONNECT_BIN=/usr/local/bin/wifi-connect-launcher
CHECK_INTERVAL=5
BOOT_PORTAL_WINDOW=180
PORTAL_READY_TIMEOUT=15
PORTAL_RESTART_GRACE=20
PORTAL_INTERFACE=wlan0
PORTAL_SSID="VisionAI Connect"
PORTAL_PASSPHRASE="mender06"
PORTAL_GATEWAY=192.168.42.1
PORTAL_DHCP_RANGE=192.168.42.2,192.168.42.254
PORTAL_LISTENING_PORT=80
WIFI_COUNTRY=RO
WIFI_CONNECT_ARGS=""
RESET_FLAG=/data/wifi-reset.flag
PID_FILE=/run/wifi-connect-manager/wifi-connect.pid
NM_DNS_ADJUST_FLAG=/run/wifi-connect-manager/nm-dns-adjusted.flag
WENV

  cat > "$deploy/etc-default/peoplecounter" <<'PENV'
# Extra environment variables for PeopleCounter (optional)
# The systemd unit already uses fixed paths:
#   /data/peoplecounter/current/launch.py
#   /data/peoplecounter/venv/bin/python
# The service runs as root on the appliance, and privileged helpers
# should report/check against the same runtime identity.
TMPDIR=/data/tmp
PIP_CACHE_DIR=/data/pip-cache
PEOPLECOUNTER_SERVICE_USER=root
DJANGO_ALLOWED_HOSTS=*
DJANGO_STATIC_ROOT=/data/peoplecounter/var/staticfiles
PYTHONDONTWRITEBYTECODE=1
PYTHONPYCACHEPREFIX=/data/peoplecounter/var/pycache
ENABLE_LOCAL_PREVIEW=0
STREAM_MAX_FPS=15
STREAM_JPEG_QUALITY=85
STREAM_FIRST_FRAME_TIMEOUT_SECONDS=2
PENV

  cat > "$deploy/systemd/wifi-connect-manager.service" <<'WUNIT'
[Unit]
Description=VisionAI Connect Manager (boot-window hotspot provisioning)
After=dbus.service NetworkManager.service
Wants=NetworkManager.service

[Service]
Type=simple
EnvironmentFile=-/etc/default/wifi-connect-manager
ExecStartPre=/usr/local/bin/wifi-prep.sh
ExecStart=/usr/local/bin/wifi-connect-manager.sh
KillMode=control-group
TimeoutStopSec=10
Restart=always
RestartSec=5
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target
WUNIT

  cat > "$deploy/nm-conf/10-peoplecounter-dns.conf" <<'NM1'
[main]
dns=default
NM1

  cat > "$deploy/nm-conf/20-peoplecounter-wifi.conf" <<'NM2'
[connection]
wifi.powersave=2
NM2

  chmod 0755 \
    "$deploy/bin/wifi-connect-manager.sh" \
    "$deploy/bin/wifi-prep.sh" \
    "$deploy/bin/wifi-connect-launcher" \
    "$deploy/bin/wifi-reset.sh"
}

# Inject wifi-connect assets into payload
mkdir -p "$PAYLOAD_DIR/deploy/wifi-connect-assets"
cp -a "$ASSETS_DIR/$bin_aarch64" "$PAYLOAD_DIR/deploy/wifi-connect-assets/"
cp -a "$ASSETS_DIR/$bin_armv7"  "$PAYLOAD_DIR/deploy/wifi-connect-assets/"
cp -a "$ASSETS_DIR/$ui_tgz"     "$PAYLOAD_DIR/deploy/wifi-connect-assets/"

# Generate authoritative deploy assets (single-file build source of truth)
write_generated_deploy_assets "$PAYLOAD_DIR"
bundle_python_assets "$PAYLOAD_DIR" "$SRC"

# ----------------------------
# HARD FAIL sanity checks
# ----------------------------
[[ -s "$PAYLOAD_DIR/launch.py" ]] || { echo "ERROR: launch.py missing or empty in payload. Refusing build." >&2; exit 2; }

required_deploy=(
  "deploy/bin/wifi-connect-manager.sh"
  "deploy/bin/wifi-prep.sh"
  "deploy/bin/wifi-connect-launcher"
  "deploy/bin/wifi-reset.sh"
  "deploy/bin/peoplecounter-ensure-udev"
  "deploy/bin/peoplecounter-mender-auth-recover"
  "deploy/bin/visionai-set-ip"
  "deploy/etc-default/wifi-connect-manager"
  "deploy/etc-default/peoplecounter"
  "deploy/systemd/peoplecounter-mender-auth-recover.service"
  "deploy/systemd/peoplecounter-mender-auth-recover.timer"
  "deploy/systemd/wifi-connect-manager.service"
  "deploy/sudoers/visionai-set-ip"
  "deploy/nm-conf/10-peoplecounter-dns.conf"
  "deploy/nm-conf/20-peoplecounter-wifi.conf"
  "deploy/wifi-connect-assets/$bin_aarch64"
  "deploy/wifi-connect-assets/$bin_armv7"
  "deploy/wifi-connect-assets/$ui_tgz"
  "deploy/python-assets/manifest.txt"
  "$LOCKFILE_REL_PATH"
  "deploy/python-assets/python-3.12-version.txt"
)
[[ -s "$PAYLOAD_DIR/$ROOT_LOCKFILE_NAME" ]] || { echo "ERROR: Missing or empty root lock file: $ROOT_LOCKFILE_NAME" >&2; exit 2; }
for f in "${required_deploy[@]}"; do
  [[ -s "$PAYLOAD_DIR/$f" ]] || { echo "ERROR: Missing or empty deploy file: $f" >&2; exit 2; }
done
if ! grep -q '^wheelhouse_required_ok=yes$' "$PAYLOAD_DIR/deploy/python-assets/manifest.txt"; then
  echo "ERROR: python wheelhouse policy not satisfied (wheelhouse_required_ok!=yes)." >&2
  exit 2
fi
if ! find "$PAYLOAD_DIR/deploy/python-assets/wheels/aarch64-cp312" -maxdepth 1 -type f 2>/dev/null | grep -q .; then
  echo "ERROR: deploy/python-assets/wheels/aarch64-cp312 is empty." >&2
  exit 2
fi
if ! grep -q '^exact_wheel_validation=yes$' "$PAYLOAD_DIR/deploy/python-assets/manifest.txt"; then
  echo "ERROR: python-assets manifest missing exact_wheel_validation=yes." >&2
  exit 2
fi
if ! grep -q '^wheelhouse_lock_enforced=yes$' "$PAYLOAD_DIR/deploy/python-assets/manifest.txt"; then
  echo "ERROR: python-assets manifest missing wheelhouse_lock_enforced=yes." >&2
  exit 2
fi
if ! grep -q '^offline_target_install=yes$' "$PAYLOAD_DIR/deploy/python-assets/manifest.txt"; then
  echo "ERROR: python-assets manifest missing offline_target_install=yes." >&2
  exit 2
fi
if ! grep -q '^runtime_online_fallback=controlled$' "$PAYLOAD_DIR/deploy/python-assets/manifest.txt"; then
  echo "ERROR: python-assets manifest missing runtime_online_fallback=controlled." >&2
  exit 2
fi
if ! grep -q '^forbidden_runtime_paths=curl,source-build$' "$PAYLOAD_DIR/deploy/python-assets/manifest.txt"; then
  echo "ERROR: python-assets manifest missing forbidden_runtime_paths=curl,source-build." >&2
  exit 2
fi
if ! grep -q '^lock_policy=root-canonical-deploy-linux-target$' "$PAYLOAD_DIR/deploy/python-assets/manifest.txt"; then
  echo "ERROR: python-assets manifest missing lock_policy=root-canonical-deploy-linux-target." >&2
  exit 2
fi
if ! grep -q '^python_supported_arches=aarch64-cp312$' "$PAYLOAD_DIR/deploy/python-assets/manifest.txt"; then
  echo "ERROR: python-assets manifest missing python_supported_arches=aarch64-cp312." >&2
  exit 2
fi
if ! grep -q '^python_unsupported_arches=armv7-cp312$' "$PAYLOAD_DIR/deploy/python-assets/manifest.txt"; then
  echo "ERROR: python-assets manifest missing python_unsupported_arches=armv7-cp312." >&2
  exit 2
fi
if ! grep -q '^python_armv7_failure_policy=install-refuse$' "$PAYLOAD_DIR/deploy/python-assets/manifest.txt"; then
  echo "ERROR: python-assets manifest missing python_armv7_failure_policy=install-refuse." >&2
  exit 2
fi
if ! grep -q '^python_armv7_blocker=depthai==2.30.0.0$' "$PAYLOAD_DIR/deploy/python-assets/manifest.txt"; then
  echo "ERROR: python-assets manifest missing python_armv7_blocker=depthai==2.30.0.0." >&2
  exit 2
fi
if ! grep -q '^py312_standalone_release_tag=' "$PAYLOAD_DIR/deploy/python-assets/manifest.txt"; then
  echo "ERROR: python-assets manifest missing py312_standalone_release_tag." >&2
  exit 2
fi
if ! grep -q '^runtime_prefix_preferred=' "$PAYLOAD_DIR/deploy/python-assets/manifest.txt"; then
  echo "ERROR: python-assets manifest missing runtime_prefix_preferred." >&2
  exit 2
fi
if ! grep -q '^py312_standalone_preferred_order=' "$PAYLOAD_DIR/deploy/python-assets/manifest.txt"; then
  echo "ERROR: python-assets manifest missing py312_standalone_preferred_order." >&2
  exit 2
fi
if ! { [[ -s "$PAYLOAD_DIR/deploy/python-assets/python312-standalone-aarch64-full.tar.gz" && -s "$PAYLOAD_DIR/deploy/python-assets/python312-standalone-aarch64-full.sha256" ]] || [[ -s "$PAYLOAD_DIR/deploy/python-assets/python312-standalone-aarch64-stripped.tar.gz" && -s "$PAYLOAD_DIR/deploy/python-assets/python312-standalone-aarch64-stripped.sha256" ]]; }; then
  echo "ERROR: no valid standalone Python variant pair found in payload." >&2
  exit 2
fi
for pinned_pattern in \
  "numpy-${NUMPY_POLICY_VERSION}-*.whl" \
  "opencv_python_headless-${OPENCV_HEADLESS_POLICY_VERSION}-*.whl" \
  "depthai-2.30.0.0-*.whl" \
  "depthai_sdk-1.9.1.1-*.whl" \
  "pyturbojpeg-1.6.4-*.whl"; do
  if ! glob_exists_ci "$PAYLOAD_DIR/deploy/python-assets/wheels/aarch64-cp312/$pinned_pattern"; then
    echo "ERROR: required pinned wheel missing from payload: $pinned_pattern" >&2
    print_wheel_candidates "$PAYLOAD_DIR/deploy/python-assets/wheels/aarch64-cp312"
    exit 2
  fi
done
for pinned_spec in \
  "numpy==${NUMPY_POLICY_VERSION}" \
  "opencv-python-headless==${OPENCV_HEADLESS_POLICY_VERSION}" \
  "depthai==2.30.0.0" \
  "depthai-sdk==1.9.1.1" \
  "pyturbojpeg==1.6.4"; do
  if ! grep -qi "^${pinned_spec}$" "$PAYLOAD_DIR/$LOCKFILE_REL_PATH"; then
    echo "ERROR: lock file missing pinned spec: $pinned_spec" >&2
    exit 2
  fi
done

# ----------------------------
# Create update.tar and verify launch.py inside tar is non-empty
# ----------------------------
tar -C "$PAYLOAD_DIR" -cf "$WORK/update.tar" .

LAUNCH_PATH="$(tar -tf "$WORK/update.tar" | grep -E '(^|/)launch\.py$' | head -n 1 || true)"
[[ -n "$LAUNCH_PATH" ]] || { echo "ERROR: launch.py not found inside update.tar"; exit 2; }
LAUNCH_BYTES="$(tar -xOf "$WORK/update.tar" "$LAUNCH_PATH" | wc -c | tr -d ' ')"
[[ "${LAUNCH_BYTES:-0}" -ge 10 ]] || { echo "ERROR: launch.py too small inside tar (${LAUNCH_BYTES} bytes)."; exit 2; }

DEST_ON_TARGET="/data/peoplecounter/releases/${RELEASE_ID}/PeopleTrackerDepthAI"
echo "$DEST_ON_TARGET" > "$WORK/dest_dir"

# ----------------------------
# State scripts (run ON DEVICE)
# ----------------------------
cat > "$WORK/ArtifactInstall_Enter_00" <<'EOS'
#!/usr/bin/env bash
set -euo pipefail

if [[ "$(id -u)" -ne 0 ]]; then
  if command -v sudo >/dev/null 2>&1; then
    sudo -H -n bash "$0" "$@" || {
      echo "[peoplecounter-install-enter] ERROR: sudo re-exec failed; root is required." >&2
      exit 1
    }
    exit 0
  fi
  echo "[peoplecounter-install-enter] ERROR: must run as root and sudo is unavailable." >&2
  exit 1
fi

if command -v systemctl >/dev/null 2>&1; then
  systemctl stop peoplecounter.service >/dev/null 2>&1 || true
  systemctl stop wifi-connect-manager.service >/dev/null 2>&1 || true
fi
EOS
chmod +x "$WORK/ArtifactInstall_Enter_00"

cat > "$WORK/ArtifactInstall_Leave_50" <<'EOS'
#!/usr/bin/env bash
set -euo pipefail
log(){ echo "[peoplecounter-install] $*" >&2; }

BASE="/data/peoplecounter"
RELEASES="$BASE/releases"
RELEASE_ID="__RELEASE_ID__"
LATEST_DIR="$RELEASES/$RELEASE_ID"
ARTIFACT_VERSION="__ARTIFACT_VERSION__"
BUILD_GIT_SHA="__BUILD_GIT_SHA__"
BUILD_TS_UTC="__BUILD_TS__"

DEVICE_TYPE_FILE="/var/lib/mender/device_type"
MENDER_CONF="/etc/mender/mender.conf"

PORTAL_SSID_DEFAULT="__PORTAL_SSID__"
PORTAL_PASSPHRASE_DEFAULT="__PORTAL_PASS__"
PORTAL_INTERFACE_DEFAULT="__PORTAL_IFACE__"

LIVE_RUNTIME_VENV="$BASE/venv"
RUNTIME_VENV="$LIVE_RUNTIME_VENV"
RUNTIME_VENV_PY="$RUNTIME_VENV/bin/python"
RUNTIME_PY=""
LIVE_RUNTIME_PREFIX_PRIMARY="/data/peoplecounter/runtime"
LIVE_RUNTIME_PREFIX_FALLBACK="/opt/peoplecounter"
RUNTIME_PREFIX_PRIMARY="/data/peoplecounter/runtime-staging.$$"
RUNTIME_PREFIX_FALLBACK="/opt/peoplecounter/runtime-staging.$$"
RUNTIME_PREFIX=""
RUNTIME_PREFIX_MIN_FREE_KB=262144
PY312_STANDALONE_PREFIX=""
INSTALL_PIP_CACHE_DIR="/root/.cache/pip"
PYTHON_BOOTSTRAP_LOG="/var/log/peoplecounter-install-python.log"
PIP_LOG_FILE="/var/log/peoplecounter-install-pip.log"
REQUIREMENTS_LOCK_REL="deploy/python-assets/requirements.lock.txt"
NUMPY_VERSION="1.26.4"
NUMPY_SPEC="numpy==${NUMPY_VERSION}"
OPENCV_HEADLESS_VERSION="4.8.1.78"
OPENCV_HEADLESS_SPEC="opencv-python-headless==${OPENCV_HEADLESS_VERSION}"
RUNTIME_PY_SOURCE="unknown"
STANDALONE_VARIANT_USED="none"
NUMPY_INSTALL_SOURCE="unknown"
OPENCV_INSTALL_SOURCE="unknown"
DEPLOY_STATUS_FILE="$BASE/var/deploy-status.json"
DEPLOY_STATE="hard-failed"
DEPLOY_PHASE="init"
DEPLOY_REASON=""
ONLINE_RECOVERY_USED=0
APT_FALLBACK_USED=0
SERVICE_RESTART_ATTEMPTED=0
SERVICE_ACTIVE_STATE="skipped"
HTTP_PROBE_STATE="skipped"
ACTIVATION_RUNTIME_LIVE_TARGET=""
ACTIVATION_VENV_BACKUP=""
ACTIVATION_RUNTIME_BACKUP=""
ACTIVATION_BACKUPS_PENDING=0
ACTIVATION_RESTORE_STATE="not-needed"
ACTIVATION_RESTORE_REASON=""
RELEASE_ACTIVATED=0

ensure_root_or_sudo_reexec() {
  if [[ "$(id -u)" -eq 0 ]]; then
    return 0
  fi
  if command -v sudo >/dev/null 2>&1; then
    sudo -H -n bash "$0" "$@" || {
      log "ERROR: sudo re-exec failed; root is required."
      exit 1
    }
    exit 0
  fi
  log "ERROR: must run as root and sudo is unavailable."
  exit 1
}

require_root(){ ensure_root_or_sudo_reexec "$@"; }
ensure_dir(){ install -d -m 0755 "$1"; }
strip_crlf(){ [[ -f "$1" ]] || return 0; sed -i 's/\r$//' "$1" || true; }
read_env_value() {
  local env_file="$1"
  local key="$2"
  [[ -f "$env_file" ]] || return 0
  awk -F= -v k="$key" '$1 == k { print substr($0, index($0, "=") + 1); exit }' "$env_file" 2>/dev/null \
    | tr -d '"' | tr -d "'"
}
json_escape() {
  local value="${1:-}"
  value="${value//\\/\\\\}"
  value="${value//\"/\\\"}"
  value="${value//$'\n'/\\n}"
  value="${value//$'\r'/}"
  value="${value//$'\t'/\\t}"
  printf '%s' "$value"
}
append_deploy_reason() {
  local reason="${1:-}"
  [[ -n "$reason" ]] || return 0
  if [[ -z "$DEPLOY_REASON" ]]; then
    DEPLOY_REASON="$reason"
  else
    DEPLOY_REASON="$DEPLOY_REASON; $reason"
  fi
}
mark_degraded() {
  local phase="$1"
  local reason="$2"
  DEPLOY_PHASE="$phase"
  DEPLOY_STATE="degraded"
  append_deploy_reason "$reason"
  log "WARNING: $reason"
}
write_deploy_status_marker() {
  local final_state="$1"
  local final_phase="$2"
  local final_reason="$3"
  local current_release=""
  ensure_dir "$BASE/var"
  current_release="$(readlink -f "$BASE/current" 2>/dev/null || true)"
  cat > "$DEPLOY_STATUS_FILE" <<JSON
{
  "timestamp_utc": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
  "artifact_version": "$(json_escape "$ARTIFACT_VERSION")",
  "release_id": "$(json_escape "$RELEASE_ID")",
  "state": "$(json_escape "$final_state")",
  "phase": "$(json_escape "$final_phase")",
  "reason": "$(json_escape "$final_reason")",
  "online_recovery_used": $( [[ "$ONLINE_RECOVERY_USED" -eq 1 ]] && echo true || echo false ),
  "apt_fallback_used": $( [[ "$APT_FALLBACK_USED" -eq 1 ]] && echo true || echo false ),
  "service_restart_attempted": $( [[ "$SERVICE_RESTART_ATTEMPTED" -eq 1 ]] && echo true || echo false ),
  "service_active": "$(json_escape "$SERVICE_ACTIVE_STATE")",
  "http_probe": "$(json_escape "$HTTP_PROBE_STATE")",
  "current_release": "$(json_escape "$current_release")"
}
JSON
  chmod 0644 "$DEPLOY_STATUS_FILE" >/dev/null 2>&1 || true
}
finalize_deploy_status() {
  local rc="$1"
  if [[ "$rc" -ne 0 ]]; then
    [[ -n "$DEPLOY_REASON" ]] || DEPLOY_REASON="installer exited with status $rc"
    DEPLOY_STATE="hard-failed"
  elif [[ "$DEPLOY_STATE" != "degraded" ]]; then
    DEPLOY_STATE="healthy"
    [[ -n "$DEPLOY_REASON" ]] || DEPLOY_REASON="deploy completed"
  fi
  write_deploy_status_marker "$DEPLOY_STATE" "$DEPLOY_PHASE" "$DEPLOY_REASON"
}
glob_exists_ci() {
  local pattern="$1"
  local had_nocaseglob=0
  shopt -q nocaseglob && had_nocaseglob=1
  shopt -s nocaseglob
  compgen -G "$pattern" >/dev/null 2>&1
  local rc=$?
  if [[ "$had_nocaseglob" -eq 1 ]]; then
    shopt -s nocaseglob
  else
    shopt -u nocaseglob
  fi
  return "$rc"
}
log_wheel_candidates() {
  local wheel_dir="$1"
  local wheel_name=""
  log "Wheel candidates in ${wheel_dir}:"
  if [[ ! -d "$wheel_dir" ]]; then
    log "wheel: (missing directory)"
    return 0
  fi
  while IFS= read -r wheel_name; do
    [[ -n "$wheel_name" ]] && log "wheel: ${wheel_name}"
  done < <(
    cd "$wheel_dir" >/dev/null 2>&1 && { ls -1 *.whl 2>/dev/null || ls -1 2>/dev/null || true; }
  )
}
prepare_install_pip_cache(){
  export HOME="/root"
  install -d -m 0700 /root /root/.cache "$INSTALL_PIP_CACHE_DIR"
  chown root:root /root /root/.cache "$INSTALL_PIP_CACHE_DIR" >/dev/null 2>&1 || true
}

init_python_log() {
  ensure_dir "$(dirname "$PYTHON_BOOTSTRAP_LOG")"
  : > "$PYTHON_BOOTSTRAP_LOG" 2>/dev/null || touch "$PYTHON_BOOTSTRAP_LOG" >/dev/null 2>&1 || true
  chmod 0644 "$PYTHON_BOOTSTRAP_LOG" >/dev/null 2>&1 || true
}

init_pip_log() {
  ensure_dir "$(dirname "$PIP_LOG_FILE")"
  : > "$PIP_LOG_FILE" 2>/dev/null || touch "$PIP_LOG_FILE" >/dev/null 2>&1 || true
  chmod 0644 "$PIP_LOG_FILE" >/dev/null 2>&1 || true
}

normalize_locale_defaults() {
  local locale_file="/etc/default/locale"
  local configured_locale=""
  local candidate=""
  local normalized=""

  ensure_dir /etc/default
  if [[ -f "$locale_file" ]]; then
    configured_locale="$(read_env_value "$locale_file" "LC_ALL")"
    [[ -n "$configured_locale" ]] || configured_locale="$(read_env_value "$locale_file" "LANG")"
  fi

  if [[ -n "$configured_locale" ]] && command -v locale >/dev/null 2>&1; then
    normalized="$(printf '%s\n' "$configured_locale" | tr '[:upper:]' '[:lower:]')"
    while IFS= read -r candidate; do
      [[ "$normalized" == "$(printf '%s\n' "$candidate" | tr '[:upper:]' '[:lower:]')" ]] && {
        export LANG="$configured_locale"
        export LC_ALL="$configured_locale"
        return 0
      }
    done < <(locale -a 2>/dev/null || true)
  fi

  log "Locale configuration is missing or invalid; normalizing to C.UTF-8"
  cat > "$locale_file" <<'LOCALE'
LANG=C.UTF-8
LC_ALL=C.UTF-8
LOCALE
  chmod 0644 "$locale_file" >/dev/null 2>&1 || true
  export LANG=C.UTF-8
  export LC_ALL=C.UTF-8
}

emit_python_log_tail() {
  local line
  [[ -s "$PYTHON_BOOTSTRAP_LOG" ]] || return 0
  log "Python bootstrap log tail:"
  while IFS= read -r line; do
    [[ -n "$line" ]] && log "py-log: $line"
  done < <(tail -n 50 "$PYTHON_BOOTSTRAP_LOG" 2>/dev/null || true)
}

emit_pip_log_tail() {
  local line
  [[ -s "$PIP_LOG_FILE" ]] || return 0
  log "PIP log tail:"
  while IFS= read -r line; do
    [[ -n "$line" ]] && log "pip-log: $line"
  done < <(tail -n 50 "$PIP_LOG_FILE" 2>/dev/null || true)
}

prefix_candidate_ready() {
  local prefix="$1"
  local min_free_kb="$2"
  local free_kb=""
  local probe_file="$prefix/.pc_runtime_probe.$$"

  install -d -m 0755 "$prefix" >/dev/null 2>&1 || return 1
  touch "$probe_file" >/dev/null 2>&1 || return 1
  rm -f "$probe_file" >/dev/null 2>&1 || true

  if command -v df >/dev/null 2>&1; then
    free_kb="$(df -Pk "$prefix" 2>/dev/null | awk 'NR==2{print $4}' || true)"
    if [[ "$free_kb" =~ ^[0-9]+$ ]] && [[ "$free_kb" -lt "$min_free_kb" ]]; then
      return 1
    fi
  fi

  return 0
}

select_runtime_prefix() {
  if [[ -n "$RUNTIME_PREFIX" ]] && prefix_candidate_ready "$RUNTIME_PREFIX" "$RUNTIME_PREFIX_MIN_FREE_KB"; then
    return 0
  fi

  if prefix_candidate_ready "$RUNTIME_PREFIX_PRIMARY" "$RUNTIME_PREFIX_MIN_FREE_KB"; then
    RUNTIME_PREFIX="$RUNTIME_PREFIX_PRIMARY"
  elif prefix_candidate_ready "$RUNTIME_PREFIX_FALLBACK" "$RUNTIME_PREFIX_MIN_FREE_KB"; then
    log "WARNING: runtime prefix fallback selected: $RUNTIME_PREFIX_FALLBACK"
    RUNTIME_PREFIX="$RUNTIME_PREFIX_FALLBACK"
  else
    log "ERROR: neither runtime prefix is writable with sufficient free space: $RUNTIME_PREFIX_PRIMARY, $RUNTIME_PREFIX_FALLBACK"
    exit 1
  fi

  PY312_STANDALONE_PREFIX="$RUNTIME_PREFIX/python312-standalone"
  log "Runtime prefix selected: $RUNTIME_PREFIX"
}

# --------------------------
# Fix Mender device_type
# --------------------------
detect_pi_model(){
  local m=""
  [[ -r /proc/device-tree/model ]] && m="$(tr -d '\0' </proc/device-tree/model 2>/dev/null || true)"
  [[ -z "$m" && -r /sys/firmware/devicetree/base/model ]] && m="$(tr -d '\0' </sys/firmware/devicetree/base/model 2>/dev/null || true)"
  echo "$m"
}
model_to_device_type(){
  case "$1" in
    *"Raspberry Pi 4"*|*"Compute Module 4"*) echo "raspberrypi4" ;;
    *"Raspberry Pi 5"*) echo "raspberrypi5" ;;
    *) echo "" ;;
  esac
}
write_device_type_files(){
  local dt="$1"; [[ -n "$dt" ]] || return 0
  install -d -m 0755 "$(dirname "$DEVICE_TYPE_FILE")" || true
  printf 'device_type=%s\n' "$dt" > "$DEVICE_TYPE_FILE"
  chmod 0644 "$DEVICE_TYPE_FILE" || true
  install -d -m 0755 /etc/mender || true
  printf 'device_type=%s\n' "$dt" > /etc/mender/device_type
  chmod 0644 /etc/mender/device_type || true
  log "Set device_type to: $dt"
}
patch_mender_conf_keep_keys(){
  local dtf="$1"
  if command -v python3 >/dev/null 2>&1; then
    python3 - <<PY || true
import json, os
path="${MENDER_CONF}"
dtf="${dtf}"
data={}
try:
  with open(path,"r",encoding="utf-8") as f:
    data=json.load(f)
except Exception:
  data={}
data["DeviceTypeFile"]=dtf
data.pop("DeviceType",None)
os.makedirs(os.path.dirname(path), exist_ok=True)
with open(path,"w",encoding="utf-8") as f:
  json.dump(data,f,indent=2)
PY
    chmod 0644 "$MENDER_CONF" || true
    log "Patched mender.conf: ensured DeviceTypeFile=${dtf}"
  fi
}
fix_mender_device_type(){
  local model dt
  model="$(detect_pi_model)"
  dt="$(model_to_device_type "$model")"
  [[ -n "$dt" ]] || { log "WARNING: cannot detect Pi model from '$model'"; return 0; }
  write_device_type_files "$dt"
  patch_mender_conf_keep_keys "$DEVICE_TYPE_FILE"
}

# --------------------------
# Python runtime + venv + requirements
# --------------------------
sha256_runtime_file() {
  local f="$1"
  if command -v sha256sum >/dev/null 2>&1; then
    sha256sum "$f" | awk '{print tolower($1)}'
    return 0
  fi
  if command -v shasum >/dev/null 2>&1; then
    shasum -a 256 "$f" | awk '{print tolower($1)}'
    return 0
  fi
  if command -v openssl >/dev/null 2>&1; then
    openssl dgst -sha256 "$f" | awk '{print tolower($NF)}'
    return 0
  fi
  return 1
}

extract_archive_with_tar() {
  local archive="$1"
  local dest="$2"
  tar -xzf "$archive" -C "$dest" >>"$PYTHON_BOOTSTRAP_LOG" 2>&1
}

extract_archive_with_python_tarfile() {
  local archive="$1"
  local dest="$2"
  local py_extract=""
  for py_extract in python3 python; do
    command -v "$py_extract" >/dev/null 2>&1 || continue
    if "$py_extract" - "$archive" "$dest" >>"$PYTHON_BOOTSTRAP_LOG" 2>&1 <<'PY'
import os
import sys
import tarfile

archive = sys.argv[1]
dest = sys.argv[2]
os.makedirs(dest, exist_ok=True)
with tarfile.open(archive, "r:gz") as tf:
    tf.extractall(dest)
PY
    then
      return 0
    fi
  done
  return 1
}

extract_archive_robust() {
  local archive="$1"
  local dest="$2"
  if extract_archive_with_tar "$archive" "$dest"; then
    return 0
  fi
  log "WARNING: tar extraction failed for $(basename "$archive"), trying python tarfile fallback."
  extract_archive_with_python_tarfile "$archive" "$dest"
}

verify_standalone_asset_pair() {
  local tgz="$1"
  local sha_file="$2"
  local variant="$3"
  local expected_sha=""
  local actual_sha=""
  [[ -s "$tgz" ]] || { log "WARNING: standalone ${variant} bundle missing: $tgz"; return 1; }
  [[ -s "$sha_file" ]] || { log "WARNING: standalone ${variant} checksum missing: $sha_file"; return 1; }

  expected_sha="$(awk 'NR==1{print tolower($1)}' "$sha_file" 2>/dev/null || true)"
  [[ -n "$expected_sha" ]] || { log "WARNING: standalone ${variant} checksum file invalid: $sha_file"; return 1; }

  actual_sha="$(sha256_runtime_file "$tgz" 2>/dev/null || true)"
  [[ -n "$actual_sha" ]] || { log "WARNING: unable to compute standalone ${variant} checksum."; return 1; }
  if [[ "$actual_sha" != "$expected_sha" ]]; then
    log "WARNING: standalone ${variant} checksum mismatch (expected=$expected_sha actual=$actual_sha)."
    return 1
  fi
  return 0
}

resolve_standalone_python_bin() {
  local prefix="$1"
  if [[ -x "$prefix/python312-standalone/python/bin/python3.12" ]]; then
    printf '%s\n' "$prefix/python312-standalone/python/bin/python3.12"
    return 0
  fi
  if [[ -x "$prefix/python/bin/python3.12" ]]; then
    printf '%s\n' "$prefix/python/bin/python3.12"
    return 0
  fi
  if [[ -x "$prefix/bin/python3.12" ]]; then
    printf '%s\n' "$prefix/bin/python3.12"
    return 0
  fi
  return 1
}

install_python312_standalone() {
  local app_dir="$1"
  local full_tgz="$app_dir/deploy/python-assets/python312-standalone-aarch64-full.tar.gz"
  local full_sha="$app_dir/deploy/python-assets/python312-standalone-aarch64-full.sha256"
  local stripped_tgz="$app_dir/deploy/python-assets/python312-standalone-aarch64-stripped.tar.gz"
  local stripped_sha="$app_dir/deploy/python-assets/python312-standalone-aarch64-stripped.sha256"
  local variant=""
  local tgz=""
  local sha_file=""
  local py=""

  select_runtime_prefix
  STANDALONE_VARIANT_USED="none"

  for variant in full stripped; do
    if [[ "$variant" == "full" ]]; then
      tgz="$full_tgz"
      sha_file="$full_sha"
    else
      tgz="$stripped_tgz"
      sha_file="$stripped_sha"
    fi

    verify_standalone_asset_pair "$tgz" "$sha_file" "$variant" || continue

    rm -rf "$PY312_STANDALONE_PREFIX" >/dev/null 2>&1 || true
    install -d -m 0755 "$PY312_STANDALONE_PREFIX" >/dev/null 2>&1 || {
      log "WARNING: cannot create standalone prefix: $PY312_STANDALONE_PREFIX"
      continue
    }

    if ! extract_archive_robust "$tgz" "$PY312_STANDALONE_PREFIX"; then
      log "WARNING: failed extracting standalone Python variant '$variant'."
      emit_python_log_tail
      continue
    fi

    py="$(resolve_standalone_python_bin "$PY312_STANDALONE_PREFIX" || true)"
    [[ -n "$py" ]] || {
      log "WARNING: standalone variant '$variant' missing python3.12 executable."
      emit_python_log_tail
      continue
    }
    "$py" --version >/dev/null 2>&1 || {
      log "WARNING: standalone variant '$variant' python3.12 is not executable."
      emit_python_log_tail
      continue
    }
    "$py" -m pip --version >/dev/null 2>&1 || {
      log "WARNING: standalone variant '$variant' pip is unavailable."
      emit_python_log_tail
      continue
    }

    STANDALONE_VARIANT_USED="$variant"
    log "Standalone Python 3.12 ready from variant '$variant': $py"
    printf '%s\n' "$py"
    return 0
  done

  log "ERROR: all standalone Python variants failed."
  emit_python_log_tail
  return 1
}

validate_python_compat() {
  local py="$1"
  local major_minor full_ver abi
  major_minor="$("$py" -c 'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}")' 2>/dev/null || true)"
  full_ver="$("$py" -c 'import sys; print(sys.version.split()[0])' 2>/dev/null || true)"
  abi="$("$py" -c 'import sys; print(getattr(sys.implementation, "cache_tag", "unknown"))' 2>/dev/null || true)"
  log "Selected Python version: ${full_ver:-unknown} (abi=${abi:-unknown})"
  case "$major_minor" in
    3.11|3.12) return 0 ;;
    *)
      log "ERROR: unsupported Python version (${full_ver:-unknown}). Current requirements are pinned for Python <= 3.12."
      exit 1
      ;;
  esac
}

ensure_runtime_pip() {
  local py="$1"
  "$py" -m pip --version >/dev/null 2>&1 && return 0
  "$py" -m ensurepip --upgrade >/dev/null 2>&1 || true
  "$py" -m pip --version >/dev/null 2>&1 || {
    log "ERROR: pip unavailable for interpreter: $py"
    exit 1
  }
}

assert_runtime_manifest_policy() {
  local manifest="$APP_DIR/deploy/python-assets/manifest.txt"
  [[ -s "$manifest" ]] || { log "ERROR: missing python-assets manifest: $manifest"; exit 1; }
  grep -q '^offline_target_install=yes$' "$manifest" || { log "ERROR: manifest offline policy missing: offline_target_install=yes"; exit 1; }
  grep -q '^runtime_bootstrap=standalone-only$' "$manifest" || { log "ERROR: manifest runtime bootstrap policy mismatch."; exit 1; }
  grep -q '^runtime_online_fallback=controlled$' "$manifest" || { log "ERROR: manifest runtime online fallback must be controlled."; exit 1; }
  grep -q '^forbidden_runtime_paths=curl,source-build$' "$manifest" || { log "ERROR: manifest forbidden runtime paths policy missing."; exit 1; }
}

python_major_minor() {
  local py="$1"
  "$py" -c 'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}")' 2>/dev/null || true
}

python_supports_current_pins() {
  local py="$1"
  case "$(python_major_minor "$py")" in
    3.11|3.12) return 0 ;;
    *) return 1 ;;
  esac
}

run_online_apt_recovery() {
  [[ "$APT_FALLBACK_USED" -eq 1 ]] && return 0
  if ! command -v apt-get >/dev/null 2>&1; then
    log "WARNING: apt-get unavailable; skipping online apt recovery."
    return 1
  fi

  APT_FALLBACK_USED=1
  ONLINE_RECOVERY_USED=1
  log "INSTALL_STAGE_RECOVERY: attempting online apt recovery for runtime prerequisites."
  if ! DEBIAN_FRONTEND=noninteractive apt-get update >>"$PIP_LOG_FILE" 2>&1; then
    log "WARNING: apt-get update failed during online recovery."
    emit_pip_log_tail
    return 1
  fi
  if ! DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
    python3 python3-venv python3-pip python3-setuptools python3-wheel \
    build-essential pkg-config ca-certificates \
    libglib2.0-0 libgl1 libusb-1.0-0 >>"$PIP_LOG_FILE" 2>&1; then
    log "WARNING: apt-get install failed during online recovery."
    emit_pip_log_tail
    return 1
  fi
  log "INSTALL_STAGE_RECOVERY: online apt recovery completed."
  return 0
}

try_system_python_runtime() {
  local system_py=""
  system_py="$(command -v python3 || true)"
  if [[ -z "$system_py" ]]; then
    run_online_apt_recovery || true
    system_py="$(command -v python3 || true)"
  fi
  [[ -n "$system_py" ]] || return 1
  python_supports_current_pins "$system_py" || return 1
  "$system_py" -m venv --help >/dev/null 2>&1 || {
    run_online_apt_recovery || true
    "$system_py" -m venv --help >/dev/null 2>&1 || return 1
  }
  ensure_runtime_pip "$system_py"
  RUNTIME_PY="$system_py"
  RUNTIME_PY_SOURCE="system-online-recovery"
  ONLINE_RECOVERY_USED=1
  return 0
}

manifest_value() {
  local manifest="$1"
  local key="$2"
  awk -F= -v k="$key" '$1 == k { print substr($0, index($0, "=") + 1); exit }' "$manifest" 2>/dev/null || true
}

csv_contains() {
  local csv="$1"
  local needle="$2"
  local item=""
  IFS=',' read -r -a items <<< "$csv"
  for item in "${items[@]}"; do
    item="${item//[[:space:]]/}"
    [[ -z "$item" ]] && continue
    [[ "$item" == "$needle" ]] && return 0
  done
  return 1
}

current_python_arch_tag() {
  case "$(uname -m)" in
    aarch64|arm64) printf '%s\n' 'aarch64-cp312' ;;
    armv7l|armv7*|armhf) printf '%s\n' 'armv7-cp312' ;;
    *) printf '%s\n' "$(uname -m)-cp312" ;;
  esac
}

resolve_runtime_wheel_dir() {
  local app_dir="$1"
  local manifest="$app_dir/deploy/python-assets/manifest.txt"
  local arch_tag supported_arches unsupported_arches blocker policy wheel_dir

  arch_tag="$(current_python_arch_tag)"
  supported_arches="$(manifest_value "$manifest" "python_supported_arches")"
  unsupported_arches="$(manifest_value "$manifest" "python_unsupported_arches")"
  blocker="$(manifest_value "$manifest" "python_armv7_blocker")"
  policy="$(manifest_value "$manifest" "python_armv7_failure_policy")"

  if csv_contains "$unsupported_arches" "$arch_tag"; then
    log "ERROR: Python runtime assets do not support '$arch_tag'; blocker=${blocker:-depthai==2.30.0.0}; policy=${policy:-install-refuse}"
    return 1
  fi
  if ! csv_contains "$supported_arches" "$arch_tag"; then
    log "ERROR: no supported offline Python wheelhouse declared for '$arch_tag'. Supported=${supported_arches:-none}"
    return 1
  fi

  wheel_dir="$app_dir/deploy/python-assets/wheels/$arch_tag"
  [[ -d "$wheel_dir" ]] || { log "ERROR: offline wheelhouse directory missing for '$arch_tag': $wheel_dir"; return 1; }
  find "$wheel_dir" -maxdepth 1 -type f | grep -q . || { log "ERROR: offline wheelhouse is empty for '$arch_tag': $wheel_dir"; return 1; }
  printf '%s\n' "$wheel_dir"
}

ensure_python_runtime() {
  local standalone_py=""
  log "INSTALL_STAGE_PYTHON: OFFLINE_POLICY=PREFERRED"
  log "INSTALL_STAGE_PYTHON: CONTROLLED_ONLINE_RECOVERY=ALLOWED"
  log "INSTALL_STAGE_PYTHON: FORBIDDEN_RUNTIME_PATHS=curl,source-build"
  assert_runtime_manifest_policy
  select_runtime_prefix
  standalone_py="$(install_python312_standalone "$APP_DIR" || true)"
  if [[ -n "$standalone_py" ]]; then
    validate_python_compat "$standalone_py"
    "$standalone_py" -m venv --help >/dev/null 2>&1 || {
      log "WARNING: bundled standalone python does not provide venv module; trying online recovery."
      standalone_py=""
    }
  fi

  if [[ -n "$standalone_py" ]]; then
    RUNTIME_PY="$standalone_py"
    RUNTIME_PY_SOURCE="standalone-${STANDALONE_VARIANT_USED}"
    ensure_runtime_pip "$RUNTIME_PY"
    log "Runtime Python path selected: $RUNTIME_PY (source=$RUNTIME_PY_SOURCE)"
    return 0
  fi

  log "WARNING: offline standalone Python bootstrap failed; attempting controlled online recovery."
  if try_system_python_runtime; then
    log "Runtime Python path selected: $RUNTIME_PY (source=$RUNTIME_PY_SOURCE)"
    return 0
  fi

  log "ERROR: runtime bootstrap failed after offline and online recovery attempts."
  exit 1
}

prepare_venv() {
  local app_dir="$1"
  local py_assets="$app_dir/deploy/python-assets"
  local prebuilt="$py_assets/prebuilt-venv.tar.gz"
  local tmp_restore="/tmp/peoplecounter-venv-restore.$$"

  rm -rf "$RUNTIME_VENV" >/dev/null 2>&1 || true

  if [[ -s "$prebuilt" ]]; then
    log "Attempting to restore prebuilt venv from payload."
    rm -rf "$tmp_restore" >/dev/null 2>&1 || true
    ensure_dir "$tmp_restore"
    if tar -xzf "$prebuilt" -C "$tmp_restore" >/dev/null 2>&1 \
      && [[ -x "$tmp_restore/bin/python" && -f "$tmp_restore/pyvenv.cfg" ]]; then
      ensure_dir "$RUNTIME_VENV"
      cp -a "$tmp_restore"/. "$RUNTIME_VENV"/
      if "$RUNTIME_PY" -m venv --upgrade "$RUNTIME_VENV" >/dev/null 2>&1 \
        && [[ -x "$RUNTIME_VENV_PY" ]]; then
        rm -rf "$tmp_restore" >/dev/null 2>&1 || true
        log "Prebuilt venv restored and upgraded successfully."
        return 0
      fi
      log "WARNING: prebuilt venv upgrade failed. Recreating from scratch."
    else
      log "WARNING: prebuilt venv invalid or extract failed. Recreating from scratch."
    fi
    rm -rf "$tmp_restore" "$RUNTIME_VENV" >/dev/null 2>&1 || true
  fi

  "$RUNTIME_PY" -m venv "$RUNTIME_VENV" || {
    log "ERROR: failed to create venv at $RUNTIME_VENV"
    return 1
  }
  [[ -x "$RUNTIME_VENV_PY" ]] || {
    log "ERROR: venv python missing after creation: $RUNTIME_VENV_PY"
    return 1
  }
  return 0
}

prepare_venv_clean() {
  rm -rf "$RUNTIME_VENV" >/dev/null 2>&1 || true
  if ! prepare_venv "$1"; then
    rm -rf "$RUNTIME_VENV" >/dev/null 2>&1 || true
    return 1
  fi
  return 0
}

offline_tooling_refresh_specs() {
  local wheel_dir="$1"
  local tool=""
  for tool in pip setuptools wheel; do
    if compgen -G "$wheel_dir/${tool}-*.whl" >/dev/null 2>&1; then
      printf '%s\n' "$tool"
    fi
  done
}

maybe_refresh_offline_tooling() {
  local py="$1"
  local wheel_dir="$2"
  local specs=()
  local spec=""

  while IFS= read -r spec; do
    [[ -n "$spec" ]] && specs+=("$spec")
  done < <(offline_tooling_refresh_specs "$wheel_dir")

  if [[ "${#specs[@]}" -eq 0 ]]; then
    log "INSTALL_STAGE_PIP: bundled pip/setuptools/wheel wheels are not present; using existing tooling."
    return 0
  fi

  if ! PIP_CACHE_DIR="$INSTALL_PIP_CACHE_DIR" "$py" -m pip install \
    --no-index --find-links "$wheel_dir" --upgrade "${specs[@]}" >>"$PIP_LOG_FILE" 2>&1; then
    log "WARNING: offline upgrade of ${specs[*]} failed; continuing with bundled tooling."
    emit_pip_log_tail
  fi
}

install_requirements_offline() {
  local app_dir="$1"
  local req="$app_dir/requirements.txt"
  local lock_file="$app_dir/$REQUIREMENTS_LOCK_REL"
  local wheel_dir=""

  [[ -s "$req" ]] || { log "ERROR: requirements.txt missing: $req"; return 1; }
  [[ -s "$lock_file" ]] || { log "ERROR: requirements lock missing: $lock_file"; return 1; }
  wheel_dir="$(resolve_runtime_wheel_dir "$app_dir")" || return 1

  NUMPY_INSTALL_SOURCE="unknown"
  OPENCV_INSTALL_SOURCE="unknown"

  log "INSTALL_STAGE_PIP: offline install preferred (--no-index) using bundled assets."
  ensure_runtime_pip "$RUNTIME_VENV_PY"
  maybe_refresh_offline_tooling "$RUNTIME_VENV_PY" "$wheel_dir"

  log "INSTALL_STAGE_PIP: installing pinned NumPy wheel from offline wheelhouse."
  PIP_CACHE_DIR="$INSTALL_PIP_CACHE_DIR" "$RUNTIME_VENV_PY" -m pip install \
    --no-index --find-links "$wheel_dir" --only-binary=numpy "$NUMPY_SPEC" >>"$PIP_LOG_FILE" 2>&1 || return 1
  NUMPY_INSTALL_SOURCE="offline-wheelhouse"

  log "INSTALL_STAGE_PIP: materializing full locked dependency set from offline lock file."
  PIP_CACHE_DIR="$INSTALL_PIP_CACHE_DIR" "$RUNTIME_VENV_PY" -m pip install \
    --no-index --find-links "$wheel_dir" -r "$lock_file" >>"$PIP_LOG_FILE" 2>&1 || return 1

  log "INSTALL_STAGE_PIP: installing dependency set from lock+requirements (offline only)."
  PIP_CACHE_DIR="$INSTALL_PIP_CACHE_DIR" "$RUNTIME_VENV_PY" -m pip install \
    --no-index --find-links "$wheel_dir" -r "$req" -c "$lock_file" >>"$PIP_LOG_FILE" 2>&1 || return 1

  log "INSTALL_STAGE_PIP: enforcing headless OpenCV policy from offline wheelhouse."
  PIP_CACHE_DIR="$INSTALL_PIP_CACHE_DIR" "$RUNTIME_VENV_PY" -m pip install \
    --no-index --find-links "$wheel_dir" --force-reinstall --no-deps "$OPENCV_HEADLESS_SPEC" >>"$PIP_LOG_FILE" 2>&1 || return 1
  OPENCV_INSTALL_SOURCE="offline-wheelhouse"

  if PIP_CACHE_DIR="$INSTALL_PIP_CACHE_DIR" "$RUNTIME_VENV_PY" -m pip show opencv-python >/dev/null 2>&1; then
    return 1
  fi

  PIP_CACHE_DIR="$INSTALL_PIP_CACHE_DIR" "$RUNTIME_VENV_PY" -m pip check >>"$PIP_LOG_FILE" 2>&1 || {
    return 1
  }
  return 0
}

install_requirements_online_recovery() {
  local app_dir="$1"
  local req="$app_dir/requirements.txt"
  local lock_file="$app_dir/$REQUIREMENTS_LOCK_REL"

  ONLINE_RECOVERY_USED=1
  run_online_apt_recovery || true
  log "INSTALL_STAGE_RECOVERY: attempting online pip recovery for Python dependencies."
  prepare_venv_clean "$app_dir"
  ensure_runtime_pip "$RUNTIME_VENV_PY"

  PIP_CACHE_DIR="$INSTALL_PIP_CACHE_DIR" "$RUNTIME_VENV_PY" -m pip install \
    --upgrade --prefer-binary pip setuptools wheel >>"$PIP_LOG_FILE" 2>&1 || {
      log "WARNING: online upgrade of pip/setuptools/wheel failed."
      emit_pip_log_tail
    }

  PIP_CACHE_DIR="$INSTALL_PIP_CACHE_DIR" "$RUNTIME_VENV_PY" -m pip install --only-binary=:all: --prefer-binary "$NUMPY_SPEC" >>"$PIP_LOG_FILE" 2>&1 || return 1
  NUMPY_INSTALL_SOURCE="online-recovery"

  PIP_CACHE_DIR="$INSTALL_PIP_CACHE_DIR" "$RUNTIME_VENV_PY" -m pip install --only-binary=:all: --prefer-binary -r "$lock_file" >>"$PIP_LOG_FILE" 2>&1 || return 1
  PIP_CACHE_DIR="$INSTALL_PIP_CACHE_DIR" "$RUNTIME_VENV_PY" -m pip install --only-binary=:all: --prefer-binary -r "$req" -c "$lock_file" >>"$PIP_LOG_FILE" 2>&1 || return 1
  PIP_CACHE_DIR="$INSTALL_PIP_CACHE_DIR" "$RUNTIME_VENV_PY" -m pip install --only-binary=:all: --prefer-binary --force-reinstall --no-deps "$OPENCV_HEADLESS_SPEC" >>"$PIP_LOG_FILE" 2>&1 || return 1
  OPENCV_INSTALL_SOURCE="online-recovery"

  if PIP_CACHE_DIR="$INSTALL_PIP_CACHE_DIR" "$RUNTIME_VENV_PY" -m pip show opencv-python >/dev/null 2>&1; then
    return 1
  fi

  PIP_CACHE_DIR="$INSTALL_PIP_CACHE_DIR" "$RUNTIME_VENV_PY" -m pip check >>"$PIP_LOG_FILE" 2>&1 || return 1
  log "INSTALL_STAGE_RECOVERY: online pip recovery succeeded."
  return 0
}

install_requirements_with_recovery() {
  local app_dir="$1"

  if install_requirements_offline "$app_dir"; then
    return 0
  fi

  log "WARNING: offline dependency installation failed; attempting controlled online recovery."
  emit_pip_log_tail
  if install_requirements_online_recovery "$app_dir"; then
    return 0
  fi

  log "ERROR: dependency installation failed after offline and online recovery attempts."
  emit_pip_log_tail
  return 1
}

validate_numpy_runtime() {
  local output=""

  output="$("$RUNTIME_VENV_PY" - "$NUMPY_VERSION" <<'PY'
import sys

expected = sys.argv[1]
try:
  import numpy as np
  import cv2
  import depthai
except Exception as exc:
  print(f"ERROR: import failure: {exc}")
  sys.exit(1)

numpy_ver = getattr(np, "__version__", "unknown")
cv2_ver = getattr(cv2, "__version__", "unknown")
depthai_ver = getattr(depthai, "__version__", "unknown")
py_ver = sys.version.split()[0]
abi_tag = getattr(getattr(sys, "implementation", None), "cache_tag", "unknown")
build_info = cv2.getBuildInformation()
gui_line = "unknown"
for line in build_info.splitlines():
  line_s = line.strip()
  if line_s.upper().startswith("GUI:"):
    gui_line = line_s
    break

print(f"numpy={numpy_ver}")
print(f"cv2={cv2_ver}")
print(f"depthai={depthai_ver}")
print(f"python={py_ver}")
print(f"abi={abi_tag}")
print(f"cv2_gui={gui_line}")

if numpy_ver != expected:
  print(f"ERROR: numpy version mismatch (expected={expected}, actual={numpy_ver})")
  sys.exit(2)

if gui_line != "unknown" and "NONE" not in gui_line.upper():
  print(f"ERROR: OpenCV build is not headless-compatible ({gui_line})")
  sys.exit(3)
PY
  )" || {
    log "ERROR: NumPy runtime validation failed."
    while IFS= read -r line; do
      [[ -n "$line" ]] && log "numpy-check: $line"
    done <<< "$output"
    return 1
  }

  log "NumPy install source: $NUMPY_INSTALL_SOURCE"
  log "OpenCV install source: $OPENCV_INSTALL_SOURCE"
  while IFS= read -r line; do
    [[ -n "$line" ]] && log "numpy-check: $line"
  done <<< "$output"
  return 0
}

validate_runtime_ready() {
  local app_dir="$1"
  [[ -s "$app_dir/launch.py" ]] || { log "ERROR: launch.py missing: $app_dir/launch.py"; return 11; }
  [[ -x "$RUNTIME_VENV_PY" ]] || { log "ERROR: venv python missing: $RUNTIME_VENV_PY"; return 11; }
  if ! "$RUNTIME_VENV_PY" - <<'PY' >/dev/null 2>&1; then
import sys
print(sys.executable)
print(sys.version)
import django
print(django.get_version())
PY
    log "ERROR: venv python smoke test failed."
    return 11
  fi
  return 0
}

normalize_tree_permissions() {
  local tree="$1"
  [[ -e "$tree" ]] || return 0
  chown -R root:root "$tree" >/dev/null 2>&1 || true
  chmod -R u=rwX,go=rX "$tree" >/dev/null 2>&1 || true
}

set_root_managed_permissions() {
  local p
  local paths=(
    "$APP_DIR"
    "$BASE/current"
    "$LIVE_RUNTIME_VENV"
    "$LIVE_RUNTIME_PREFIX_PRIMARY"
    "$LIVE_RUNTIME_PREFIX_FALLBACK"
    "$BASE/config"
    "$BASE/state"
    "$BASE/logs"
    "$BASE/var"
    "$BASE/var/staticfiles"
    "$BASE/events"
    "/data/tmp"
    "/data/pip-cache"
  )
  for p in "${paths[@]}"; do
    [[ -e "$p" ]] || continue
    if [[ -L "$p" ]]; then
      chown -h root:root "$p" >/dev/null 2>&1 || true
      continue
    fi
    case "$p" in
      "$LIVE_RUNTIME_VENV"|"$LIVE_RUNTIME_PREFIX_PRIMARY"|"$LIVE_RUNTIME_PREFIX_FALLBACK")
        normalize_tree_permissions "$p"
        ;;
      *)
        normalize_tree_permissions "$p"
        ;;
    esac
  done
}

verify_oak_udev_install() {
  local result=""
  if [[ ! -x /usr/local/sbin/peoplecounter-ensure-udev ]]; then
    log "ERROR: missing /usr/local/sbin/peoplecounter-ensure-udev"
    exit 1
  fi

  if ! result="$(/usr/local/sbin/peoplecounter-ensure-udev --json 2>&1)"; then
    log "ERROR: OAK udev verification failed: $result"
    exit 1
  fi
  log "OAK udev verification: $result"
}

current_host_probe_target() {
  local ip_value=""
  ip_value="$(ip -o -4 addr show scope global up 2>/dev/null | awk '{print $4}' | cut -d/ -f1 | head -n 1)"
  [[ -n "$ip_value" ]] || ip_value="visionai.local"
  printf '%s\n' "$ip_value"
}

current_django_port() {
  local bind_value=""
  local candidate=""
  bind_value="$(read_env_value /etc/default/peoplecounter DJANGO_BIND)"
  [[ -n "$bind_value" ]] || bind_value="0.0.0.0:2001"
  candidate="${bind_value##*:}"
  if [[ "$candidate" =~ ^[0-9]+$ ]] && (( candidate >= 1 && candidate <= 65535 )); then
    printf '%s\n' "$candidate"
  else
    printf '2001\n'
  fi
}

write_release_metadata() {
  local metadata_path="$LATEST_DIR/.release-metadata.env"
  cat > "$metadata_path" <<META
ARTIFACT_VERSION=${ARTIFACT_VERSION}
RELEASE_ID=${RELEASE_ID}
BUILD_GIT_SHA=${BUILD_GIT_SHA}
BUILD_TS_UTC=${BUILD_TS_UTC}
META
  chmod 0644 "$metadata_path" >/dev/null 2>&1 || true
}

runtime_live_target_for_selected_prefix() {
  if [[ "$RUNTIME_PREFIX" == "$RUNTIME_PREFIX_PRIMARY" ]]; then
    printf '%s\n' "$LIVE_RUNTIME_PREFIX_PRIMARY"
  else
    printf '%s\n' "$LIVE_RUNTIME_PREFIX_FALLBACK"
  fi
}

runtime_prefix_candidate_state() {
  local prefix="$1"
  local py=""

  [[ -d "$prefix" ]] || { printf 'runtime-dir-missing\n'; return 1; }
  py="$(resolve_standalone_python_bin "$prefix" || true)"
  [[ -n "$py" ]] || { printf 'runtime-python-missing\n'; return 1; }
  [[ -x "$py" ]] || { printf 'runtime-python-not-executable\n'; return 1; }
  if ! "$py" - <<'PY' >/dev/null 2>&1; then
import sys
print(sys.executable)
PY
    printf 'runtime-python-not-runnable\n'
    return 1
  fi
  printf 'ok\n'
  return 0
}

venv_candidate_state() {
  local venv="$1"
  local require_imports="${2:-1}"
  local py="$venv/bin/python"

  [[ -d "$venv" ]] || { printf 'venv-dir-missing\n'; return 1; }
  [[ -e "$py" ]] || { printf 'venv-python-missing\n'; return 1; }
  [[ -x "$py" ]] || { printf 'venv-python-not-executable\n'; return 1; }
  if ! "$py" - <<'PY' >/dev/null 2>&1; then
import sys
print(sys.executable)
print(sys.version)
PY
    printf 'venv-python-not-runnable\n'
    return 1
  fi
  if [[ "$require_imports" == "1" ]]; then
    if ! "$py" - <<'PY' >/dev/null 2>&1; then
import cv2
import depthai
import django
import numpy
PY
      printf 'venv-core-import-failure\n'
      return 1
    fi
    if ! "$py" -m pip check >>"$PIP_LOG_FILE" 2>&1; then
      log "WARNING: pip check reported issues for $venv; continuing because core imports succeeded."
    fi
  fi
  printf 'ok\n'
  return 0
}

cleanup_invalid_live_venv() {
  local state=""
  state="$(venv_candidate_state "$LIVE_RUNTIME_VENV" 0 || true)"
  if [[ "$state" != "ok" ]]; then
    rm -rf "$LIVE_RUNTIME_VENV" >/dev/null 2>&1 || true
  fi
}

promote_valid_runtime_backup() {
  local backup="$1"
  local live="$2"
  local state=""

  state="$(runtime_prefix_candidate_state "$backup" || true)"
  if [[ "$state" != "ok" ]]; then
    log "WARNING: runtime backup is invalid ($backup): $state"
    return 1
  fi

  rm -rf "$live" >/dev/null 2>&1 || true
  mv "$backup" "$live" >/dev/null 2>&1 || return 1
  return 0
}

promote_valid_venv_backup() {
  local backup="$1"
  local live="$2"
  local state=""

  state="$(venv_candidate_state "$backup" 1 || true)"
  if [[ "$state" != "ok" ]]; then
    log "WARNING: venv backup is invalid ($backup): $state"
    return 1
  fi

  rm -rf "$live" >/dev/null 2>&1 || true
  mv "$backup" "$live" >/dev/null 2>&1 || return 1
  return 0
}

activate_release_paths() {
  local runtime_live_target=""
  local runtime_backup=""
  local venv_backup="${LIVE_RUNTIME_VENV}.previous"
  local promoted_runtime_python=""

  runtime_live_target="$(runtime_live_target_for_selected_prefix)"
  runtime_backup="${runtime_live_target}.previous"
  ACTIVATION_RUNTIME_LIVE_TARGET="$runtime_live_target"
  ACTIVATION_VENV_BACKUP="$venv_backup"
  ACTIVATION_RUNTIME_BACKUP="$runtime_backup"
  ACTIVATION_BACKUPS_PENDING=0
  ACTIVATION_RESTORE_STATE="not-needed"
  ACTIVATION_RESTORE_REASON=""

  command -v systemctl >/dev/null 2>&1 && systemctl stop peoplecounter.service >/dev/null 2>&1 || true

  rm -rf "$venv_backup" "$runtime_backup" >/dev/null 2>&1 || true
  if [[ -e "$LIVE_RUNTIME_VENV" ]]; then
    mv "$LIVE_RUNTIME_VENV" "$venv_backup" >/dev/null 2>&1 || {
      log "ERROR: failed to move existing live venv out of the way."
      exit 1
    }
  fi
  if [[ -e "$runtime_live_target" ]]; then
    mv "$runtime_live_target" "$runtime_backup" >/dev/null 2>&1 || {
      [[ -e "$venv_backup" ]] && mv "$venv_backup" "$LIVE_RUNTIME_VENV" >/dev/null 2>&1 || true
      log "ERROR: failed to move existing live runtime prefix out of the way."
      exit 1
    }
  fi
  ACTIVATION_BACKUPS_PENDING=1

  mv "$RUNTIME_PREFIX" "$runtime_live_target" || {
    restore_activation_backups
    log "ERROR: failed to promote staged runtime prefix into place."
    return 1
  }

  RUNTIME_VENV="$LIVE_RUNTIME_VENV"
  RUNTIME_VENV_PY="$RUNTIME_VENV/bin/python"
  RUNTIME_PREFIX="$runtime_live_target"
  PY312_STANDALONE_PREFIX="$RUNTIME_PREFIX/python312-standalone"
  promoted_runtime_python="$(resolve_standalone_python_bin "$RUNTIME_PREFIX" || true)"
  RUNTIME_PY="$promoted_runtime_python"

  if [[ ! -x "$promoted_runtime_python" ]]; then
    restore_activation_backups
    log "ERROR: promoted live runtime is missing executable python: ${promoted_runtime_python:-$RUNTIME_PREFIX/python312-standalone/python/bin/python3.12}"
    return 1
  fi
  if ! "$promoted_runtime_python" - <<'PY' >/dev/null 2>&1; then
import sys
print(sys.executable)
PY
    restore_activation_backups
    log "ERROR: promoted live runtime failed smoke test: $promoted_runtime_python"
    return 1
  fi
  return 0
}

restore_activation_backups() {
  [[ "$ACTIVATION_BACKUPS_PENDING" -eq 1 ]] || return 0
  ACTIVATION_RESTORE_STATE="failed"
  ACTIVATION_RESTORE_REASON=""

  if [[ -n "$ACTIVATION_RUNTIME_BACKUP" && -n "$ACTIVATION_RUNTIME_LIVE_TARGET" && -e "$ACTIVATION_RUNTIME_BACKUP" ]]; then
    promote_valid_runtime_backup "$ACTIVATION_RUNTIME_BACKUP" "$ACTIVATION_RUNTIME_LIVE_TARGET" || {
      ACTIVATION_RESTORE_REASON="runtime-backup-invalid"
      return 1
    }
  fi

  if [[ -n "$ACTIVATION_VENV_BACKUP" && -e "$ACTIVATION_VENV_BACKUP" ]]; then
    promote_valid_venv_backup "$ACTIVATION_VENV_BACKUP" "$LIVE_RUNTIME_VENV" || {
      ACTIVATION_RESTORE_REASON="venv-backup-invalid"
      return 1
    }
  else
    cleanup_invalid_live_venv
  fi

  RUNTIME_VENV="$LIVE_RUNTIME_VENV"
  RUNTIME_VENV_PY="$RUNTIME_VENV/bin/python"
  if [[ -n "$ACTIVATION_RUNTIME_LIVE_TARGET" ]]; then
    RUNTIME_PREFIX="$ACTIVATION_RUNTIME_LIVE_TARGET"
    PY312_STANDALONE_PREFIX="$RUNTIME_PREFIX/python312-standalone"
    RUNTIME_PY="$(resolve_standalone_python_bin "$RUNTIME_PREFIX" 2>/dev/null || true)"
  fi
  local live_state=""
  live_state="$(venv_candidate_state "$LIVE_RUNTIME_VENV" 1 || true)"
  if [[ "$live_state" != "ok" ]]; then
    ACTIVATION_RESTORE_REASON="$live_state"
    cleanup_invalid_live_venv
    return 1
  fi
  ACTIVATION_BACKUPS_PENDING=0
  ACTIVATION_RESTORE_STATE="restored"
  ACTIVATION_RESTORE_REASON=""
  return 0
}

cleanup_activation_backups() {
  [[ -n "$ACTIVATION_VENV_BACKUP" ]] && rm -rf "$ACTIVATION_VENV_BACKUP" >/dev/null 2>&1 || true
  [[ -n "$ACTIVATION_RUNTIME_BACKUP" ]] && rm -rf "$ACTIVATION_RUNTIME_BACKUP" >/dev/null 2>&1 || true
  ACTIVATION_BACKUPS_PENDING=0
}

cleanup_runtime_staging_paths() {
  local candidate=""
  for candidate in "$RUNTIME_PREFIX_PRIMARY" "$RUNTIME_PREFIX_FALLBACK"; do
    case "$candidate" in
      "$LIVE_RUNTIME_PREFIX_PRIMARY"|"$LIVE_RUNTIME_PREFIX_FALLBACK")
        continue
        ;;
    esac
    [[ -d "$candidate" ]] || continue
    rm -rf "$candidate" >/dev/null 2>&1 || true
  done
}

finalize_release_symlink() {
  ln -sfn "$APP_DIR" "$BASE/current"
  chown -h root:root "$BASE/current" >/dev/null 2>&1 || true
}

activate_new_release_runtime() {
  local app_dir="$1"

  if ! activate_release_paths; then
    return 1
  fi

  if ! prepare_venv_clean "$app_dir"; then
    restore_activation_backups || true
    return 1
  fi
  if ! install_requirements_with_recovery "$app_dir"; then
    restore_activation_backups || true
    return 1
  fi
  if ! validate_numpy_runtime; then
    restore_activation_backups || true
    return 1
  fi
  if ! validate_runtime_ready "$app_dir"; then
    restore_activation_backups || true
    return 1
  fi

  finalize_release_symlink
  RELEASE_ACTIVATED=1
  return 0
}

resolve_realpath_safe() {
  local target="$1"
  if command -v readlink >/dev/null 2>&1; then
    readlink -f "$target" 2>/dev/null && return 0
  fi
  return 1
}

prune_old_releases() {
  local releases_root_real=""
  local current_release_real=""
  local current_symlink_real=""
  local candidate_line=""
  local candidate_path=""
  local candidate_real=""
  local kept_previous_count=0
  local delete_error=""

  releases_root_real="$(resolve_realpath_safe "$RELEASES" || true)"
  current_release_real="$(resolve_realpath_safe "$LATEST_DIR" || true)"
  current_symlink_real="$(resolve_realpath_safe "$BASE/current" || true)"

  if [[ -z "$releases_root_real" || -z "$current_release_real" ]]; then
    log "WARNING: release pruning skipped because canonical release paths could not be resolved."
    return 0
  fi

  while IFS= read -r candidate_line; do
    candidate_path="${candidate_line#* }"
    [[ -n "$candidate_path" ]] || continue

    candidate_real="$(resolve_realpath_safe "$candidate_path" || true)"
    if [[ -z "$candidate_real" ]]; then
      log "WARNING: skipping release cleanup for unresolved path: $candidate_path"
      continue
    fi
    if [[ ! -d "$candidate_real" ]]; then
      log "WARNING: skipping release cleanup for non-directory path: $candidate_path"
      continue
    fi
    if [[ "$candidate_real" != "$releases_root_real"/* ]]; then
      log "WARNING: refusing to prune path outside releases root: $candidate_real"
      continue
    fi

    if [[ "$candidate_real" == "$current_release_real" || "$candidate_real" == "$current_symlink_real" ]]; then
      continue
    fi

    if (( kept_previous_count < 1 )); then
      kept_previous_count=$((kept_previous_count + 1))
      continue
    fi

    delete_error=""
    if ! delete_error="$(rm -rf -- "$candidate_real" 2>&1)"; then
      log "WARNING: failed to prune old release '$candidate_real': ${delete_error:-no output}"
      continue
    fi
    log "Pruned old release: $candidate_real"
  done < <(
    find "$RELEASES" -mindepth 1 -maxdepth 1 \( -type d -o -type l \) -printf '%T@ %p\n' 2>/dev/null | sort -nr
  )
}

best_effort_local_web_host_header_probe() {
  local py=""
  local host_target=""
  local port=""
  local output=""

  host_target="$(current_host_probe_target)"
  port="$(current_django_port)"
  py="$RUNTIME_VENV_PY"
  [[ -x "$py" ]] || py="$(command -v python3 || true)"
  if [[ -z "$py" ]]; then
    HTTP_PROBE_STATE="skipped"
    mark_degraded "http-probe" "local web probe skipped because no Python interpreter was available"
    return 0
  fi

  if output="$("$py" - "$host_target" "$port" <<'PY'
import http.client
import json
import sys

host = sys.argv[1]
port = int(sys.argv[2])
payload = {"host_header": f"{host}:{port}"}
try:
    conn = http.client.HTTPConnection("127.0.0.1", port, timeout=3)
    conn.request("GET", "/", headers={"Host": f"{host}:{port}"})
    resp = conn.getresponse()
    body = resp.read(200).decode("utf-8", errors="replace")
    conn.close()
    payload.update(
        {
            "status_code": resp.status,
            "reason": resp.reason,
            "body_preview": body[:200],
        }
    )
    ok = 200 <= resp.status < 400
except Exception as exc:
    payload.update(
        {
            "status_code": None,
            "reason": type(exc).__name__,
            "error": str(exc),
        }
    )
    ok = False

print(json.dumps(payload, ensure_ascii=True))
sys.exit(0 if ok else 1)
PY
  )"; then
    HTTP_PROBE_STATE="passed"
    log "Local web host-header probe passed: $output"
    return 0
  fi

  HTTP_PROBE_STATE="failed"
  mark_degraded "http-probe" "local web host-header probe failed for ${host_target}:${port}: ${output:-no output}"
  return 0
}

# --------------------------
# wifi-connect install from payload assets (offline-safe)
# --------------------------
install_wifi_connect_from_payload() {
  local deploy_dir="$1"
  local assets="$deploy_dir/wifi-connect-assets"
  local arch="$(uname -m)"
  local tgz=""

  case "$arch" in
    aarch64|arm64) tgz="$assets/wifi-connect-aarch64-unknown-linux-gnu.tar.gz" ;;
    armv7l|armv7*|armhf) tgz="$assets/wifi-connect-armv7-unknown-linux-gnueabihf.tar.gz" ;;
    *) log "WARNING: Unsupported arch for wifi-connect: $arch"; return 0 ;;
  esac

  ensure_dir /opt/wifi-connect/tmp
  ensure_dir /opt/wifi-connect/ui
  rm -rf /opt/wifi-connect/tmp/* /opt/wifi-connect/ui/* 2>/dev/null || true

  tar -xzf "$tgz" -C /opt/wifi-connect/tmp
  local bin_path=""
  bin_path="$(find /opt/wifi-connect/tmp -maxdepth 5 -type f -name wifi-connect -perm -111 2>/dev/null | head -n 1 || true)"
  [[ -n "$bin_path" ]] || { log "ERROR: wifi-connect binary not found after extract"; return 1; }
  install -m 0755 "$bin_path" /usr/local/bin/wifi-connect

  # Extract UI (layout may vary)
  local ui_tgz="$assets/wifi-connect-ui.tar.gz"
  tar -xzf "$ui_tgz" -C /opt/wifi-connect/ui

  # Find index.html anywhere
  local idx=""
  idx="$(find /opt/wifi-connect/ui -maxdepth 8 -type f -iname index.html 2>/dev/null | head -n 1 || true)"

  touch /etc/default/wifi-connect-manager

  if [[ -n "$idx" ]]; then
    local ui_dir
    ui_dir="$(dirname "$idx")"
    log "UI index.html found at: $idx"
    # Pass ui directory via args
    if grep -q '^WIFI_CONNECT_ARGS=' /etc/default/wifi-connect-manager; then
      sed -i "s|^WIFI_CONNECT_ARGS=.*|WIFI_CONNECT_ARGS=\"--ui-directory $ui_dir\"|g" /etc/default/wifi-connect-manager
    else
      echo "WIFI_CONNECT_ARGS=\"--ui-directory $ui_dir\"" >> /etc/default/wifi-connect-manager
    fi
  else
    log "WARNING: UI index.html NOT found after extract. Will run wifi-connect without --ui-directory (fallback)."
    if grep -q '^WIFI_CONNECT_ARGS=' /etc/default/wifi-connect-manager; then
      sed -i "s|^WIFI_CONNECT_ARGS=.*|WIFI_CONNECT_ARGS=\"\"|g" /etc/default/wifi-connect-manager
    else
      echo "WIFI_CONNECT_ARGS=\"\"" >> /etc/default/wifi-connect-manager
    fi
  fi

  if /usr/local/bin/wifi-connect --help >/dev/null 2>&1; then
    log "wifi-connect OK (arch=$arch)"
  else
    log "WARNING: wifi-connect installed but not executable"
  fi
}

ensure_wifi_env_defaults() {
  local envf="/etc/default/wifi-connect-manager"
  touch "$envf"

  sed -i '/^CONNECTIVITY_TARGETS=/d' "$envf"
  sed -i '/^OFFLINE_GRACE=/d' "$envf"
  sed -i '/^CONNECT_RETRY_INTERVAL=/d' "$envf"
  sed -i '/^ONLINE_OK_REQUIRED=/d' "$envf"
  sed -i '/^HOTSPOT_MIN_UPTIME=/d' "$envf"
  sed -i '/^ALLOW_LIMITED_CONNECTIVITY=/d' "$envf"

  if ! grep -q '^PORTAL_SSID=' "$envf"; then
    echo "PORTAL_SSID=\"${PORTAL_SSID_DEFAULT}\"" >> "$envf"
  fi

  # ensure >=8 chars
  if grep -q '^PORTAL_PASSPHRASE=' "$envf"; then
    local pass
    pass="$(. "$envf" 2>/dev/null; echo "${PORTAL_PASSPHRASE:-}")"
    if [[ "${#pass}" -lt 8 ]]; then
      sed -i "s|^PORTAL_PASSPHRASE=.*|PORTAL_PASSPHRASE=\"${PORTAL_PASSPHRASE_DEFAULT}\"|g" "$envf"
    fi
  else
    echo "PORTAL_PASSPHRASE=\"${PORTAL_PASSPHRASE_DEFAULT}\"" >> "$envf"
  fi

  if ! grep -q '^PORTAL_INTERFACE=' "$envf"; then
    echo "PORTAL_INTERFACE=\"${PORTAL_INTERFACE_DEFAULT}\"" >> "$envf"
  fi

  if ! grep -q '^PORTAL_GATEWAY=' "$envf"; then
    echo "PORTAL_GATEWAY=192.168.42.1" >> "$envf"
  fi

  if ! grep -q '^PORTAL_DHCP_RANGE=' "$envf"; then
    echo "PORTAL_DHCP_RANGE=192.168.42.2,192.168.42.254" >> "$envf"
  fi

  if ! grep -q '^PORTAL_LISTENING_PORT=' "$envf"; then
    echo "PORTAL_LISTENING_PORT=80" >> "$envf"
  fi

  if ! grep -q '^WIFI_COUNTRY=' "$envf"; then
    echo 'WIFI_COUNTRY=RO' >> "$envf"
  fi

  if grep -q '^WIFI_CONNECT_BIN=' "$envf"; then
    sed -i 's|^WIFI_CONNECT_BIN=.*|WIFI_CONNECT_BIN=/usr/local/bin/wifi-connect-launcher|g' "$envf"
  else
    echo 'WIFI_CONNECT_BIN=/usr/local/bin/wifi-connect-launcher' >> "$envf"
  fi

  # ensure exists even if empty
  if ! grep -q '^WIFI_CONNECT_ARGS=' "$envf"; then
    echo 'WIFI_CONNECT_ARGS=""' >> "$envf"
  fi

  if ! grep -q '^BOOT_PORTAL_WINDOW=' "$envf"; then
    echo 'BOOT_PORTAL_WINDOW=180' >> "$envf"
  fi

  if ! grep -q '^CHECK_INTERVAL=' "$envf"; then
    echo 'CHECK_INTERVAL=5' >> "$envf"
  fi

  if ! grep -q '^PORTAL_READY_TIMEOUT=' "$envf"; then
    echo 'PORTAL_READY_TIMEOUT=15' >> "$envf"
  fi

  if ! grep -q '^PORTAL_RESTART_GRACE=' "$envf"; then
    echo 'PORTAL_RESTART_GRACE=20' >> "$envf"
  fi

  if ! grep -q '^RESET_FLAG=' "$envf"; then
    echo 'RESET_FLAG=/data/wifi-reset.flag' >> "$envf"
  fi

  if ! grep -q '^PID_FILE=' "$envf"; then
    echo 'PID_FILE=/run/wifi-connect-manager/wifi-connect.pid' >> "$envf"
  fi
}

# --------------------------
# Deploy assets
# --------------------------
install_deploy_assets() {
  local cur="$1"
  local deploy="$cur/deploy"
  local required=(
    "$deploy/bin/wifi-connect-manager.sh"
    "$deploy/bin/wifi-prep.sh"
    "$deploy/bin/wifi-connect-launcher"
    "$deploy/bin/wifi-reset.sh"
    "$deploy/bin/peoplecounter-ensure-udev"
    "$deploy/bin/peoplecounter-mender-auth-recover"
    "$deploy/bin/visionai-set-ip"
    "$deploy/etc-default/wifi-connect-manager"
    "$deploy/etc-default/peoplecounter"
    "$deploy/systemd/peoplecounter-mender-auth-recover.service"
    "$deploy/systemd/peoplecounter-mender-auth-recover.timer"
    "$deploy/systemd/wifi-connect-manager.service"
    "$deploy/sudoers/visionai-set-ip"
    "$deploy/nm-conf/10-peoplecounter-dns.conf"
    "$deploy/nm-conf/20-peoplecounter-wifi.conf"
    "$deploy/python-assets/manifest.txt"
    "$deploy/python-assets/requirements.lock.txt"
    "$deploy/python-assets/python-3.12-version.txt"
  )
  local f

  for f in "${required[@]}"; do
    [[ -s "$f" ]] || { log "ERROR: Missing deploy asset: $f"; exit 1; }
  done
  if ! grep -q '^wheelhouse_required_ok=yes$' "$deploy/python-assets/manifest.txt"; then
    log "ERROR: deploy/python-assets/manifest.txt indicates wheelhouse_required_ok!=yes."
    exit 1
  fi
  if ! find "$deploy/python-assets/wheels/aarch64-cp312" -maxdepth 1 -type f 2>/dev/null | grep -q .; then
    log "ERROR: arm64 wheelhouse is empty at $deploy/python-assets/wheels/aarch64-cp312."
    exit 1
  fi
  grep -q '^offline_target_install=yes$' "$deploy/python-assets/manifest.txt" || { log "ERROR: manifest missing offline_target_install=yes."; exit 1; }
  grep -q '^runtime_bootstrap=standalone-only$' "$deploy/python-assets/manifest.txt" || { log "ERROR: manifest runtime bootstrap policy mismatch."; exit 1; }
  grep -q '^runtime_online_fallback=controlled$' "$deploy/python-assets/manifest.txt" || { log "ERROR: manifest runtime online fallback policy mismatch."; exit 1; }
  grep -q '^forbidden_runtime_paths=curl,source-build$' "$deploy/python-assets/manifest.txt" || { log "ERROR: manifest forbidden runtime path policy mismatch."; exit 1; }
  grep -q '^wheelhouse_lock_enforced=yes$' "$deploy/python-assets/manifest.txt" || { log "ERROR: manifest missing wheelhouse_lock_enforced=yes."; exit 1; }
  grep -q '^exact_wheel_validation=yes$' "$deploy/python-assets/manifest.txt" || { log "ERROR: manifest missing exact_wheel_validation=yes."; exit 1; }
  grep -q '^lock_policy=root-canonical-deploy-linux-target$' "$deploy/python-assets/manifest.txt" || { log "ERROR: manifest lock policy mismatch."; exit 1; }
  grep -q '^python_supported_arches=aarch64-cp312$' "$deploy/python-assets/manifest.txt" || { log "ERROR: manifest missing python_supported_arches=aarch64-cp312."; exit 1; }
  grep -q '^python_unsupported_arches=armv7-cp312$' "$deploy/python-assets/manifest.txt" || { log "ERROR: manifest missing python_unsupported_arches=armv7-cp312."; exit 1; }
  grep -q '^python_armv7_failure_policy=install-refuse$' "$deploy/python-assets/manifest.txt" || { log "ERROR: manifest missing python_armv7_failure_policy=install-refuse."; exit 1; }
  grep -q '^python_armv7_blocker=depthai==2.30.0.0$' "$deploy/python-assets/manifest.txt" || { log "ERROR: manifest missing python_armv7_blocker=depthai==2.30.0.0."; exit 1; }
  if ! grep -q '^py312_standalone_release_tag=' "$deploy/python-assets/manifest.txt"; then
    log "ERROR: deploy/python-assets/manifest.txt missing py312_standalone_release_tag."
    exit 1
  fi
  if ! grep -q '^runtime_prefix_preferred=' "$deploy/python-assets/manifest.txt"; then
    log "ERROR: deploy/python-assets/manifest.txt missing runtime_prefix_preferred."
    exit 1
  fi
  if ! grep -q '^py312_standalone_preferred_order=' "$deploy/python-assets/manifest.txt"; then
    log "ERROR: deploy/python-assets/manifest.txt missing py312_standalone_preferred_order."
    exit 1
  fi
  if ! { [[ -s "$deploy/python-assets/python312-standalone-aarch64-full.tar.gz" && -s "$deploy/python-assets/python312-standalone-aarch64-full.sha256" ]] || [[ -s "$deploy/python-assets/python312-standalone-aarch64-stripped.tar.gz" && -s "$deploy/python-assets/python312-standalone-aarch64-stripped.sha256" ]]; }; then
    log "ERROR: no valid standalone Python variant pair found in deploy assets."
    exit 1
  fi
  for pinned_pattern in \
    "numpy-${NUMPY_VERSION}-*.whl" \
    "opencv_python_headless-${OPENCV_HEADLESS_VERSION}-*.whl" \
    "depthai-2.30.0.0-*.whl" \
    "depthai_sdk-1.9.1.1-*.whl" \
    "pyturbojpeg-1.6.4-*.whl"; do
    if ! glob_exists_ci "$deploy/python-assets/wheels/aarch64-cp312/$pinned_pattern"; then
      log "ERROR: required pinned wheel missing in deploy assets: $pinned_pattern"
      log_wheel_candidates "$deploy/python-assets/wheels/aarch64-cp312"
      exit 1
    fi
  done
  for pinned_spec in \
    "numpy==${NUMPY_VERSION}" \
    "opencv-python-headless==${OPENCV_HEADLESS_VERSION}" \
    "depthai==2.30.0.0" \
    "depthai-sdk==1.9.1.1" \
    "pyturbojpeg==1.6.4"; do
    if ! grep -qi "^${pinned_spec}$" "$deploy/python-assets/requirements.lock.txt"; then
      log "ERROR: requirements lock missing pinned spec at install time: $pinned_spec"
      exit 1
    fi
  done

  ensure_dir /usr/local/bin
  ensure_dir /usr/local/sbin
  ensure_dir /etc/default
  ensure_dir /etc/sudoers.d
  ensure_dir /etc/systemd/system
  ensure_dir /etc/NetworkManager/conf.d

  install -m 0755 "$deploy/bin/wifi-connect-manager.sh" /usr/local/bin/wifi-connect-manager.sh
  install -m 0755 "$deploy/bin/wifi-prep.sh" /usr/local/bin/wifi-prep.sh
  install -m 0755 "$deploy/bin/wifi-connect-launcher" /usr/local/bin/wifi-connect-launcher
  install -m 0755 "$deploy/bin/wifi-reset.sh" /usr/local/bin/wifi-reset.sh
  install -m 0755 "$deploy/bin/visionai-set-ip" /usr/local/sbin/visionai-set-ip
  install -m 0755 "$deploy/bin/peoplecounter-ensure-udev" /usr/local/sbin/peoplecounter-ensure-udev
  install -m 0755 "$deploy/bin/peoplecounter-mender-auth-recover" /usr/local/sbin/peoplecounter-mender-auth-recover
  strip_crlf /usr/local/bin/wifi-connect-manager.sh
  strip_crlf /usr/local/bin/wifi-prep.sh
  strip_crlf /usr/local/bin/wifi-connect-launcher
  strip_crlf /usr/local/bin/wifi-reset.sh
  strip_crlf /usr/local/sbin/visionai-set-ip
  strip_crlf /usr/local/sbin/peoplecounter-ensure-udev
  strip_crlf /usr/local/sbin/peoplecounter-mender-auth-recover

  install -m 0644 "$deploy/etc-default/wifi-connect-manager" /etc/default/wifi-connect-manager
  install -m 0644 "$deploy/etc-default/peoplecounter" /etc/default/peoplecounter
  strip_crlf /etc/default/wifi-connect-manager
  strip_crlf /etc/default/peoplecounter

  install -m 0644 "$deploy/systemd/wifi-connect-manager.service" /etc/systemd/system/wifi-connect-manager.service
  install -m 0644 "$deploy/systemd/peoplecounter-mender-auth-recover.service" /etc/systemd/system/peoplecounter-mender-auth-recover.service
  install -m 0644 "$deploy/systemd/peoplecounter-mender-auth-recover.timer" /etc/systemd/system/peoplecounter-mender-auth-recover.timer
  install -m 0440 "$deploy/sudoers/visionai-set-ip" /etc/sudoers.d/visionai-set-ip
  install -m 0644 "$deploy/nm-conf/10-peoplecounter-dns.conf" /etc/NetworkManager/conf.d/10-peoplecounter-dns.conf
  install -m 0644 "$deploy/nm-conf/20-peoplecounter-wifi.conf" /etc/NetworkManager/conf.d/20-peoplecounter-wifi.conf
  strip_crlf /etc/systemd/system/wifi-connect-manager.service
  strip_crlf /etc/systemd/system/peoplecounter-mender-auth-recover.service
  strip_crlf /etc/systemd/system/peoplecounter-mender-auth-recover.timer
  strip_crlf /etc/sudoers.d/visionai-set-ip
  strip_crlf /etc/NetworkManager/conf.d/10-peoplecounter-dns.conf
  strip_crlf /etc/NetworkManager/conf.d/20-peoplecounter-wifi.conf

  if command -v visudo >/dev/null 2>&1; then
    visudo -cf /etc/sudoers.d/visionai-set-ip >/dev/null 2>&1 || {
      log "ERROR: invalid sudoers file /etc/sudoers.d/visionai-set-ip"
      exit 1
    }
  fi

  rm -f /etc/systemd/system/wifi-connect-manager.service.d/10-wifi-prep.conf >/dev/null 2>&1 || true
}

clear_wifi_connect_runtime_state() {
  local runtime_dir="/run/wifi-connect-manager"
  mkdir -p "$runtime_dir"
  find "$runtime_dir" -mindepth 1 -maxdepth 1 -exec rm -rf {} + >/dev/null 2>&1 || true
}

clear_peoplecounter_static_root() {
  local static_root="$BASE/var/staticfiles"
  mkdir -p "$static_root"
  find "$static_root" -mindepth 1 -maxdepth 1 -exec rm -rf {} + >/dev/null 2>&1 || true
}

# --------------------------
# PeopleCounter runner + unit (stable)
# --------------------------
install_peoplecounter_runner() {
  cat > /usr/local/bin/peoplecounter-runner <<'RUN'
#!/usr/bin/env bash
set -euo pipefail
BASE="/data/peoplecounter"
APP_DIR="$BASE/current"
LIVE_VENV="$BASE/venv"
PREV_VENV="${LIVE_VENV}.previous"
LIVE_RUNTIME_PRIMARY="$BASE/runtime"
LIVE_RUNTIME_FALLBACK="/opt/peoplecounter"
PREV_RUNTIME_PRIMARY="${LIVE_RUNTIME_PRIMARY}.previous"
PREV_RUNTIME_FALLBACK="${LIVE_RUNTIME_FALLBACK}.previous"
PY="$LIVE_VENV/bin/python"
LAUNCH="$APP_DIR/launch.py"
STATUS_FILE="$BASE/var/deploy-status.json"
PIP_LOG_FILE="/var/log/peoplecounter-runner-repair.log"
NUMPY_SPEC="numpy==1.26.4"
OPENCV_HEADLESS_SPEC="opencv-python-headless==4.8.1.78"
REPAIR_ACTION="none"
VENV_STATE_REASON="unknown"

log() {
  echo "[peoplecounter-runner] $*" >&2
}

json_escape() {
  local value="${1:-}"
  value="${value//\\/\\\\}"
  value="${value//\"/\\\"}"
  value="${value//$'\n'/\\n}"
  value="${value//$'\r'/}"
  value="${value//$'\t'/\\t}"
  printf '%s' "$value"
}

camera_preflight_state() {
  local output=""
  if [[ ! -x /usr/local/sbin/peoplecounter-ensure-udev ]]; then
    printf 'unavailable\n'
    return 0
  fi
  output="$(/usr/local/sbin/peoplecounter-ensure-udev --json --check-only 2>/dev/null || true)"
  if grep -Eq '"ok"[[:space:]]*:[[:space:]]*true' <<<"$output"; then
    printf 'passed\n'
  else
    printf 'failed\n'
  fi
}

write_runner_status() {
  local state="$1"
  local reason="$2"
  local current_release=""
  local camera_state=""

  mkdir -p "$BASE/var" >/dev/null 2>&1 || true
  current_release="$(readlink -f "$APP_DIR" 2>/dev/null || true)"
  camera_state="$(camera_preflight_state)"
  cat > "$STATUS_FILE" <<JSON
{
  "timestamp_utc": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
  "state": "$(json_escape "$state")",
  "phase": "runner-start",
  "reason": "$(json_escape "$reason")",
  "repair_action": "$(json_escape "$REPAIR_ACTION")",
  "venv_state_reason": "$(json_escape "$VENV_STATE_REASON")",
  "camera_preflight": "$(json_escape "$camera_state")",
  "current_release": "$(json_escape "$current_release")"
}
JSON
  chmod 0644 "$STATUS_FILE" >/dev/null 2>&1 || true
}

runtime_prefix_python_path() {
  local prefix="$1"
  local candidate=""
  for candidate in \
    "$prefix/python312-standalone/python/bin/python3.12" \
    "$prefix/python/bin/python3.12" \
    "$prefix/bin/python3.12"; do
    [[ -x "$candidate" ]] || continue
    printf '%s\n' "$candidate"
    return 0
  done
  return 1
}

runtime_prefix_state() {
  local prefix="$1"
  local py=""

  [[ -d "$prefix" ]] || { printf 'runtime-dir-missing\n'; return 1; }
  py="$(runtime_prefix_python_path "$prefix" || true)"
  [[ -n "$py" ]] || { printf 'runtime-python-missing\n'; return 1; }
  if ! "$py" - <<'PY' >/dev/null 2>&1; then
import sys
print(sys.executable)
PY
    printf 'runtime-python-not-runnable\n'
    return 1
  fi
  printf 'ok\n'
  return 0
}

venv_candidate_state() {
  local candidate="$1"
  local py="$candidate/bin/python"

  [[ -d "$candidate" ]] || { printf 'live-venv-missing\n'; return 1; }
  [[ -e "$py" ]] || { printf 'live-python-missing\n'; return 1; }
  [[ -x "$py" ]] || { printf 'live-python-not-executable\n'; return 1; }
  if ! "$py" - <<'PY' >/dev/null 2>&1; then
import sys
print(sys.executable)
print(sys.version)
PY
    printf 'live-python-broken\n'
    return 1
  fi
  if ! "$py" - <<'PY' >/dev/null 2>&1; then
import cv2
import depthai
import django
import numpy
PY
    printf 'core-import-failure\n'
    return 1
  fi
  if ! "$py" -m pip check >>"$PIP_LOG_FILE" 2>&1; then
    log "WARNING: pip check reported issues for $candidate; continuing because core imports succeeded."
  fi
  printf 'ok\n'
  return 0
}

refresh_live_venv_state() {
  VENV_STATE_REASON="$(venv_candidate_state "$LIVE_VENV" || true)"
  [[ "$VENV_STATE_REASON" == "ok" ]]
}

promote_valid_venv_candidate() {
  local candidate="$1"
  local target="$2"
  local label="$3"
  local state=""

  state="$(venv_candidate_state "$candidate" || true)"
  if [[ "$state" != "ok" ]]; then
    log "${label} is invalid: $candidate ($state)"
    return 1
  fi

  rm -rf "$target" >/dev/null 2>&1 || true
  mv "$candidate" "$target" || return 1
  return 0
}

promote_previous_venv_backup() {
  if [[ ! -e "$PREV_VENV" ]]; then
    return 1
  fi
  if promote_valid_venv_candidate "$PREV_VENV" "$LIVE_VENV" "previous venv"; then
    log "restored previous venv"
    return 0
  fi
  return 1
}

promote_valid_runtime_candidate() {
  local candidate="$1"
  local target="$2"
  local label="$3"
  local state=""

  state="$(runtime_prefix_state "$candidate" || true)"
  if [[ "$state" != "ok" ]]; then
    log "${label} is invalid: $candidate ($state)"
    return 1
  fi

  rm -rf "$target" >/dev/null 2>&1 || true
  mv "$candidate" "$target" || return 1
  return 0
}

restore_previous_runtime_if_needed() {
  local restored=0
  local state=""

  state="$(runtime_prefix_state "$LIVE_RUNTIME_PRIMARY" || true)"
  if [[ "$state" != "ok" && -e "$PREV_RUNTIME_PRIMARY" ]]; then
    promote_valid_runtime_candidate "$PREV_RUNTIME_PRIMARY" "$LIVE_RUNTIME_PRIMARY" "previous runtime prefix" || return 1
    restored=1
  fi
  state="$(runtime_prefix_state "$LIVE_RUNTIME_FALLBACK" || true)"
  if [[ "$state" != "ok" && -e "$PREV_RUNTIME_FALLBACK" ]]; then
    promote_valid_runtime_candidate "$PREV_RUNTIME_FALLBACK" "$LIVE_RUNTIME_FALLBACK" "previous runtime prefix" || return 1
    restored=1
  fi

  if (( restored == 1 )); then
    log "restored previous runtime prefix"
  fi
  return 0
}

select_runtime_python() {
  local candidate=""
  for candidate in \
    "$LIVE_RUNTIME_PRIMARY/python312-standalone/python/bin/python3.12" \
    "$LIVE_RUNTIME_FALLBACK/python312-standalone/python/bin/python3.12" \
    "$(command -v python3 2>/dev/null || true)"; do
    [[ -n "$candidate" && -x "$candidate" ]] || continue
    printf '%s\n' "$candidate"
    return 0
  done
  return 1
}

offline_tooling_refresh_specs() {
  local wheel_dir="$1"
  local tool=""
  for tool in pip setuptools wheel; do
    if compgen -G "$wheel_dir/${tool}-*.whl" >/dev/null 2>&1; then
      printf '%s\n' "$tool"
    fi
  done
}

maybe_refresh_offline_tooling() {
  local py="$1"
  local wheel_dir="$2"
  local specs=()
  local spec=""

  while IFS= read -r spec; do
    [[ -n "$spec" ]] && specs+=("$spec")
  done < <(offline_tooling_refresh_specs "$wheel_dir")

  if [[ "${#specs[@]}" -eq 0 ]]; then
    log "runner repair skipped offline pip/setuptools/wheel refresh because those wheels are not bundled"
    return 0
  fi

  if ! "$py" -m pip install \
    --no-index --find-links "$wheel_dir" --upgrade "${specs[@]}" >>"$PIP_LOG_FILE" 2>&1; then
    log "WARNING: offline ${specs[*]} refresh failed during runner repair; continuing."
  fi
}

promote_existing_repair_venv() {
  local candidate=""
  while IFS= read -r candidate; do
    [[ -d "$candidate" ]] || continue
    if promote_valid_venv_candidate "$candidate" "$LIVE_VENV" "repair venv"; then
      log "promoted existing repair venv: $candidate -> $LIVE_VENV"
      return 0
    fi
    log "removing invalid repair venv candidate: $candidate"
    rm -rf "$candidate" >/dev/null 2>&1 || true
  done < <(ls -1dt "$LIVE_VENV".repair.* 2>/dev/null || true)
  return 1
}

rebuild_live_venv_offline() {
  local runtime_py=""
  local req="$APP_DIR/requirements.txt"
  local lock_file="$APP_DIR/deploy/python-assets/requirements.lock.txt"
  local wheel_dir="$APP_DIR/deploy/python-assets/wheels/aarch64-cp312"
  local tmp_venv="${LIVE_VENV}.repair.$$"

  [[ -s "$req" ]] || { log "ERROR: requirements.txt missing: $req"; return 1; }
  [[ -s "$lock_file" ]] || { log "ERROR: requirements lock missing: $lock_file"; return 1; }
  [[ -d "$wheel_dir" ]] || { log "ERROR: wheelhouse missing: $wheel_dir"; return 1; }

  runtime_py="$(select_runtime_python || true)"
  [[ -n "$runtime_py" ]] || { log "ERROR: no runtime python available to rebuild live venv"; return 1; }

  rm -rf "$tmp_venv" >/dev/null 2>&1 || true
  if ! "$runtime_py" -m venv "$tmp_venv" >>"$PIP_LOG_FILE" 2>&1; then
    rm -rf "$tmp_venv" >/dev/null 2>&1 || true
    return 1
  fi
  [[ -x "$tmp_venv/bin/python" ]] || { rm -rf "$tmp_venv" >/dev/null 2>&1 || true; return 1; }

  if ! {
    maybe_refresh_offline_tooling "$tmp_venv/bin/python" "$wheel_dir" &&
    "$tmp_venv/bin/python" -m pip install --no-index --find-links "$wheel_dir" --only-binary=numpy "$NUMPY_SPEC" >>"$PIP_LOG_FILE" 2>&1 &&
    "$tmp_venv/bin/python" -m pip install --no-index --find-links "$wheel_dir" -r "$lock_file" >>"$PIP_LOG_FILE" 2>&1 &&
    "$tmp_venv/bin/python" -m pip install --no-index --find-links "$wheel_dir" -r "$req" -c "$lock_file" >>"$PIP_LOG_FILE" 2>&1 &&
    "$tmp_venv/bin/python" -m pip install --no-index --find-links "$wheel_dir" --force-reinstall --no-deps "$OPENCV_HEADLESS_SPEC" >>"$PIP_LOG_FILE" 2>&1
  }; then
    rm -rf "$tmp_venv" >/dev/null 2>&1 || true
    return 1
  fi

  if ! promote_valid_venv_candidate "$tmp_venv" "$LIVE_VENV" "rebuilt live venv"; then
    rm -rf "$tmp_venv" >/dev/null 2>&1 || true
    return 1
  fi
  log "rebuilt live venv from current release"
  return 0
}

log "using LAUNCH=$LAUNCH"

if [[ ! -s "$LAUNCH" ]]; then
  log "ERROR: launch.py missing or empty ($LAUNCH)"
  write_runner_status "degraded" "launch.py missing or empty"
  exit 11
fi

if ! refresh_live_venv_state; then
  log "live venv is not ready: $VENV_STATE_REASON"
  restore_previous_runtime_if_needed || true
  if refresh_live_venv_state; then
    REPAIR_ACTION="restored-previous-runtime"
  elif promote_previous_venv_backup; then
    if refresh_live_venv_state; then
      REPAIR_ACTION="restored-previous-venv"
    else
      REPAIR_ACTION="repair-failed-invalid-backup"
    fi
  elif promote_existing_repair_venv; then
    if refresh_live_venv_state; then
      REPAIR_ACTION="repair-dir-promoted"
    else
      REPAIR_ACTION="repair-failed-invalid-backup"
    fi
  elif rebuild_live_venv_offline; then
    if refresh_live_venv_state; then
      REPAIR_ACTION="rebuilt-live-venv"
    else
      REPAIR_ACTION="repair-rebuild-failed"
    fi
  else
    if [[ -e "$PREV_VENV" ]]; then
      REPAIR_ACTION="repair-failed-invalid-backup"
    else
      REPAIR_ACTION="repair-failed-no-runtime"
    fi
    refresh_live_venv_state || true
  fi
fi

if ! refresh_live_venv_state; then
  log "ERROR: live python venv is not usable: $PY ($VENV_STATE_REASON)"
  write_runner_status "degraded" "python venv unusable after repair attempt"
  exit 11
fi

if [[ "$REPAIR_ACTION" != "none" ]]; then
  write_runner_status "healthy" "runner ready after repair"
fi
exec "$PY" "$LAUNCH"
RUN
  chmod 0755 /usr/local/bin/peoplecounter-runner
}

ensure_visionai_user() {
  if ! id visionai >/dev/null 2>&1; then
    useradd --system --home /data/peoplecounter --shell /usr/sbin/nologin visionai >/dev/null 2>&1 \
      || useradd -r -d /data/peoplecounter -s /usr/sbin/nologin visionai >/dev/null 2>&1 \
      || { log "ERROR: failed to create visionai user"; exit 1; }
  fi
  if ! getent group plugdev >/dev/null 2>&1; then
    groupadd -f plugdev >/dev/null 2>&1 || true
  fi

  local grp
  for grp in video render netdev plugdev; do
    if getent group "$grp" >/dev/null 2>&1; then
      usermod -aG "$grp" visionai >/dev/null 2>&1 || true
    fi
  done
}

write_peoplecounter_unit() {
  cat > /etc/systemd/system/peoplecounter.service <<'UNIT'
[Unit]
Description=PeopleCounter Application
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
EnvironmentFile=-/etc/default/peoplecounter
User=root
Group=root
WorkingDirectory=/data/peoplecounter/current
Environment=PYTHONUNBUFFERED=1
ExecStartPre=+/usr/local/sbin/peoplecounter-ensure-udev
ExecStart=/usr/local/bin/peoplecounter-runner
Restart=on-failure
RestartSec=3
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target
UNIT
  strip_crlf /etc/systemd/system/peoplecounter.service
}

# --------------------------
# MAIN
# --------------------------
require_root "$@"
trap 'rc=$?; trap - EXIT; finalize_deploy_status "$rc"; exit "$rc"' EXIT
prepare_install_pip_cache
init_python_log
init_pip_log
log "INSTALL_STAGE_POLICY: build-time internet is allowed only to assemble artifact."
log "INSTALL_STAGE_POLICY: target install is offline-first; controlled online recovery is permitted."
log "INSTALL_STAGE_POLICY: no auto-update behavior is allowed."
normalize_locale_defaults
fix_mender_device_type

[[ -d "$LATEST_DIR" ]] || { log "ERROR: Release dir missing: $LATEST_DIR"; exit 1; }

APP_DIR="$LATEST_DIR"
[[ -d "$LATEST_DIR/PeopleTrackerDepthAI" ]] && APP_DIR="$LATEST_DIR/PeopleTrackerDepthAI"

if [[ ! -s "$APP_DIR/launch.py" ]]; then
  log "ERROR: launch.py missing/empty after deploy: $APP_DIR/launch.py"
  exit 11
fi

ensure_visionai_user

install -d -m 0755 "$BASE" "$RELEASES" "$BASE/config" "$BASE/state" "$BASE/logs" "$BASE/var" "$BASE/var/pycache" "$BASE/var/staticfiles" "$BASE/events"

chown -R root:root "$APP_DIR" "$BASE/config" "$BASE/state" "$BASE/logs" "$BASE/var" "$BASE/events" >/dev/null 2>&1 || true
install -d -m 0755 /data/tmp /data/pip-cache
chown -R root:root /data/tmp /data/pip-cache >/dev/null 2>&1 || true
write_release_metadata

install_deploy_assets "$APP_DIR"

if [[ -s "$APP_DIR/deploy/python-assets/manifest.txt" ]]; then
  log "Python asset manifest:"
  sed 's/^/[peoplecounter-install] manifest: /' "$APP_DIR/deploy/python-assets/manifest.txt" >&2 || true
fi

ensure_python_runtime

# WiFi: install binary from payload and enforce runtime defaults
install_wifi_connect_from_payload "$APP_DIR/deploy"
ensure_wifi_env_defaults

install_peoplecounter_runner
write_peoplecounter_unit
verify_oak_udev_install

if ! command -v systemctl >/dev/null 2>&1; then
  log "ERROR: systemctl not found; cannot activate deployed runtime."
  exit 1
fi

if activate_new_release_runtime "$APP_DIR"; then
  log "New release runtime activated successfully."
else
  if [[ "$ACTIVATION_RESTORE_STATE" == "restored" ]]; then
    mark_degraded "activation" "new release activation failed; restored previous runtime"
  else
    log "ERROR: new release activation failed and previous runtime could not be restored: ${ACTIVATION_RESTORE_REASON:-unknown}"
    exit 1
  fi
fi
cleanup_runtime_staging_paths
set_root_managed_permissions
clear_wifi_connect_runtime_state
clear_peoplecounter_static_root

if command -v systemctl >/dev/null 2>&1; then
  systemctl disable --now dnsmasq.service >/dev/null 2>&1 || true
  systemctl daemon-reload || true
  systemctl enable wifi-connect-manager.service >/dev/null 2>&1 || true
  systemctl enable peoplecounter.service >/dev/null 2>&1 || true
  systemctl enable peoplecounter-mender-auth-recover.timer >/dev/null 2>&1 || true
  systemctl restart wifi-connect-manager.service >/dev/null 2>&1 || true
  SERVICE_RESTART_ATTEMPTED=1
  if systemctl restart peoplecounter.service >/dev/null 2>&1; then
    log "peoplecounter.service restart requested."
  else
    mark_degraded "service-restart" "peoplecounter.service restart failed during install"
  fi
  if systemctl is-active --quiet peoplecounter.service; then
    SERVICE_ACTIVE_STATE="active"
    log "peoplecounter.service is active after restart."
  else
    SERVICE_ACTIVE_STATE="inactive"
    mark_degraded "service-active-check" "peoplecounter.service is not active after restart"
    systemctl status peoplecounter.service --no-pager >&2 || true
  fi
  best_effort_local_web_host_header_probe
  if [[ "$SERVICE_ACTIVE_STATE" == "active" ]]; then
    if [[ "$RELEASE_ACTIVATED" -eq 1 ]]; then
      cleanup_activation_backups
    else
      log "WARNING: previous runtime restored; activation backups not pruned for failed new release."
    fi
  else
    log "WARNING: keeping activation backups in place for runtime self-heal."
  fi
  if [[ "$RELEASE_ACTIVATED" -eq 1 ]]; then
    prune_old_releases
  else
    log "WARNING: skipping old release pruning because the new release did not activate."
  fi
  systemctl start peoplecounter-mender-auth-recover.timer >/dev/null 2>&1 || true
fi

DEPLOY_PHASE="completed"
if [[ "$DEPLOY_STATE" == "degraded" ]]; then
  append_deploy_reason "deploy completed in degraded state"
else
  DEPLOY_STATE="healthy"
  append_deploy_reason "deploy completed"
fi
log "Install complete. Final state: ${DEPLOY_STATE}"
EOS

# inject constants
sed -i "s|__RELEASE_ID__|$RELEASE_ID|g" "$WORK/ArtifactInstall_Leave_50"
sed -i "s|__ARTIFACT_VERSION__|$VERSION|g" "$WORK/ArtifactInstall_Leave_50"
sed -i "s|__BUILD_GIT_SHA__|${GIT_SHA:-none}|g" "$WORK/ArtifactInstall_Leave_50"
sed -i "s|__BUILD_TS__|$TS|g" "$WORK/ArtifactInstall_Leave_50"
sed -i "s|__PORTAL_SSID__|$PORTAL_SSID_DEFAULT|g" "$WORK/ArtifactInstall_Leave_50"
sed -i "s|__PORTAL_PASS__|$PORTAL_PASSPHRASE_DEFAULT|g" "$WORK/ArtifactInstall_Leave_50"
sed -i "s|__PORTAL_IFACE__|$PORTAL_INTERFACE_DEFAULT|g" "$WORK/ArtifactInstall_Leave_50"
chmod +x "$WORK/ArtifactInstall_Leave_50"

# Build device-type args
DT_ARGS=()
for dt in "${DEVICE_TYPES[@]}"; do DT_ARGS+=(--device-type "$dt"); done

mender-artifact write module-image \
  --artifact-name "$ARTIFACT_NAME" \
  "${DT_ARGS[@]}" \
  --type directory \
  --compression "$COMPRESSION" \
  --file "$WORK/update.tar" \
  --file "$WORK/dest_dir" \
  --script "$WORK/ArtifactInstall_Enter_00" \
  --script "$WORK/ArtifactInstall_Leave_50" \
  --output-path "$OUT_PATH"

sync_canonical_script_to_unc

echo "Built: $OUT_PATH"
echo "Verify:"
echo "  mender-artifact read \"$OUT_PATH\" | grep -Ei 'Name:|device_types_compatible|Type:'"
