#!/bin/bash

# ZeeKit Platform v1 macOS Installer.
#
# This file deliberately contains all executable Installer logic. Platform
# Bundles are signed data: they cannot add shell, ADB, or package-manager
# commands. Production execution uses only macOS command-line facilities and
# the official, source-pinned Android Debug Bridge below.

set -u
set -o pipefail
umask 077
PATH=/usr/bin:/bin:/usr/sbin:/sbin
export PATH
export LC_ALL=C

INSTALLER_VERSION="1"
PLATFORM_BUNDLE_SCHEMA="1"
PUBLIC_ORIGIN="https://downloads.zeekit.ru"
CURRENT_INSTALLER_URL="https://downloads.zeekit.ru/installer/macos/ZeeKitInstaller.command"
PLATFORM_BUNDLE_KEY_ID="f437f5f344b5375ded7ebd62221fb748adc21277bb565f8587222d27a397bd5b"
PLATFORM_SIGNER_SHA256="c8a2e9bccf597c2fb6dc66bee293fc13f2fc47ec77bc6b2b0d52c11f51192ab8"
APP_SIGNER_SHA256="c0c597caa241591911ca52460736c440b19cc1049edbb676d5aad51c264e5783"

ADB_VERSION="36.0.0"
ADB_ARCHIVE_URL="https://dl.google.com/android/repository/platform-tools_r36.0.0-darwin.zip"
ADB_ARCHIVE_SHA256="d3e9fa1df3345cf728586908426615a60863d2632f73f1ce14f0f1349ef000fd"
ADB_BINARY_SHA256="0e8bb380b1993eac9d2433a05d92a33035971cd25542b1c36b3537ddd6defe94"
TEST_BOUNDARY_MARKER_SHA256="882f2b627f6cf8fe1fd0a0399e1c109b242e0af7f3fb89d3cccbc2f1acbaba98"
TEST_BUNDLE_KEY_ID="9dff65aee5f29c5538fccdea9666d9cea5705a3074b55e95cecfb0dacafc77a2"
TEST_APK_SIGNER_SHA256="393ad443c8905531ebc004d05eb75de4c7a9ea9331af11facd4e29fa19ff6d07"
TEST_ADB_SHA256="06ef74d1e9d1af5d37d8dbdc0381d5d5d8f03099898aac5ebc5e9681abdaea2d"

SYSTEM_UPDATER_PACKAGE="ru.zeekit.packageupdater"
CORE_PACKAGE="ru.zeekit.core"
MANAGER_PACKAGE="ru.zeekit.manager"
CORE_REPAIR_COMPONENT="ru.zeekit.core/.CorePlatformInputRepairActivity"

CURRENT_PHASE="startup"
CURRENT_COMPONENT="installer"
WORK_ROOT=""
LOG_FILE=""
JXA_HELPER=""
TRUST_KEY=""
ADB_PATH=""
SELECTED_SERIAL=""
BUNDLE_DIRECTORY=""
BUNDLE_ID=""
DOWNLOAD_ORIGIN="$PUBLIC_ORIGIN"
ONLINE_MODE=0
READINESS_INCOMPLETE=0
TEST_BOUNDARY_ACTIVE=0
TEST_REPOSITORY=""
REPAIR_WAIT_ATTEMPTS=10
REPAIR_WAIT_SECONDS=1

cleanup() {
  if [ -n "$WORK_ROOT" ] && [ -d "$WORK_ROOT" ]; then
    /bin/rm -rf "$WORK_ROOT"
  fi
}

trap cleanup EXIT HUP INT TERM

timestamp() {
  /bin/date -u '+%Y-%m-%dT%H:%M:%SZ'
}

log_detail() {
  if [ -n "$LOG_FILE" ]; then
    /usr/bin/printf '%s phase=%s component=%s %s\n' \
      "$(timestamp)" "$CURRENT_PHASE" "$CURRENT_COMPONENT" "$1" >> "$LOG_FILE"
  fi
}

fail() {
  code="$1"
  guidance="$2"
  log_detail "result=FAILED code=$code detail=$guidance"
  /usr/bin/printf 'FAILED [%s/%s]: %s\n%s\nLog: %s\n' \
    "$CURRENT_PHASE" "$CURRENT_COMPONENT" "$code" "$guidance" "$LOG_FILE" >&2
  exit 1
}

setup_incomplete() {
  log_detail "result=SETUP_INCOMPLETE"
  /usr/bin/printf 'SETUP_INCOMPLETE: ZeeKit APKs remain installed, but Platform Readiness is incomplete.\n'
  /usr/bin/printf 'Run this Installer again to Repair after resolving the listed permission or prerequisite.\n'
  /usr/bin/printf 'Log: %s\n' "$LOG_FILE"
  exit 2
}

usage() {
  fail "ARGUMENTS_INVALID" "Usage: $0 [--bundle <local-platform-bundle>]"
}

sha256_file() {
  /usr/bin/shasum -a 256 "$1" | /usr/bin/awk '{print $1}'
}

public_key_id() {
  /usr/bin/openssl pkey -pubin -in "$1" -outform DER 2>/dev/null \
    | /usr/bin/shasum -a 256 \
    | /usr/bin/awk '{print $1}'
}

write_embedded_trust_key() {
  /bin/cat > "$TRUST_KEY" <<'EOF_TRUST_KEY'
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEID6bfURnQVK4CYLFC/c9zJV4GaR1
w86f1iKF3d5rqxWlwt2kxKJjJdVz5ElY7osYnVw/yoy+ng3gLBul8B2hAg==
-----END PUBLIC KEY-----
EOF_TRUST_KEY
}

write_jxa_helper() {
  /bin/cat > "$JXA_HELPER" <<'EOF_JXA'
ObjC.import("Foundation");

function reject(code) {
  throw new Error(code);
}

function readText(path) {
  const text = $.NSString.stringWithContentsOfFileEncodingError(
    path,
    $.NSUTF8StringEncoding,
    null,
  );
  if (!text) reject("INSTALLER_FILE_READ_FAILED");
  return ObjC.unwrap(text);
}

function decodeBase64(value) {
  const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  const output = [];
  let accumulator = 0;
  let bits = 0;
  for (let index = 0; index < value.length; index += 1) {
    const character = value.charAt(index);
    if (character === "=") break;
    const digit = alphabet.indexOf(character);
    if (digit < 0) continue;
    accumulator = accumulator * 64 + digit;
    bits += 6;
    if (bits >= 8) {
      bits -= 8;
      output.push(Math.floor(accumulator / Math.pow(2, bits)) & 0xff);
      accumulator %= Math.pow(2, bits);
    }
  }
  return output;
}

function readBytes(path) {
  const data = $.NSData.dataWithContentsOfFile(path);
  if (!data) reject("INSTALLER_FILE_READ_FAILED");
  return decodeBase64(ObjC.unwrap(data.base64EncodedStringWithOptions(0)));
}

function canonical(value) {
  if (value === null || typeof value === "boolean" || typeof value === "string") {
    return JSON.stringify(value);
  }
  if (typeof value === "number") {
    if (!Number.isFinite(value)) reject("INSTALLER_MANIFEST_INVALID");
    return JSON.stringify(value);
  }
  if (Array.isArray(value)) {
    return "[" + value.map(canonical).join(",") + "]";
  }
  if (typeof value === "object") {
    return "{" + Object.keys(value).sort().map(function (key) {
      return JSON.stringify(key) + ":" + canonical(value[key]);
    }).join(",") + "}";
  }
  reject("INSTALLER_MANIFEST_INVALID");
}

function exactKeys(value, expected) {
  if (value === null || Array.isArray(value) || typeof value !== "object") return false;
  const actual = Object.keys(value).sort();
  const wanted = expected.slice().sort();
  return actual.length === wanted.length && actual.every(function (key, index) {
    return key === wanted[index];
  });
}

function equal(left, right) {
  return canonical(left) === canonical(right);
}

function validateEcdsaP256Signature(path) {
  const bytes = readBytes(path);
  if (bytes.length < 8 || bytes.length > 72 || bytes[0] !== 0x30) {
    reject("INSTALLER_SIGNATURE_DER_INVALID");
  }
  const sequenceLength = bytes[1];
  if ((sequenceLength & 0x80) !== 0 || sequenceLength !== bytes.length - 2) {
    reject("INSTALLER_SIGNATURE_DER_INVALID");
  }
  let cursor = 2;
  for (let integer = 0; integer < 2; integer += 1) {
    if (cursor + 2 > bytes.length || bytes[cursor] !== 0x02) {
      reject("INSTALLER_SIGNATURE_DER_INVALID");
    }
    const length = bytes[cursor + 1];
    cursor += 2;
    if (length < 1 || length > 33 || cursor + length > bytes.length) {
      reject("INSTALLER_SIGNATURE_DER_INVALID");
    }
    const first = bytes[cursor];
    if ((first & 0x80) !== 0) reject("INSTALLER_SIGNATURE_DER_INVALID");
    if (length > 1 && first === 0 && (bytes[cursor + 1] & 0x80) === 0) {
      reject("INSTALLER_SIGNATURE_DER_INVALID");
    }
    cursor += length;
  }
  if (cursor !== bytes.length) reject("INSTALLER_SIGNATURE_DER_INVALID");
}

function validateManifest(path, trustKeyId, platformSigner, appSigner) {
  const source = readText(path);
  let manifest;
  try {
    manifest = JSON.parse(source);
  } catch (_) {
    reject("INSTALLER_MANIFEST_INVALID");
  }
  if (!manifest || manifest.schemaVersion !== 1) {
    reject("INSTALLER_SCHEMA_UNSUPPORTED");
  }
  if (source !== canonical(manifest) + "\n") {
    reject("INSTALLER_MANIFEST_NOT_CANONICAL");
  }
  if (!exactKeys(manifest, [
    "schemaVersion",
    "sourceRevision",
    "createdAt",
    "bundleSigner",
    "artifacts",
    "installationOrder",
    "platformReadiness",
  ])) reject("INSTALLER_MANIFEST_SCHEMA_INVALID");
  if (typeof manifest.sourceRevision !== "string" || !/^(?:[0-9a-f]{40}|[0-9a-f]{64})$/.test(manifest.sourceRevision)) {
    reject("INSTALLER_MANIFEST_PROVENANCE_INVALID");
  }
  if (typeof manifest.createdAt !== "string" || !/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$/.test(manifest.createdAt)) {
    reject("INSTALLER_MANIFEST_PROVENANCE_INVALID");
  }
  if (!equal(manifest.bundleSigner, {
    algorithm: "ECDSA_P256_SHA256",
    publicKeySha256: trustKeyId,
  })) reject("INSTALLER_BUNDLE_SIGNER_IDENTITY_INVALID");

  const expected = [
    ["system-updater", "system-updater.apk", "ru.zeekit.packageupdater", 1, platformSigner],
    ["core", "core.apk", "ru.zeekit.core", 1000, appSigner],
    ["manager", "manager.apk", "ru.zeekit.manager", 1000, appSigner],
  ];
  if (!Array.isArray(manifest.artifacts) || manifest.artifacts.length !== expected.length) {
    reject("INSTALLER_ARTIFACT_IDENTITIES_INVALID");
  }
  expected.forEach(function (wanted, index) {
    const artifact = manifest.artifacts[index];
    if (!exactKeys(artifact, ["role", "filename", "packageName", "versionCode", "sha256", "signerSha256"])) {
      reject("INSTALLER_ARTIFACT_IDENTITIES_INVALID");
    }
    if (
      artifact.role !== wanted[0] ||
      artifact.filename !== wanted[1] ||
      artifact.packageName !== wanted[2] ||
      artifact.versionCode !== wanted[3] ||
      artifact.signerSha256 !== wanted[4] ||
      typeof artifact.sha256 !== "string" ||
      !/^[0-9a-f]{64}$/.test(artifact.sha256)
    ) reject("INSTALLER_ARTIFACT_IDENTITIES_INVALID");
  });
  if (!equal(manifest.installationOrder, ["system-updater", "core", "manager"])) {
    reject("INSTALLER_INSTALLATION_ORDER_INVALID");
  }
  const readiness = {
    requiredSystemFeatures: [],
    packages: [
      {
        artifactRole: "system-updater",
        enabled: true,
        requiredPermissions: [
          "android.permission.FORCE_STOP_PACKAGES",
          "android.permission.START_ACTIVITIES_FROM_BACKGROUND",
          "android.permission.START_ANY_ACTIVITY",
          "android.permission.INSTALL_PACKAGES",
          "android.permission.DELETE_PACKAGES",
          "android.permission.GRANT_RUNTIME_PERMISSIONS",
          "android.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS",
          "android.permission.CHANGE_COMPONENT_ENABLED_STATE",
        ],
        forbiddenPermissionFlags: [],
      },
      {
        artifactRole: "core",
        enabled: true,
        requiredPermissions: [
          "android.permission.ACCESS_COARSE_LOCATION",
          "android.permission.ACCESS_FINE_LOCATION",
          "android.permission.ACCESS_BACKGROUND_LOCATION",
        ],
        forbiddenPermissionFlags: ["ONE_TIME"],
      },
      {
        artifactRole: "manager",
        enabled: true,
        requiredPermissions: [],
        forbiddenPermissionFlags: [],
      },
    ],
  };
  if (!equal(manifest.platformReadiness, readiness)) {
    reject("INSTALLER_READINESS_SCHEMA_INVALID");
  }
}

function parseChannel(path) {
  const source = readText(path);
  let channel;
  try {
    channel = JSON.parse(source);
  } catch (_) {
    reject("INSTALLER_CHANNEL_INVALID");
  }
  if (!channel || channel.schemaVersion !== 1) {
    reject("INSTALLER_CHANNEL_SCHEMA_UNSUPPORTED");
  }
  if (
    source !== canonical(channel) + "\n" ||
    !exactKeys(channel, ["schemaVersion", "bundleId"]) ||
    typeof channel.bundleId !== "string" ||
    !/^[0-9a-f]{64}$/.test(channel.bundleId)
  ) reject("INSTALLER_CHANNEL_INVALID");
  return channel.bundleId;
}

function u16(bytes, offset) {
  if (offset < 0 || offset + 2 > bytes.length) reject("INSTALLER_APK_MANIFEST_INVALID");
  return bytes[offset] + bytes[offset + 1] * 256;
}

function u32(bytes, offset) {
  if (offset < 0 || offset + 4 > bytes.length) reject("INSTALLER_APK_MANIFEST_INVALID");
  return (bytes[offset] + bytes[offset + 1] * 256 + bytes[offset + 2] * 65536 + bytes[offset + 3] * 16777216) >>> 0;
}

function utf8Length(bytes, offset) {
  const first = bytes[offset];
  if (first === undefined) reject("INSTALLER_APK_MANIFEST_INVALID");
  if ((first & 0x80) === 0) return [first, offset + 1];
  if (bytes[offset + 1] === undefined) reject("INSTALLER_APK_MANIFEST_INVALID");
  return [((first & 0x7f) << 8) | bytes[offset + 1], offset + 2];
}

function utf16Length(bytes, offset) {
  const first = u16(bytes, offset);
  if ((first & 0x8000) === 0) return [first, offset + 2];
  return [((first & 0x7fff) << 16) | u16(bytes, offset + 2), offset + 4];
}

function decodeStringPool(bytes, start, size) {
  const count = u32(bytes, start + 8);
  const flags = u32(bytes, start + 16);
  const stringsStart = u32(bytes, start + 20);
  const utf8 = (flags & 0x100) !== 0;
  if (count > 100000 || stringsStart >= size) reject("INSTALLER_APK_MANIFEST_INVALID");
  const strings = [];
  for (let index = 0; index < count; index += 1) {
    const relative = u32(bytes, start + 28 + index * 4);
    let cursor = start + stringsStart + relative;
    let length;
    let value = "";
    if (utf8) {
      const characterLength = utf8Length(bytes, cursor);
      cursor = characterLength[1];
      const byteLength = utf8Length(bytes, cursor);
      length = byteLength[0];
      cursor = byteLength[1];
      const end = cursor + length;
      if (end > start + size) reject("INSTALLER_APK_MANIFEST_INVALID");
      let encoded = "";
      for (; cursor < end; cursor += 1) encoded += "%" + ("0" + bytes[cursor].toString(16)).slice(-2);
      try { value = decodeURIComponent(encoded); } catch (_) { reject("INSTALLER_APK_MANIFEST_INVALID"); }
    } else {
      const decodedLength = utf16Length(bytes, cursor);
      length = decodedLength[0];
      cursor = decodedLength[1];
      if (cursor + length * 2 > start + size) reject("INSTALLER_APK_MANIFEST_INVALID");
      for (let character = 0; character < length; character += 1) {
        value += String.fromCharCode(u16(bytes, cursor + character * 2));
      }
    }
    strings.push(value);
  }
  return strings;
}

function inspectAndroidManifest(path) {
  const bytes = readBytes(path);
  if (bytes.length < 8 || u16(bytes, 0) !== 0x0003 || u32(bytes, 4) !== bytes.length) {
    reject("INSTALLER_APK_MANIFEST_INVALID");
  }
  let cursor = 8;
  let strings = [];
  while (cursor + 8 <= bytes.length) {
    const type = u16(bytes, cursor);
    const size = u32(bytes, cursor + 4);
    if (size < 8 || cursor + size > bytes.length) reject("INSTALLER_APK_MANIFEST_INVALID");
    if (type === 0x0001) {
      strings = decodeStringPool(bytes, cursor, size);
    } else if (type === 0x0102) {
      const name = strings[u32(bytes, cursor + 20)];
      if (name === "manifest") {
        const attributeStart = u16(bytes, cursor + 24);
        const attributeSize = u16(bytes, cursor + 26);
        const attributeCount = u16(bytes, cursor + 28);
        if (attributeSize < 20 || attributeCount > 1000) reject("INSTALLER_APK_MANIFEST_INVALID");
        const base = cursor + 16 + attributeStart;
        let packageName = null;
        let versionCode = null;
        for (let index = 0; index < attributeCount; index += 1) {
          const attribute = base + index * attributeSize;
          const attributeName = strings[u32(bytes, attribute + 4)];
          const dataType = bytes[attribute + 15];
          const data = u32(bytes, attribute + 16);
          if (attributeName === "package" && dataType === 0x03) packageName = strings[data];
          if (attributeName === "versionCode" && (dataType === 0x10 || dataType === 0x11)) versionCode = data;
        }
        if (typeof packageName !== "string" || !/^[A-Za-z][A-Za-z0-9_]*(?:\.[A-Za-z][A-Za-z0-9_]*)+$/.test(packageName)) {
          reject("INSTALLER_APK_PACKAGE_INVALID");
        }
        if (!Number.isInteger(versionCode) || versionCode < 1) reject("INSTALLER_APK_VERSION_INVALID");
        return packageName + "\t" + versionCode;
      }
    }
    cursor += size;
  }
  reject("INSTALLER_APK_MANIFEST_INVALID");
}

function run(argv) {
  if (argv[0] === "signature") {
    validateEcdsaP256Signature(argv[1]);
    return "";
  }
  if (argv[0] === "manifest") {
    validateManifest(argv[1], argv[2], argv[3], argv[4]);
    return "";
  }
  if (argv[0] === "channel") return parseChannel(argv[1]);
  if (argv[0] === "apk-manifest") return inspectAndroidManifest(argv[1]);
  reject("INSTALLER_HELPER_COMMAND_INVALID");
}
EOF_JXA
}

read_u32_le() {
  set -- $(/usr/bin/od -An -v -tu1 -N4 -j "$2" "$1" 2>/dev/null)
  [ "$#" -eq 4 ] || return 1
  /usr/bin/printf '%s\n' "$(( $1 + ($2 << 8) + ($3 << 16) + ($4 << 24) ))"
}

read_u64_le() {
  set -- $(/usr/bin/od -An -v -tu1 -N8 -j "$2" "$1" 2>/dev/null)
  [ "$#" -eq 8 ] || return 1
  /usr/bin/printf '%s\n' "$(( $1 + ($2 << 8) + ($3 << 16) + ($4 << 24) + ($5 << 32) + ($6 << 40) + ($7 << 48) + ($8 << 56) ))"
}

find_eocd_offset() {
  file="$1"
  size=$(/usr/bin/stat -f '%z' "$file" 2>/dev/null) || return 1
  [ "$size" -ge 22 ] || return 1
  tail_size=65557
  if [ "$size" -lt "$tail_size" ]; then
    tail_size="$size"
  fi
  tail_offset=$((size - tail_size))
  /usr/bin/od -An -v -tu1 -N "$tail_size" -j "$tail_offset" "$file" 2>/dev/null \
    | /usr/bin/awk -v base="$tail_offset" '
      {
        for (field = 1; field <= NF; field += 1) {
          fourth = third; third = second; second = first; first = $field; count += 1;
          if (fourth == 80 && third == 75 && second == 5 && first == 6) found = base + count - 4;
        }
      }
      END { if (found == "") exit 1; print found }
    '
}

apk_signer_sha256() {
  apk="$1"
  file_size=$(/usr/bin/stat -f '%z' "$apk" 2>/dev/null) || return 1
  eocd=$(find_eocd_offset "$apk") || return 1
  comment_length=$(/usr/bin/od -An -v -tu1 -N2 -j "$((eocd + 20))" "$apk" 2>/dev/null \
    | /usr/bin/awk 'NF >= 2 { value = $1 + ($2 * 256) } END { if (value == "") exit 1; print value }') || return 1
  [ "$((eocd + 22 + comment_length))" -eq "$file_size" ] || return 1
  central_offset=$(read_u32_le "$apk" "$((eocd + 16))") || return 1
  [ "$central_offset" -ge 32 ] || return 1
  footer_size=$(read_u64_le "$apk" "$((central_offset - 24))") || return 1
  block_start=$((central_offset - footer_size - 8))
  [ "$block_start" -ge 0 ] || return 1
  header_size=$(read_u64_le "$apk" "$block_start") || return 1
  [ "$header_size" -eq "$footer_size" ] || return 1
  magic=$(/bin/dd if="$apk" bs=1 skip="$((central_offset - 16))" count=16 2>/dev/null) || return 1
  [ "$magic" = "APK Sig Block 42" ] || return 1

  pairs_end=$((central_offset - 24))
  cursor=$((block_start + 8))
  v2_start=""
  v2_length=""
  while [ "$cursor" -lt "$pairs_end" ]; do
    pair_size=$(read_u64_le "$apk" "$cursor") || return 1
    [ "$pair_size" -ge 4 ] || return 1
    pair_end=$((cursor + 8 + pair_size))
    [ "$pair_end" -le "$pairs_end" ] || return 1
    pair_id=$(read_u32_le "$apk" "$((cursor + 8))") || return 1
    if [ "$pair_id" -eq 1896449818 ]; then
      [ -z "$v2_start" ] || return 1
      v2_start=$((cursor + 12))
      v2_length=$((pair_size - 4))
    fi
    cursor="$pair_end"
  done
  [ "$cursor" -eq "$pairs_end" ] || return 1
  [ -n "$v2_start" ] || return 1

  signers_length=$(read_u32_le "$apk" "$v2_start") || return 1
  signers_start=$((v2_start + 4))
  signers_end=$((signers_start + signers_length))
  [ "$signers_end" -eq "$((v2_start + v2_length))" ] || return 1
  signer_length=$(read_u32_le "$apk" "$signers_start") || return 1
  signer_start=$((signers_start + 4))
  signer_end=$((signer_start + signer_length))
  [ "$signer_end" -eq "$signers_end" ] || return 1
  signed_data_length=$(read_u32_le "$apk" "$signer_start") || return 1
  signed_data_start=$((signer_start + 4))
  signed_data_end=$((signed_data_start + signed_data_length))
  [ "$signed_data_end" -le "$signer_end" ] || return 1
  digests_length=$(read_u32_le "$apk" "$signed_data_start") || return 1
  certificates_field=$((signed_data_start + 4 + digests_length))
  [ "$certificates_field" -lt "$signed_data_end" ] || return 1
  certificates_length=$(read_u32_le "$apk" "$certificates_field") || return 1
  certificates_start=$((certificates_field + 4))
  certificates_end=$((certificates_start + certificates_length))
  [ "$certificates_end" -le "$signed_data_end" ] || return 1
  certificate_length=$(read_u32_le "$apk" "$certificates_start") || return 1
  certificate_start=$((certificates_start + 4))
  certificate_end=$((certificate_start + certificate_length))
  [ "$certificate_length" -gt 0 ] || return 1
  [ "$certificate_end" -eq "$certificates_end" ] || return 1
  certificate_file=$(/usr/bin/mktemp "$WORK_ROOT/apk-certificate.XXXXXX") || return 1
  if ! /bin/dd if="$apk" of="$certificate_file" bs=1 skip="$certificate_start" count="$certificate_length" 2>/dev/null; then
    /bin/rm -f "$certificate_file"
    return 1
  fi
  if ! /usr/bin/openssl x509 -inform DER -in "$certificate_file" -noout >/dev/null 2>&1; then
    /bin/rm -f "$certificate_file"
    return 1
  fi
  signer_digest=$(sha256_file "$certificate_file") || {
    /bin/rm -f "$certificate_file"
    return 1
  }
  /bin/rm -f "$certificate_file"
  /usr/bin/printf '%s\n' "$signer_digest"
}

inspect_apk() {
  apk="$1"
  manifest_file=$(/usr/bin/mktemp "$WORK_ROOT/android-manifest.XXXXXX") || return 1
  manifest_count=$(/usr/bin/unzip -Z1 "$apk" 2>/dev/null \
    | /usr/bin/awk '$0 == "AndroidManifest.xml" { count += 1 } END { print count + 0 }') || {
      /bin/rm -f "$manifest_file"
      return 1
    }
  [ "$manifest_count" -eq 1 ] || {
    /bin/rm -f "$manifest_file"
    return 1
  }
  if ! /usr/bin/unzip -p "$apk" AndroidManifest.xml > "$manifest_file" 2>/dev/null; then
    /bin/rm -f "$manifest_file"
    return 1
  fi
  identity=$(/usr/bin/osascript -l JavaScript "$JXA_HELPER" apk-manifest "$manifest_file" 2>/dev/null) || {
    /bin/rm -f "$manifest_file"
    return 1
  }
  /bin/rm -f "$manifest_file"
  APK_PACKAGE=${identity%%	*}
  APK_VERSION=${identity#*	}
  [ "$APK_PACKAGE" != "$identity" ] || return 1
  case "$APK_VERSION" in
    ''|*[!0-9]*) return 1 ;;
  esac
  APK_SIGNER=$(apk_signer_sha256 "$apk") || return 1
  return 0
}

require_exact_bundle_files() {
  [ -d "$BUNDLE_DIRECTORY" ] && [ ! -L "$BUNDLE_DIRECTORY" ] \
    || fail "BUNDLE_DIRECTORY_INVALID" "Choose the immutable Bundle ID directory produced by ZeeKit Platform Distribution."
  seen_manifest=0
  seen_signature=0
  seen_updater=0
  seen_core=0
  seen_manager=0
  entries=0
  while IFS= read -r -d '' entry; do
    entries=$((entries + 1))
    [ -f "$entry" ] && [ ! -L "$entry" ] \
      || fail "BUNDLE_FILE_SET_INVALID" "The Bundle contains a linked or non-regular entry; obtain the Bundle again."
    name=${entry##*/}
    case "$name" in
      manifest.json) seen_manifest=$((seen_manifest + 1)) ;;
      manifest.sig) seen_signature=$((seen_signature + 1)) ;;
      system-updater.apk) seen_updater=$((seen_updater + 1)) ;;
      core.apk) seen_core=$((seen_core + 1)) ;;
      manager.apk) seen_manager=$((seen_manager + 1)) ;;
      *) fail "BUNDLE_FILE_SET_INVALID" "The Bundle has an unlisted file and cannot be used." ;;
    esac
  done < <(/usr/bin/find "$BUNDLE_DIRECTORY" -mindepth 1 -maxdepth 1 -print0 2>/dev/null)
  [ "$entries" -eq 5 ] \
    && [ "$seen_manifest" -eq 1 ] \
    && [ "$seen_signature" -eq 1 ] \
    && [ "$seen_updater" -eq 1 ] \
    && [ "$seen_core" -eq 1 ] \
    && [ "$seen_manager" -eq 1 ] \
    || fail "BUNDLE_FILE_SET_INVALID" "The Bundle must contain exactly its manifest, signature, and three declared APKs."
}

download_public_file() {
  url="$1"
  destination="$2"
  if [ "$TEST_BOUNDARY_ACTIVE" -eq 1 ]; then
    protocol="=http"
  else
    protocol="=https"
  fi
  /usr/bin/curl --proto "$protocol" --tlsv1.2 -fL "$url" -o "$destination" >/dev/null 2>&1
}

resolve_latest_bundle() {
  CURRENT_PHASE="channel-resolution"
  CURRENT_COMPONENT="latest"
  channel_file="$WORK_ROOT/latest.json"
  download_public_file "$DOWNLOAD_ORIGIN/platform/channels/latest.json" "$channel_file" \
    || fail "LATEST_DOWNLOAD_FAILED" "Check the Mac's internet connection and download the current Installer from $CURRENT_INSTALLER_URL if the problem continues."
  channel_error="$WORK_ROOT/channel-validation.error"
  if ! BUNDLE_ID=$(/usr/bin/osascript -l JavaScript "$JXA_HELPER" channel "$channel_file" 2>"$channel_error"); then
    if /usr/bin/grep -q 'INSTALLER_CHANNEL_SCHEMA_UNSUPPORTED' "$channel_error"; then
      fail "CHANNEL_SCHEMA_UNSUPPORTED" "This saved Installer cannot read the current channel. Download the current Installer from $CURRENT_INSTALLER_URL."
    fi
    fail "CHANNEL_INVALID" "The latest channel response is invalid. Download the current Installer from $CURRENT_INSTALLER_URL."
  fi
  BUNDLE_DIRECTORY="$WORK_ROOT/$BUNDLE_ID"
  /bin/mkdir "$BUNDLE_DIRECTORY" || fail \
    "BUNDLE_DOWNLOAD_FAILED" "The temporary Bundle directory could not be created."
  CURRENT_PHASE="bundle-download"
  for name in manifest.json manifest.sig system-updater.apk core.apk manager.apk; do
    CURRENT_COMPONENT="$name"
    download_public_file \
      "$DOWNLOAD_ORIGIN/platform/bundles/$BUNDLE_ID/$name" \
      "$BUNDLE_DIRECTORY/$name" \
      || fail "BUNDLE_DOWNLOAD_FAILED" "The complete selected Bundle could not be downloaded; the vehicle was not changed."
  done
  log_detail "downloaded bundle_id=$BUNDLE_ID exact_files=5"
}

manifest_value() {
  /usr/bin/plutil -extract "$1" raw -n -- "$BUNDLE_DIRECTORY/manifest.json" 2>/dev/null
}

application_specs() {
  /usr/bin/printf '%s\n' \
    "0 system-updater system-updater.apk $SYSTEM_UPDATER_PACKAGE 1 $PLATFORM_SIGNER_SHA256" \
    "1 core core.apk $CORE_PACKAGE 1000 $APP_SIGNER_SHA256" \
    "2 manager manager.apk $MANAGER_PACKAGE 1000 $APP_SIGNER_SHA256"
}

artifact_digest() {
  case "$1" in
    0) /usr/bin/printf '%s\n' "$ARTIFACT_0_DIGEST" ;;
    1) /usr/bin/printf '%s\n' "$ARTIFACT_1_DIGEST" ;;
    2) /usr/bin/printf '%s\n' "$ARTIFACT_2_DIGEST" ;;
    *) return 1 ;;
  esac
}

verify_bundle() {
  CURRENT_PHASE="bundle-verification"
  CURRENT_COMPONENT="bundle"
  log_detail "begin bundle verification"
  require_exact_bundle_files

  actual_key_id=$(public_key_id "$TRUST_KEY") || fail \
    "BUNDLE_TRUST_KEY_INVALID" "This Installer's embedded Platform Bundle trust root is unavailable. Obtain a current Installer."
  [ "$actual_key_id" = "$PLATFORM_BUNDLE_KEY_ID" ] || fail \
    "BUNDLE_TRUST_KEY_INVALID" "The Platform Bundle trust root does not match this Installer. Obtain a current Installer."
  if ! /usr/bin/osascript -l JavaScript "$JXA_HELPER" signature \
    "$BUNDLE_DIRECTORY/manifest.sig" >/dev/null 2>&1; then
    fail "BUNDLE_SIGNATURE_INVALID" "Bundle authentication failed. Obtain the Bundle again from ZeeKit."
  fi
  if ! /usr/bin/openssl dgst -sha256 -verify "$TRUST_KEY" \
    -signature "$BUNDLE_DIRECTORY/manifest.sig" "$BUNDLE_DIRECTORY/manifest.json" >/dev/null 2>&1; then
    fail "BUNDLE_SIGNATURE_INVALID" "Bundle authentication failed. Obtain the Bundle again from ZeeKit."
  fi

  BUNDLE_ID=$(sha256_file "$BUNDLE_DIRECTORY/manifest.json") || fail \
    "BUNDLE_ID_UNAVAILABLE" "The Bundle manifest could not be hashed."
  [ "${BUNDLE_DIRECTORY##*/}" = "$BUNDLE_ID" ] || fail \
    "BUNDLE_ID_MISMATCH" "The Bundle directory name does not match its signed manifest."

  manifest_error="$WORK_ROOT/manifest-validation.error"
  if ! /usr/bin/osascript -l JavaScript "$JXA_HELPER" manifest \
    "$BUNDLE_DIRECTORY/manifest.json" "$PLATFORM_BUNDLE_KEY_ID" \
    "$PLATFORM_SIGNER_SHA256" "$APP_SIGNER_SHA256" >/dev/null 2>"$manifest_error"; then
    if /usr/bin/grep -q 'INSTALLER_SCHEMA_UNSUPPORTED' "$manifest_error"; then
      fail "BUNDLE_SCHEMA_UNSUPPORTED" "This Bundle needs a newer Installer. Download it from $CURRENT_INSTALLER_URL."
    fi
    fail "BUNDLE_MANIFEST_INVALID" "The signed Bundle manifest is not valid for this Installer. Obtain the Bundle again."
  fi

  while read -r index role filename package version signer; do
    verify_bundle_artifact "$index" "$role" "$filename" "$package" "$version" "$signer"
  done < <(application_specs)
  log_detail "verified bundle_id=$BUNDLE_ID exact_files=5"
}

verify_bundle_artifact() {
  index="$1"
  role="$2"
  filename="$3"
  package="$4"
  version="$5"
  signer="$6"
  CURRENT_COMPONENT="$role"
  expected_digest=$(manifest_value "artifacts.$index.sha256") || fail \
    "BUNDLE_MANIFEST_INVALID" "The signed artifact digest is unavailable."
  actual_digest=$(sha256_file "$BUNDLE_DIRECTORY/$filename") || fail \
    "ARTIFACT_DIGEST_UNAVAILABLE" "The $role APK could not be hashed."
  [ "$actual_digest" = "$expected_digest" ] || fail \
    "ARTIFACT_DIGEST_MISMATCH" "The $role APK bytes do not match the signed Bundle."
  inspect_apk "$BUNDLE_DIRECTORY/$filename" || fail \
    "APK_IDENTITY_UNREADABLE" "The $role APK package, version, or signing certificate could not be verified."
  [ "$APK_PACKAGE" = "$package" ] || fail \
    "APK_PACKAGE_MISMATCH" "The $role APK has the wrong Android package identity."
  [ "$APK_VERSION" = "$version" ] || fail \
    "APK_VERSION_MISMATCH" "The $role APK has the wrong Android versionCode."
  [ "$APK_SIGNER" = "$signer" ] || fail \
    "APK_SIGNER_MISMATCH" "The $role APK has the wrong Android signer identity."
  case "$index" in
    0) ARTIFACT_0_DIGEST="$expected_digest" ;;
    1) ARTIFACT_1_DIGEST="$expected_digest" ;;
    2) ARTIFACT_2_DIGEST="$expected_digest" ;;
    *) fail "BUNDLE_MANIFEST_INVALID" "The signed artifact index is not supported." ;;
  esac
}

ensure_adb() {
  CURRENT_PHASE="adb-verification"
  CURRENT_COMPONENT="adb"
  if [ "${ZEEKIT_INSTALLER_TEST_MODE:-}" = "recording-fake-adb" ]; then
    [ "$TEST_BOUNDARY_ACTIVE" -eq 1 ] \
      || fail "TEST_BOUNDARY_INVALID" "Test executable injection is unavailable outside the repository recording harness."
    ADB_PATH="$TEST_REPOSITORY/tools/fixtures/recording_fake_adb.py"
    expected_adb_digest="$TEST_ADB_SHA256"
  else
    cache_root="${HOME:-/tmp}/Library/Caches/ru.zeekit.installer/platform-tools/$ADB_VERSION"
    archive="$cache_root/platform-tools_r${ADB_VERSION}-darwin.zip"
    cached_adb="$cache_root/adb"
    /bin/mkdir -p "$cache_root" || fail "ADB_CACHE_UNAVAILABLE" "The private ADB cache could not be created."
    /bin/chmod 700 "$cache_root" 2>/dev/null || true
    if [ ! -f "$cached_adb" ] || [ "$(sha256_file "$cached_adb" 2>/dev/null || true)" != "$ADB_BINARY_SHA256" ]; then
      if [ ! -f "$archive" ] || [ "$(sha256_file "$archive" 2>/dev/null || true)" != "$ADB_ARCHIVE_SHA256" ]; then
        download=$(/usr/bin/mktemp "$cache_root/adb-download.XXXXXX") \
          || fail "ADB_DOWNLOAD_FAILED" "The ADB download could not be prepared."
        if ! /usr/bin/curl --proto '=https' --tlsv1.2 -fL "$ADB_ARCHIVE_URL" -o "$download" >/dev/null 2>&1; then
          /bin/rm -f "$download"
          fail "ADB_DOWNLOAD_FAILED" "Check the Mac's internet connection and run the Installer again."
        fi
        [ "$(sha256_file "$download" 2>/dev/null || true)" = "$ADB_ARCHIVE_SHA256" ] || {
          /bin/rm -f "$download"
          fail "ADB_ARCHIVE_DIGEST_MISMATCH" "The official ADB download did not match the Installer pin."
        }
        /bin/mv -f "$download" "$archive" || fail "ADB_CACHE_UNAVAILABLE" "The verified ADB archive could not be cached."
      fi
      [ "$(sha256_file "$archive" 2>/dev/null || true)" = "$ADB_ARCHIVE_SHA256" ] || fail \
        "ADB_ARCHIVE_DIGEST_MISMATCH" "The cached ADB archive is corrupt and was not executed."
      extract_root=$(/usr/bin/mktemp -d "$cache_root/adb-extract.XXXXXX") \
        || fail "ADB_EXTRACTION_FAILED" "The verified ADB archive could not be unpacked."
      if ! /usr/bin/unzip -q "$archive" 'platform-tools/adb' -d "$extract_root"; then
        fail "ADB_EXTRACTION_FAILED" "The verified ADB archive could not be unpacked."
      fi
      extracted_adb="$extract_root/platform-tools/adb"
      [ "$(sha256_file "$extracted_adb" 2>/dev/null || true)" = "$ADB_BINARY_SHA256" ] || fail \
        "ADB_BINARY_DIGEST_MISMATCH" "The extracted ADB binary did not match the Installer pin."
      /bin/chmod 700 "$extracted_adb" || fail "ADB_CACHE_UNAVAILABLE" "The verified ADB binary could not be made executable."
      /bin/mv -f "$extracted_adb" "$cached_adb" || fail "ADB_CACHE_UNAVAILABLE" "The verified ADB binary could not be cached."
    fi
    ADB_PATH="$cached_adb"
    expected_adb_digest="$ADB_BINARY_SHA256"
  fi
  [ -f "$ADB_PATH" ] && [ ! -L "$ADB_PATH" ] && [ -x "$ADB_PATH" ] || fail \
    "ADB_BINARY_INVALID" "The selected ADB is not a regular executable file."
  actual_adb_digest=$(sha256_file "$ADB_PATH") || fail \
    "ADB_BINARY_DIGEST_UNAVAILABLE" "ADB could not be verified and was not executed."
  [ "$actual_adb_digest" = "$expected_adb_digest" ] || fail \
    "ADB_BINARY_DIGEST_MISMATCH" "ADB does not match the Installer pin and was not executed."
  log_detail "verified adb_version=$ADB_VERSION"
}

select_device() {
  CURRENT_PHASE="device-selection"
  CURRENT_COMPONENT="adb"
  listing="$WORK_ROOT/adb-devices.txt"
  listing_error="$WORK_ROOT/adb-devices.error"
  if ! "$ADB_PATH" devices -l </dev/null >"$listing" 2>"$listing_error"; then
    fail "ADB_DEVICE_LIST_FAILED" "Reconnect the vehicle, enable USB debugging, and run the Installer again."
  fi
  rows="$WORK_ROOT/adb-device-rows.txt"
  /usr/bin/awk 'NR == 1 && /^List of devices attached/ { next } NF > 0 { print }' "$listing" > "$rows"
  row_count=$(/usr/bin/awk 'END { print NR + 0 }' "$rows")
  if [ "$row_count" -eq 0 ]; then
    fail "ADB_NO_DEVICE" "Connect one vehicle by USB, enable USB debugging, and accept its authorization prompt."
  fi
  if [ "$row_count" -gt 1 ]; then
    fail "ADB_MULTIPLE_DEVICES" "Disconnect every other Android device or emulator, then leave exactly one authorized vehicle connected."
  fi
  row=$(/usr/bin/sed -n '1p' "$rows")
  set -- $row
  [ "$#" -ge 2 ] || fail "ADB_DEVICE_LIST_INVALID" "ADB returned an unreadable device list."
  SELECTED_SERIAL="$1"
  device_state="$2"
  case "$device_state" in
    device) ;;
    unauthorized) fail "ADB_UNAUTHORIZED" "Unlock the vehicle screen and accept the USB debugging authorization prompt." ;;
    offline) fail "ADB_OFFLINE" "Reconnect USB and restart USB debugging until the vehicle is online." ;;
    *) fail "ADB_DEVICE_NOT_READY" "Wait for the single connected vehicle to enter ADB state 'device'." ;;
  esac
  log_detail "selected exactly one authorized device; serial redacted"
}

adb_to_file() {
  output_file="$1"
  shift
  "$ADB_PATH" -s "$SELECTED_SERIAL" "$@" </dev/null >"$output_file" 2>&1
}

installed_apk() {
  package="$1"
  destination="$2"
  path_output="$WORK_ROOT/pm-path.txt"
  if ! adb_to_file "$path_output" shell pm path "$package"; then
    return 2
  fi
  path_count=$(/usr/bin/awk '/^package:/ { count += 1 } END { print count + 0 }' "$path_output")
  if [ "$path_count" -eq 0 ]; then
    return 1
  fi
  [ "$path_count" -eq 1 ] || return 2
  remote_path=$(/usr/bin/awk -F: '/^package:/ { sub(/^package:/, ""); print; exit }' "$path_output")
  [ -n "$remote_path" ] || return 2
  pull_output="$WORK_ROOT/adb-pull.txt"
  adb_to_file "$pull_output" pull "$remote_path" "$destination" || return 2
  [ -f "$destination" ] || return 2
  return 0
}

preflight_component() {
  role="$1"
  filename="$2"
  package="$3"
  wanted_version="$4"
  wanted_signer="$5"
  wanted_digest="$6"
  CURRENT_PHASE="device-preflight"
  CURRENT_COMPONENT="$role"
  installed="$WORK_ROOT/preflight-$role.apk"
  installed_apk "$package" "$installed"
  installed_status=$?
  if [ "$installed_status" -eq 1 ]; then
    /usr/bin/printf '%s\t%s\t%s\n' "$role" "$filename" "$package" >> "$WORK_ROOT/actions.tsv"
    log_detail "package absent; action=install"
    return
  fi
  [ "$installed_status" -eq 0 ] || fail \
    "INSTALLED_PACKAGE_INSPECTION_FAILED" "The installed $role package could not be inspected safely."
  inspect_apk "$installed" || fail \
    "INSTALLED_PACKAGE_IDENTITY_UNREADABLE" "The installed $role package identity could not be verified."
  [ "$APK_PACKAGE" = "$package" ] || fail \
    "INSTALLED_PACKAGE_IDENTITY_MISMATCH" "The installed $role package identity does not match its package path."
  [ "$APK_SIGNER" = "$wanted_signer" ] || fail \
    "INSTALLED_SIGNER_CONFLICT" "The installed $role uses an incompatible signer. It was not uninstalled and its data was not deleted."
  if [ "$APK_VERSION" -gt "$wanted_version" ]; then
    fail "NEWER_VERSION_INSTALLED" "The installed $role is newer than this Bundle. Automatic downgrade is disabled. Obtain a current Bundle."
  fi
  installed_digest=$(sha256_file "$installed") || fail \
    "INSTALLED_PACKAGE_DIGEST_UNAVAILABLE" "The installed $role bytes could not be verified."
  if [ "$APK_VERSION" -lt "$wanted_version" ] || [ "$installed_digest" != "$wanted_digest" ]; then
    /usr/bin/printf '%s\t%s\t%s\n' "$role" "$filename" "$package" >> "$WORK_ROOT/actions.tsv"
    log_detail "compatible installed package requires data-preserving replacement"
  else
    log_detail "exact installed package found; action=verify-only"
  fi
}

install_actions() {
  CURRENT_PHASE="package-install"
  while IFS="	" read -r role filename package; do
    [ -n "$role" ] || continue
    CURRENT_COMPONENT="$role"
    install_output="$WORK_ROOT/install-$role.txt"
    install_attempt=1
    while [ "$install_attempt" -le 2 ]; do
      if adb_to_file "$install_output" install -r -g "$BUNDLE_DIRECTORY/$filename" \
        && /usr/bin/grep -Eq '^[[:space:]]*Success[[:space:]]*$' "$install_output"; then
        log_detail "adb install -r -g reported Success attempt=$install_attempt"
        break
      fi
      if /usr/bin/grep -q 'INSTALL_FAILED_UPDATE_INCOMPATIBLE' "$install_output"; then
        fail "INSTALLED_SIGNER_CONFLICT" "Android rejected $role because its installed signer is incompatible. The package was not uninstalled."
      fi
      if [ "$install_attempt" -eq 1 ]; then
        log_detail "data-preserving install did not succeed; retrying the same command once"
        install_attempt=2
        continue
      fi
      fail "PACKAGE_INSTALL_FAILED" "Android rejected the data-preserving $role install twice. No uninstall or destructive fallback was attempted."
    done
  done < "$WORK_ROOT/actions.tsv"
}

repair_platform_inputs() {
  CURRENT_PHASE="platform-repair"
  CURRENT_COMPONENT="core"
  repair_output="$WORK_ROOT/core-repair.txt"
  if ! adb_to_file "$repair_output" shell am start -W -n "$CORE_REPAIR_COMPONENT"; then
    fail "PLATFORM_REPAIR_FAILED" "Core could not ask System Updater to repair its fixed Platform Input permissions."
  fi
  /usr/bin/grep -Eq '^Status:[[:space:]]*ok[[:space:]]*$' "$repair_output" || fail \
    "PLATFORM_REPAIR_FAILED" "Core's fixed Platform Input repair entry point did not start successfully."
  log_detail "invoked fixed Core-to-System-Updater permission repair; waiting for asynchronous completion"
  wait_for_core_repair
}

permission_line() {
  permission="$1"
  dump="$2"
  /usr/bin/awk -v permission="$permission:" '
    index($0, permission) > 0 {
      count += 1;
      line = $0;
    }
    END {
      if (count != 1) exit 1;
      print line;
    }
  ' "$dump"
}

core_permissions_ready() {
  dump="$1"
  for permission in \
    "android.permission.ACCESS_COARSE_LOCATION" \
    "android.permission.ACCESS_FINE_LOCATION" \
    "android.permission.ACCESS_BACKGROUND_LOCATION"; do
    observed=$(permission_line "$permission" "$dump" 2>/dev/null || true)
    [ -n "$observed" ] || return 1
    /usr/bin/printf '%s\n' "$observed" | /usr/bin/grep -q 'granted=true' || return 1
    if /usr/bin/printf '%s\n' "$observed" \
      | /usr/bin/grep -Eiq '(^|[^A-Za-z0-9_])ONE_TIME([^A-Za-z0-9_]|$)'; then
      return 1
    fi
  done
  return 0
}

wait_for_core_repair() {
  attempt=1
  while [ "$attempt" -le "$REPAIR_WAIT_ATTEMPTS" ]; do
    repair_state="$WORK_ROOT/core-repair-state-$attempt.txt"
    adb_to_file "$repair_state" shell dumpsys package "$CORE_PACKAGE" || fail \
      "PLATFORM_REPAIR_VERIFICATION_FAILED" "Core permission state could not be read after repair."
    if core_permissions_ready "$repair_state"; then
      log_detail "asynchronous permission repair reached its ready postcondition attempt=$attempt"
      return 0
    fi
    if [ "$attempt" -lt "$REPAIR_WAIT_ATTEMPTS" ] && [ "$REPAIR_WAIT_SECONDS" -gt 0 ]; then
      /bin/sleep "$REPAIR_WAIT_SECONDS"
    fi
    attempt=$((attempt + 1))
  done
  log_detail "permission repair did not reach readiness before the bounded verification deadline"
  return 0
}

package_is_enabled() {
  dump="$1"
  /usr/bin/grep -Eo 'enabled=(true|false|[0-9]+)' "$dump" 2>/dev/null \
    | /usr/bin/awk -F= '
      $2 == "true" || $2 == "0" || $2 == "1" { enabled = 1 }
      $2 == "false" || ($2 ~ /^[0-9]+$/ && $2 >= 2) { disabled = 1 }
      END { exit !(enabled && !disabled) }
    '
}

verify_permission() {
  permission="$1"
  dump="$2"
  forbidden_flag="$3"
  observed=$(permission_line "$permission" "$dump" 2>/dev/null || true)
  if [ -z "$observed" ] || ! /usr/bin/printf '%s\n' "$observed" | /usr/bin/grep -q 'granted=true'; then
    READINESS_INCOMPLETE=1
    log_detail "readiness missing_permission=$permission"
    return
  fi
  if [ -n "$forbidden_flag" ] \
    && /usr/bin/printf '%s\n' "$observed" | /usr/bin/grep -Eiq "(^|[^A-Za-z0-9_])${forbidden_flag}([^A-Za-z0-9_]|$)"; then
    READINESS_INCOMPLETE=1
    log_detail "readiness forbidden_permission_flag=$forbidden_flag permission=$permission"
  fi
}

verify_installed_component() {
  role="$1"
  package="$2"
  wanted_version="$3"
  wanted_signer="$4"
  wanted_digest="$5"
  CURRENT_PHASE="post-install-verification"
  CURRENT_COMPONENT="$role"
  installed="$WORK_ROOT/post-$role.apk"
  installed_apk "$package" "$installed"
  [ "$?" -eq 0 ] || fail "PACKAGE_HEALTH_FAILED" "The exact $role package is missing after Platform Setup."
  inspect_apk "$installed" || fail \
    "PACKAGE_HEALTH_FAILED" "The installed $role package identity is unreadable after Platform Setup."
  [ "$APK_PACKAGE" = "$package" ] \
    && [ "$APK_VERSION" = "$wanted_version" ] \
    && [ "$APK_SIGNER" = "$wanted_signer" ] \
    || fail "PACKAGE_HEALTH_FAILED" "The installed $role package, version, or signer is not exact after Platform Setup."
  installed_digest=$(sha256_file "$installed") || fail \
    "PACKAGE_HEALTH_FAILED" "The installed $role bytes could not be verified after Platform Setup."
  [ "$installed_digest" = "$wanted_digest" ] || fail \
    "PACKAGE_HEALTH_FAILED" "The installed $role bytes do not match the selected Bundle after Platform Setup."
  dump="$WORK_ROOT/dumpsys-$role.txt"
  adb_to_file "$dump" shell dumpsys package "$package" || fail \
    "PACKAGE_HEALTH_FAILED" "Android package health for $role could not be read."
  package_is_enabled "$dump" || fail \
    "PACKAGE_DISABLED" "The exact $role package is installed but not enabled."

  case "$role" in
    system-updater)
      verify_permission "android.permission.FORCE_STOP_PACKAGES" "$dump" ""
      verify_permission "android.permission.START_ACTIVITIES_FROM_BACKGROUND" "$dump" ""
      verify_permission "android.permission.START_ANY_ACTIVITY" "$dump" ""
      verify_permission "android.permission.INSTALL_PACKAGES" "$dump" ""
      verify_permission "android.permission.DELETE_PACKAGES" "$dump" ""
      verify_permission "android.permission.GRANT_RUNTIME_PERMISSIONS" "$dump" ""
      verify_permission "android.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS" "$dump" ""
      verify_permission "android.permission.CHANGE_COMPONENT_ENABLED_STATE" "$dump" ""
      ;;
    core)
      verify_permission "android.permission.ACCESS_COARSE_LOCATION" "$dump" "ONE_TIME"
      verify_permission "android.permission.ACCESS_FINE_LOCATION" "$dump" "ONE_TIME"
      verify_permission "android.permission.ACCESS_BACKGROUND_LOCATION" "$dump" "ONE_TIME"
      ;;
  esac
  log_detail "exact package version signer digest and enabled state verified"
}

verify_platform_readiness() {
  READINESS_INCOMPLETE=0
  while read -r index role _filename package version signer; do
    wanted_digest=$(artifact_digest "$index") || fail \
      "BUNDLE_MANIFEST_INVALID" "The verified artifact digest is unavailable."
    verify_installed_component "$role" "$package" "$version" "$signer" "$wanted_digest"
  done < <(application_specs)
}

configure_test_boundary() {
  if [ "${ZEEKIT_INSTALLER_TEST_MODE:-}" != "recording-fake-adb" ]; then
    write_embedded_trust_key
    return
  fi
  script_directory=$(cd "$(/usr/bin/dirname "$0")" 2>/dev/null && /bin/pwd -P) \
    || fail "TEST_BOUNDARY_INVALID" "The repository recording harness could not resolve the Installer source path."
  TEST_REPOSITORY=$(cd "$script_directory/../.." 2>/dev/null && /bin/pwd -P) \
    || fail "TEST_BOUNDARY_INVALID" "Test injection is unavailable outside the repository recording harness."
  test_marker="$TEST_REPOSITORY/tools/fixtures/installer-recording-boundary"
  test_trust_key="$TEST_REPOSITORY/tools/fixtures/installer-test-bundle-public.pem"
  test_adb="$TEST_REPOSITORY/tools/fixtures/recording_fake_adb.py"
  [ "$script_directory" = "$TEST_REPOSITORY/installer/macos" ] \
    && [ -e "$TEST_REPOSITORY/.git" ] \
    && [ -f "$test_marker" ] \
    && [ "$(sha256_file "$test_marker" 2>/dev/null || true)" = "$TEST_BOUNDARY_MARKER_SHA256" ] \
    && [ -f "$test_trust_key" ] \
    && [ "$(public_key_id "$test_trust_key" 2>/dev/null || true)" = "$TEST_BUNDLE_KEY_ID" ] \
    && [ -f "$test_adb" ] \
    && [ ! -L "$test_adb" ] \
    && [ "$(sha256_file "$test_adb" 2>/dev/null || true)" = "$TEST_ADB_SHA256" ] \
    || fail "TEST_BOUNDARY_INVALID" "Test injection is unavailable outside the repository recording harness."
  /bin/cp "$test_trust_key" "$TRUST_KEY" || fail \
    "TEST_BOUNDARY_INVALID" "The recording test trust root is unavailable."
  PLATFORM_BUNDLE_KEY_ID="$TEST_BUNDLE_KEY_ID"
  PLATFORM_SIGNER_SHA256="$TEST_APK_SIGNER_SHA256"
  APP_SIGNER_SHA256="$TEST_APK_SIGNER_SHA256"
  TEST_BOUNDARY_ACTIVE=1
  if [ -n "${ZEEKIT_INSTALLER_TEST_ORIGIN:-}" ]; then
    case "$ZEEKIT_INSTALLER_TEST_ORIGIN" in
      http://127.0.0.1:*)
        test_origin_port=${ZEEKIT_INSTALLER_TEST_ORIGIN#http://127.0.0.1:}
        case "$test_origin_port" in
          ''|*[!0-9]*) fail "TEST_BOUNDARY_INVALID" "The recording harness origin must contain one numeric loopback port." ;;
        esac
        [ "$test_origin_port" -le 65535 ] || fail \
          "TEST_BOUNDARY_INVALID" "The recording harness loopback port is outside the supported range."
        DOWNLOAD_ORIGIN="$ZEEKIT_INSTALLER_TEST_ORIGIN"
        ;;
      *) fail "TEST_BOUNDARY_INVALID" "The recording harness origin must be a loopback HTTP endpoint." ;;
    esac
  fi
  REPAIR_WAIT_ATTEMPTS=3
  REPAIR_WAIT_SECONDS=0
  log_detail "bounded recording-fake-adb test mode enabled"
}

main() {
  WORK_ROOT=$(/usr/bin/mktemp -d "${TMPDIR:-/tmp}/zeekit-installer.XXXXXX") || {
    /usr/bin/printf 'FAILED [startup/installer]: TEMPORARY_DIRECTORY_UNAVAILABLE\n' >&2
    exit 1
  }
  LOG_FILE=$(/usr/bin/mktemp "${TMPDIR:-/tmp}/ZeeKitInstaller-startup.XXXXXX.log") || {
    /usr/bin/printf 'FAILED [startup/installer]: LOG_FILE_UNAVAILABLE\n' >&2
    exit 1
  }
  [ -n "${HOME:-}" ] || fail \
    "LOG_DIRECTORY_UNAVAILABLE" "The macOS home directory is unavailable; the private fallback log is shown below."
  log_root="$HOME/Library/Logs/ZeeKit/Installer"
  /bin/mkdir -p "$log_root" || fail \
    "LOG_DIRECTORY_UNAVAILABLE" "The Installer log directory could not be created; the private fallback log is shown below."
  /bin/chmod 700 "$log_root" 2>/dev/null || true
  final_log="$log_root/$(/bin/date -u '+%Y%m%dT%H%M%SZ')-$$.log"
  /bin/mv "$LOG_FILE" "$final_log" || fail \
    "LOG_FILE_UNAVAILABLE" "The timestamped Installer log could not be created; the private fallback log is shown below."
  LOG_FILE="$final_log"
  /bin/chmod 600 "$LOG_FILE" 2>/dev/null || true

  JXA_HELPER="$WORK_ROOT/installer-helper.js"
  TRUST_KEY="$WORK_ROOT/platform-bundle-public.pem"
  write_jxa_helper
  configure_test_boundary

  if [ "$#" -eq 0 ]; then
    ONLINE_MODE=1
    resolve_latest_bundle
  elif [ "$#" -eq 2 ] && [ "$1" = "--bundle" ]; then
    BUNDLE_DIRECTORY="$2"
    while [ "${BUNDLE_DIRECTORY%/}" != "$BUNDLE_DIRECTORY" ]; do
      BUNDLE_DIRECTORY=${BUNDLE_DIRECTORY%/}
    done
    [ -n "$BUNDLE_DIRECTORY" ] || usage
  else
    usage
  fi

  log_detail "installer_version=$INSTALLER_VERSION online_mode=$ONLINE_MODE telemetry=false"
  verify_bundle
  /usr/bin/printf 'Verified Platform Bundle %s\n' "$BUNDLE_ID"
  ensure_adb
  select_device
  /usr/bin/printf 'Selected exactly one authorized ADB device (serial redacted).\n'

  : > "$WORK_ROOT/actions.tsv"
  while read -r index role filename package version signer; do
    wanted_digest=$(artifact_digest "$index") || fail \
      "BUNDLE_MANIFEST_INVALID" "The verified artifact digest is unavailable."
    preflight_component "$role" "$filename" "$package" "$version" "$signer" "$wanted_digest"
  done < <(application_specs)

  action_count=$(/usr/bin/awk 'NF > 0 { count += 1 } END { print count + 0 }' "$WORK_ROOT/actions.tsv")
  if [ "$action_count" -eq 0 ]; then
    verify_platform_readiness
    if [ "$READINESS_INCOMPLETE" -eq 0 ]; then
      CURRENT_PHASE="complete"
      CURRENT_COMPONENT="platform"
      log_detail "result=PLATFORM_READY exact_bundle_noop=true"
      /usr/bin/printf 'PLATFORM_READY: the exact Bundle is installed and healthy; no APK was reinstalled.\n'
      exit 0
    fi
  else
    install_actions
  fi

  repair_platform_inputs
  verify_platform_readiness
  [ "$READINESS_INCOMPLETE" -eq 0 ] || setup_incomplete
  CURRENT_PHASE="complete"
  CURRENT_COMPONENT="platform"
  log_detail "result=PLATFORM_READY installed_or_repaired=true"
  /usr/bin/printf 'PLATFORM_READY: the exact Bundle is installed and Platform Readiness is complete.\n'
}

main "$@"
