#!/bin/bash

set -euo pipefail

ROOT_DIR="$(git rev-parse --show-toplevel)"
cd "$ROOT_DIR"

EXPECTED_PODS_GITLINK="a9b598ba3c71523a66f88463adc85e0c1dc73901"
EXPECTED_PODFILE_LOCK_SHA256="f0c93346b5641f43b9fac00bbe0eb34b8273a438dffc205ef54094e6e4464840"
EXPECTED_GENERATED_PODS_CONTENT_SHA256="049660e68330ad2fedc713575625d9fca267cf1bc5fafea34519cb35eef4ef07"
EXPECTED_PODS_PROJECT_SEMANTIC_SHA256="1534cfb3a8001ea7828f8c30d4078d946422b9255902b11cac0f4122bcabd734"
EXPECTED_RINGRTC_PREBUILD_SHA256="f1ea93081cca203d6b529ddbd960e8abe14be0d177154a1c8d87024fa5286707"
EXPECTED_WEBRTC_ARTIFACT_SHA256="e2d527eb995e433bcbe52bfec053acd7842da2dfda08f9dd7f67fecfa1820bbd"
EXPECTED_RINGRTC_RELEASE_CONTENT_SHA256="25125009bdeb1b6b7838f47e8ee6a02d6c042cf08be656e9e20964024ece8965"
EXPECTED_SDWEBIMAGE_HELPER_SHA256="90dac42daa7efec15098d1552e0425490f931d94883c561c8e046e5f02b90381"
EXPECTED_SDWEBIMAGE_METADATA_SHA256="79e8e16a916867e27f4e6e09cfaa3925167138cb32a59b26cb1473c5f31e9e41"
EXPECTED_SDWEBIMAGE_MACROS_SHA256="d92f864f9f9f37d92be32722c857f246db006f8406c9996553411e4f768d1c6d"
EXPECTED_TRUSTWALLET_PRIVACY_SHA256="443f9d8b95c80ae74789b572a57c3e356e7ba7772a0a18dae863cd001be00bdf"

fail() {
  printf 'Pods verification failed: %s\n' "$1" >&2
  exit 1
}

pods_head_gitlink="$(git rev-parse HEAD:Pods 2>/dev/null || true)"
pods_index_gitlink="$(git rev-parse :Pods 2>/dev/null || true)"
pods_checkout="$(git -C Pods rev-parse HEAD 2>/dev/null || true)"

if [[ "$pods_head_gitlink" != "$EXPECTED_PODS_GITLINK" ||
      "$pods_index_gitlink" != "$EXPECTED_PODS_GITLINK" ||
      "$pods_checkout" != "$EXPECTED_PODS_GITLINK" ]]; then
  fail "gitlink mismatch (expected $EXPECTED_PODS_GITLINK, HEAD $pods_head_gitlink, index $pods_index_gitlink, checkout $pods_checkout)"
fi

podfile_lock_sha256="$(shasum -a 256 Podfile.lock | cut -d ' ' -f 1)"
[[ "$podfile_lock_sha256" == "$EXPECTED_PODFILE_LOCK_SHA256" ]] ||
  fail "Podfile.lock hash $podfile_lock_sha256 does not match the frozen Build 12 hash"

cmp -s Podfile.lock Pods/Manifest.lock ||
  fail "Pods/Manifest.lock does not byte-match Podfile.lock"

cmp -s ThirdParty/TrustWalletCore/PrivacyInfo.xcprivacy \
  Pods/TrustWalletCore/PrivacyInfo.xcprivacy ||
  fail "generated TrustWalletCore privacy manifest differs from the reviewed source"
/usr/bin/plutil -lint Pods/TrustWalletCore/PrivacyInfo.xcprivacy >/dev/null ||
  fail "generated TrustWalletCore privacy manifest is invalid"
trustwallet_privacy_sha256="$(
  shasum -a 256 Pods/TrustWalletCore/PrivacyInfo.xcprivacy | cut -d ' ' -f 1
)"
[[ "$trustwallet_privacy_sha256" == "$EXPECTED_TRUSTWALLET_PRIVACY_SHA256" ]] ||
  fail "TrustWalletCore privacy manifest hash $trustwallet_privacy_sha256 is not reviewed"

unexpected_changes=()
while IFS= read -r -d '' entry; do
  [[ -z "$entry" ]] && continue
  case "$entry" in
    " M Manifest.lock" | \
    " M Pods.xcodeproj/project.pbxproj" | \
    " M SDWebImage/SDWebImage/Core/SDImageCoderHelper.m" | \
    " M SDWebImage/SDWebImage/Core/UIImage+Metadata.m" | \
    " M SDWebImage/SDWebImage/Private/SDInternalMacros.h" | \
    " M Target Support Files/LibSignalClient/"* | \
    " M Target Support Files/Pods-"* | \
    "?? Target Support Files/TrustWalletCore/"* | \
    "?? Target Support Files/WalletCoreSwiftProtobuf/"* | \
    "?? TrustWalletCore/"* | \
    "?? WalletCoreSwiftProtobuf/"*)
      ;;
    *)
      unexpected_changes+=("$entry")
      ;;
  esac
done < <(git -C Pods status --porcelain=v1 -z)

if ((${#unexpected_changes[@]})); then
  fail "unexpected source or generated paths: ${unexpected_changes[*]}"
fi

verify_patched_source() {
  local path="$1"
  local expected_sha256="$2"
  local actual_sha256
  actual_sha256="$(shasum -a 256 "Pods/$path" | cut -d ' ' -f 1)"
  [[ "$actual_sha256" == "$expected_sha256" ]] ||
    fail "$path hash $actual_sha256 does not match the reviewed App Store patch"
}

verify_patched_source \
  SDWebImage/SDWebImage/Core/SDImageCoderHelper.m \
  "$EXPECTED_SDWEBIMAGE_HELPER_SHA256"
verify_patched_source \
  SDWebImage/SDWebImage/Core/UIImage+Metadata.m \
  "$EXPECTED_SDWEBIMAGE_METADATA_SHA256"
verify_patched_source \
  SDWebImage/SDWebImage/Private/SDInternalMacros.h \
  "$EXPECTED_SDWEBIMAGE_MACROS_SHA256"

generated_roots=(
  Manifest.lock
  "Target Support Files/LibSignalClient"
  "Target Support Files/Pods-Signal"
  "Target Support Files/Pods-SignalNSE"
  "Target Support Files/Pods-SignalServiceKit"
  "Target Support Files/Pods-SignalServiceKitTests"
  "Target Support Files/Pods-SignalShareExtension"
  "Target Support Files/Pods-SignalTests"
  "Target Support Files/Pods-SignalUI"
  "Target Support Files/Pods-SignalUITests"
  "Target Support Files/TrustWalletCore"
  "Target Support Files/WalletCoreSwiftProtobuf"
  TrustWalletCore
  WalletCoreSwiftProtobuf
)

[[ -f Pods/Pods.xcodeproj/project.pbxproj ]] ||
  fail "missing generated path Pods/Pods.xcodeproj/project.pbxproj"

for root in "${generated_roots[@]}"; do
  [[ -e "Pods/$root" ]] || fail "missing generated path Pods/$root"
done

generated_pods_sha256="$(
  (
    cd Pods
    for root in "${generated_roots[@]}"; do
      find "$root" \( -type f -o -type l \) -print0
    done | LC_ALL=C sort -z | while IFS= read -r -d '' item; do
      if [[ -L "$item" ]]; then
        printf 'L\0%s\0%s\0' "$item" "$(readlink "$item")"
      else
        file_sha256="$(shasum -a 256 "$item")"
        file_sha256="${file_sha256%% *}"
        printf 'F\0%s\0%s\0' "$item" "$file_sha256"
      fi
    done
  ) | shasum -a 256 | cut -d ' ' -f 1
)"

[[ "$generated_pods_sha256" == "$EXPECTED_GENERATED_PODS_CONTENT_SHA256" ]] ||
  fail "generated Pods content digest $generated_pods_sha256 does not match $EXPECTED_GENERATED_PODS_CONTENT_SHA256"

pods_project_semantic_sha256="$(
  RUBYOPT=-W0 bundle _2.6.9_ exec ruby \
    Scripts/kivo_pods_project_semantic_digest.rb \
    Pods/Pods.xcodeproj
)" || fail "could not compute the Pods project semantic digest"

[[ "$pods_project_semantic_sha256" == "$EXPECTED_PODS_PROJECT_SEMANTIC_SHA256" ]] ||
  fail "Pods project semantic digest $pods_project_semantic_sha256 does not match $EXPECTED_PODS_PROJECT_SEMANTIC_SHA256"

ringrtc_cache_root="$HOME/Library/Caches/org.signal.ringrtc"
ringrtc_prebuild_root="$ringrtc_cache_root/prebuild-2.70.1"
ringrtc_release_root="$ringrtc_prebuild_root/release"
ringrtc_archive="$ringrtc_prebuild_root/ringrtc-ios-build-v2.70.1.tar.bz2"
webrtc_archive="$ringrtc_cache_root/webrtc-7871e-ios-release.tar.bz2"

tracked_ringrtc_sha256="$(tr -d '[:space:]' < Pods/SignalRingRTC/prebuild-checksum)"
[[ "$tracked_ringrtc_sha256" == "$EXPECTED_RINGRTC_PREBUILD_SHA256" ]] ||
  fail "tracked RingRTC prebuild checksum $tracked_ringrtc_sha256 is unexpected"

tracked_webrtc_sha256="$(
  /usr/bin/plutil -extract ios raw -o - \
    Pods/SignalRingRTC/config/webrtc_artifact_checksums.json
)"
[[ "$tracked_webrtc_sha256" == "$EXPECTED_WEBRTC_ARTIFACT_SHA256" ]] ||
  fail "tracked WebRTC artifact checksum $tracked_webrtc_sha256 is unexpected"

for artifact in "$ringrtc_archive" "$webrtc_archive"; do
  [[ -f "$artifact" ]] || fail "missing RingRTC cache artifact $artifact"
done

ringrtc_archive_sha256="$(shasum -a 256 "$ringrtc_archive" | cut -d ' ' -f 1)"
[[ "$ringrtc_archive_sha256" == "$EXPECTED_RINGRTC_PREBUILD_SHA256" ]] ||
  fail "RingRTC archive checksum $ringrtc_archive_sha256 is unexpected"

webrtc_archive_sha256="$(shasum -a 256 "$webrtc_archive" | cut -d ' ' -f 1)"
[[ "$webrtc_archive_sha256" == "$EXPECTED_WEBRTC_ARTIFACT_SHA256" ]] ||
  fail "WebRTC archive checksum $webrtc_archive_sha256 is unexpected"

[[ -d "$ringrtc_release_root" ]] ||
  fail "missing extracted RingRTC release $ringrtc_release_root"

ringrtc_release_content_sha256="$(
  (
    cd "$ringrtc_release_root"
    find . \( -type f -o -type l \) -print0 |
      LC_ALL=C sort -z |
      while IFS= read -r -d '' item; do
        if [[ -L "$item" ]]; then
          printf 'L\0%s\0%s\0' "$item" "$(readlink "$item")"
        else
          item_sha256="$(shasum -a 256 "$item" | cut -d ' ' -f 1)"
          printf 'F\0%s\0%s\0' "$item" "$item_sha256"
        fi
      done
  ) | shasum -a 256 | cut -d ' ' -f 1
)"

[[ "$ringrtc_release_content_sha256" == "$EXPECTED_RINGRTC_RELEASE_CONTENT_SHA256" ]] ||
  fail "extracted RingRTC content digest $ringrtc_release_content_sha256 is unexpected"

ringrtc_out_symlink_count=0
while IFS= read -r -d '' symlink; do
  symlink_target="$(readlink "$symlink")"
  case "$symlink_target" in
    "$ringrtc_release_root"/*)
      ;;
    *)
      fail "RingRTC output symlink $symlink points outside the verified release cache"
      ;;
  esac
  ringrtc_out_symlink_count=$((ringrtc_out_symlink_count + 1))
done < <(find Pods/SignalRingRTC/out/release -type l -print0)

[[ "$ringrtc_out_symlink_count" -eq 7 ]] ||
  fail "expected 7 RingRTC output symlinks, found $ringrtc_out_symlink_count"

printf 'Verified Pods gitlink, lockfile, path boundary, generated content %s, project semantics %s, and RingRTC cache content %s.\n' \
  "$generated_pods_sha256" \
  "$pods_project_semantic_sha256" \
  "$ringrtc_release_content_sha256"
