#!/usr/bin/env python3
"""Retain iOS dSYMs and a typed receipt for automatic upload through the proxied console."""
from __future__ import annotations

import argparse
import hashlib
import json
import os
from pathlib import Path
import subprocess
import zipfile

from crashlytics_dsyms import (CONFIG_NAME, app_id_from_config, find_upload_symbols,
                               select_app_id)

SCHEMA = "gowalk-cicd/firebase-symbols-pending.v1"


def prepare(archive: Path, output: Path, app_id: str) -> dict:
    root = (archive / "dSYMs").resolve()
    bundles = sorted(root.glob("*.dSYM"))
    files = sorted(path for bundle in bundles for path in bundle.rglob("*") if path.is_file())
    if not files or any(path.is_symlink() or root not in path.resolve().parents for path in files):
        raise ValueError("Archive must contain dSYM files owned by this build")
    output.mkdir(parents=True, exist_ok=True)
    target = output / "ios-dsyms.zip"
    with zipfile.ZipFile(target, "w", compression=zipfile.ZIP_DEFLATED) as zipped:
        for path in files:
            zipped.write(path, path.relative_to(root))
    with target.open("rb") as stream:
        digest = hashlib.file_digest(stream, "sha256").hexdigest()
    uuids = subprocess.check_output(["dwarfdump", "--uuid", *(str(bundle) for bundle in bundles)],
                                    text=True, timeout=60).splitlines()
    artifact = f"ios-crashlytics-symbols-{os.environ['GITHUB_RUN_ID']}-{os.environ['GITHUB_RUN_ATTEMPT']}"
    receipt = {"schema": SCHEMA, "platform": "ios", "app_id": app_id,
               "source_sha": os.environ["GITHUB_SHA"], "artifact": artifact,
               "file": target.name, "sha256": digest, "status": "pending_console_upload"}
    (output / "firebase-symbols.json").write_text(json.dumps({**receipt, "uuids": uuids}, indent=2))
    return receipt


def main() -> None:
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("--archive", required=True, type=Path)
    parser.add_argument("--search-root", required=True, type=Path)
    parser.add_argument("--output", required=True, type=Path)
    args = parser.parse_args()
    app_id = select_app_id(os.environ.get("FIREBASE_APP_ID", ""), "ios")
    tool = find_upload_symbols(args.search_root)
    if not tool:
        print("No Crashlytics SDK upload tool found; no Firebase symbol delivery is required.")
        return
    if not app_id:
        app_id = app_id_from_config(args.search_root, "ios")
    if not app_id:
        raise SystemExit(
            "The app embeds Crashlytics but no iOS Firebase app is named: FIREBASE_APP_ID is "
            f"unset or names another platform, and no {CONFIG_NAME} under "
            f"{args.search_root} carries an iOS GOOGLE_APP_ID")
    receipt = prepare(args.archive, args.output, app_id)
    if os.environ.get("MOBILE_CANDIDATE_BUILD") != "true":
        print("::notice title=firebase_symbols_pending::" + json.dumps(receipt, separators=(",", ":")))


if __name__ == "__main__":
    main()
