#!/usr/bin/env bash
#
# firebase-app-discovery.sh  -  read the Firebase app ids a repo already carries.
#
# Every Crashlytics call needs the opaque appId (1:<number>:<platform>:<hex>), and
# a console URL only ever carries the bundle id. fetch-crashlytics.sh resolves the
# pair through the Firebase Management API on every run, which works and costs a
# round trip plus a resolved project. The repo has already been told the answer:
# GoogleService-Info*.plist (iOS) and google-services.json (Android) are generated
# by the console and carry both ids.
#
# Usage:
#   ./firebase-app-discovery.sh [repo-dir]            # table
#   ./firebase-app-discovery.sh [repo-dir] --json     # {"accounts":[...]}
#
# --json prints entries shaped for prefs.global.firebase.accounts[]: one per
# projectId, each with an apps[] of {bundleId, appId, platform}. keychainKey is
# left out on purpose - which credential covers a project is the user's mapping to
# make, not this script's to guess.
#
# A repo with several targets has several plists and they do not all point at one
# Firebase project: every match is read, never just the first. Build outputs are
# skipped, because a copied plist under DerivedData or build/ is the same app
# counted twice.
#
# Exit 0 always: finding nothing is an answer, not a failure.

set -uo pipefail

DIR="."
MODE="table"
for a in "$@"; do
  case "$a" in
    --json) MODE="json" ;;
    -h|--help) echo "usage: $0 [repo-dir] [--json]" >&2; exit 0 ;;
    *) DIR="$a" ;;
  esac
done

if [ ! -d "$DIR" ]; then
  echo "ERR: not a directory: $DIR" >&2
  exit 0
fi

FILES=$(find "$DIR" \
  \( -name node_modules -o -name Pods -o -name .build -o -name DerivedData \
     -o -name build -o -name .git -o -name .next \) -prune -o \
  \( -name 'GoogleService-Info*.plist' -o -name 'google-services.json' \) -print 2>/dev/null)

# The file list travels as an env var, not on stdin: `python3 - <<SCRIPT` already
# takes its program from stdin, and a second redirection silently wins, feeding
# the interpreter the paths as if they were source.
MODE="$MODE" FB_FILES="$FILES" python3 - "$DIR" <<'PY'
import json, os, plistlib, sys

repo = sys.argv[1]
paths = [p for p in os.environ.get("FB_FILES", "").split("\n") if p.strip()]

# projectId -> {bundleId: (appId, platform)}; a dict per project because the same
# target can appear twice (a Debug and a Release plist naming one app), and the
# second read must not double the row.
projects = {}

def record(project, bundle, app_id, platform):
    if not (project and bundle and app_id):
        return
    projects.setdefault(project, {})[bundle] = (app_id, platform)

for path in paths:
    try:
        if path.endswith(".plist"):
            with open(path, "rb") as fh:
                d = plistlib.load(fh)
            app_id = d.get("GOOGLE_APP_ID") or ""
            platform = "android" if ":android:" in app_id else "ios"
            record(d.get("PROJECT_ID"), d.get("BUNDLE_ID"), app_id, platform)
        else:
            with open(path, encoding="utf-8") as fh:
                d = json.load(fh)
            project = ((d.get("project_info") or {}).get("project_id")) or ""
            for client in d.get("client") or []:
                info = client.get("client_info") or {}
                app_id = info.get("mobilesdk_app_id") or ""
                bundle = ((info.get("android_client_info") or {}).get("package_name")) or ""
                record(project, bundle, app_id, "android")
    except Exception:
        # A malformed or unreadable file is one app not discovered, never a reason
        # to abandon the ones that parsed.
        continue

accounts = [
    {
        "projectId": pid,
        "apps": [
            {"bundleId": b, "appId": a, "platform": pf}
            for b, (a, pf) in sorted(apps.items())
        ],
    }
    for pid, apps in sorted(projects.items())
]

if os.environ.get("MODE") == "json":
    print(json.dumps({"accounts": accounts}, indent=2))
    sys.exit(0)

if not accounts:
    print("no Firebase config found under %s" % repo)
    sys.exit(0)

for acc in accounts:
    print(acc["projectId"])
    for app in acc["apps"]:
        print("  %-8s %-45s %s" % (app["platform"], app["bundleId"], app["appId"]))
PY
