#!/usr/bin/env bash
# Is the falcon actually in the APK? The way this loses is silent: gen/android
# is regenerated and gitignored, so a project rebuilt without the overlay copy
# still compiles, still installs, and wears tauri's logo again with nothing in
# the log. So every APK this repo makes is opened and read before it is
# installed. Called by build.sh and dev.sh; run it by hand on any APK.
#
#   bash src-tauri/android/verify-icon.sh <apk> [--crunched]
#
# Debug and release are read DIFFERENTLY, because AGP treats their resources
# differently and both differences were measured on 2026-09-14:
#
#   debug    packaged with --no-crunch (AGP's default for the debuggable build
#            type), so every entry is byte for byte the file on disk — checked
#            against the real 107 MB APK. Names are names: res/mipmap-hdpi-v4/…
#   release  --crunched. Two things change. aapt2 re-encodes every PNG, so the
#            bytes are no longer the file; and AGP's resource optimization
#            (OptimizeResourcesTask → SHORTEN_RESOURCE_PATHS) renames the lot
#            to res/Ag.png, so the names are gone as well — an APK optimized
#            here had zero entries matching "res/mipmap". Nothing but the
#            resource table can say what is what, so that is what is read:
#            `aapt2 dump resources`, then the pixel dimensions of whatever it
#            points at. 72x72 at hdpi still tells the kit's legacy icon from
#            tauri's 49x49.
#
# If anyone ever sets isCrunchPngs = true on the debug build type, the debug
# path fails on byte-equality with the file named; --crunched is the answer.
set -uo pipefail
APK="${1:-}"
test -n "$APK" || { echo "usage: verify-icon.sh <apk> [--crunched]"; exit 2; }
# resolved before the cd, so a relative path typed by hand still means what it
# said; the repo root is where $RES is
[ -f "$APK" ] && APK="$(cd "$(dirname "$APK")" && pwd)/$(basename "$APK")"
# the repo this script is IN, not a drive letter. build.sh and dev.sh have
# already cd'd to /f/Coding/SoulStream and call this as
# src-tauri/android/verify-icon.sh, so ../.. lands on the same place they are
# — but a checkout on another letter, or an APK checked by hand from
# somewhere else, then compares against ITS OWN overlay rather than F:'s.
cd "$(dirname "$0")/../.." || { echo "cannot find the repo above $0"; exit 2; }
CRUNCH=0; [ "${2:-}" = "--crunched" ] && CRUNCH=1
RES=src-tauri/android/res
DPI="mdpi hdpi xhdpi xxhdpi xxxhdpi"
NAMES="ic_launcher ic_launcher_round ic_launcher_foreground ic_launcher_monochrome"
bad() { echo "ICON CHECK FAILED: $*"; exit 1; }
test -f "$APK" || bad "no APK at $APK"
test -d "$RES" || bad "$RES is missing — there is nothing to check the APK against"

# 1. the overlay itself, before the APK is opened. The monochrome layer is the
#    one Android 13 tints for themed icons and the one tauri's generator has
#    never made, so a later edit that drops it should not pass quietly.
for x in ic_launcher ic_launcher_round; do
    test -f "$RES/mipmap-anydpi-v26/$x.xml" || bad "$RES/mipmap-anydpi-v26/$x.xml is missing from the overlay"
    grep -q "<monochrome" "$RES/mipmap-anydpi-v26/$x.xml" \
        || bad "$RES/mipmap-anydpi-v26/$x.xml declares no <monochrome> layer — themed icons need one"
done
for d in $DPI; do for n in $NAMES; do
    test -f "$RES/mipmap-$d/$n.png" || bad "$RES/mipmap-$d/$n.png is missing from the overlay"
done; done

# the PNG header's width and height, eight bytes at offset 16 — the one thing
# about an image that survives being re-encoded. Printed as 72x72, so a failure
# reads as a size rather than as hex.
dims() {
    local h
    h="$(xxd -s 16 -l 8 -p)"
    [ "${#h}" = 16 ] || { echo "unreadable"; return; }
    printf '%dx%d\n' "$((16#${h:0:8}))" "$((16#${h:8:8}))"
}

LIST="$(unzip -l "$APK")" || bad "cannot read $APK"

if [ "$CRUNCH" = 0 ]; then
    # 2. debug: the adaptive XMLs by name, then all twenty PNGs byte for byte.
    #    Nothing but the overlay makes a mipmap-anydpi-v26 file, so its absence
    #    is exactly the failure this script exists for.
    for x in ic_launcher ic_launcher_round; do
        echo "$LIST" | grep -q " res/mipmap-anydpi-v26/$x\.xml$" \
            || bad "res/mipmap-anydpi-v26/$x.xml is not in the APK — $RES never reached src-tauri/gen/android/app/src/main/res"
    done
    for d in $DPI; do for n in $NAMES; do
        got="res/mipmap-$d-v4/$n.png"
        echo "$LIST" | grep -q " $got$" || bad "$got is not in the APK"
        unzip -p "$APK" "$got" | cmp -s - "$RES/mipmap-$d/$n.png" \
            || bad "$got in the APK is not $RES/mipmap-$d/$n.png — a stale res in gen/, the overlay lost a file, or this build crunched its PNGs (then: --crunched)"
    done; done
    echo "== icon: adaptive + monochrome, five densities, byte for byte from $RES"
    exit 0
fi

# 3. release. Ask the resource table what the names point at, since the paths
#    have very likely been shortened away. aapt2 is beside the zipalign and
#    apksigner build.sh has just used.
SDKU=""
[ -n "${ANDROID_HOME:-}" ] && SDKU="$(cygpath -u "$ANDROID_HOME" 2>/dev/null || echo "")"
[ -z "$SDKU" ] && [ -n "${LOCALAPPDATA:-}" ] && SDKU="$(cygpath -u "$LOCALAPPDATA" 2>/dev/null || echo "")/Android/Sdk"
A2="$(ls -1 "$SDKU"/build-tools/*/aapt2.exe 2>/dev/null | sort -V | tail -1 || true)"
if [ -z "$A2" ]; then
    echo "== icon: NOT CHECKED — no aapt2 under ${SDKU:-(no SDK path)}/build-tools."
    echo "   A release APK's resource paths are shortened (res/Ag.png), so names"
    echo "   alone cannot find the icon. Unverified here, not missing."
    exit 0
fi
# one line per file entry: "<name> <config> <path in the APK>"
MAP="$("$A2" dump resources "$APK" | awk '
    /^[ \t]*resource 0x[0-9a-f]+ mipmap\// { split($3, a, "/"); cur = a[2]; next }
    /^[ \t]*resource 0x/ { cur = ""; next }
    cur != "" { for (i = 1; i <= NF; i++) if ($i ~ /^res\//) { cfg = $1; gsub(/[()]/, "", cfg); print cur, cfg, $i } }
')" || bad "aapt2 could not read the resource table of $APK"
# the other half of the same optimization pass: with resource shrinking on,
# aapt2 also collapses the NAMES, and then even the table cannot say which
# entry is the launcher icon
if echo "$MAP" | grep -q "0_resource_name_obfuscated"; then
    echo "== icon: NOT CHECKED — this APK's resource names are collapsed"
    echo "   (aapt2 optimize --collapse-resource-names, which comes with resource"
    echo "   shrinking). Nothing left to match on. Unverified here, not missing."
    exit 0
fi
# the config is printed as "mdpi" or as "mdpi-v4" depending on the link's
# min-sdk — both seen on this machine from the same resource tree, so both are
# taken, and "anydpi" matches the "anydpi-v26" the adaptive icon lives in
look() { echo "$MAP" | awk -v n="$1" -v c="$2" '$1 == n && ($2 == c || $2 ~ "^" c "-v[0-9]+$") { print $3; exit }'; }
for x in ic_launcher ic_launcher_round; do
    got="$(look "$x" anydpi)"
    test -n "$got" || bad "mipmap/$x has no anydpi entry in this APK — the adaptive icon is not in it, so $RES never reached src-tauri/gen/android/app/src/main/res"
done
for d in $DPI; do for n in $NAMES; do
    got="$(look "$n" "$d")"
    test -n "$got" || bad "mipmap/$n has no $d entry in this APK"
    a="$(unzip -p "$APK" "$got" | dims)"
    b="$(dims < "$RES/mipmap-$d/$n.png")"
    [ "$a" = "$b" ] || bad "mipmap/$n at $d ($got) is $a, not the overlay's $b"
done; done
echo "== icon: adaptive + monochrome, five densities, by resource table ($(basename "$(dirname "$A2")")); release re-encodes the bytes, so dimensions only"
