from pathlib import Path
import argparse
import json


def run(
    summary_p: Path,
    show_distribution: bool,
    list_apks_nz_dyn: bool,
    show_dload_ads: bool,
    list_uniq_nonads: bool,
):
    with summary_p.open("r") as fp:
        summary = json.load(fp)

    nb_failed = summary["nb_failed"] + summary["nb_timeout"]
    apk_with_zero_act_visited = set()
    apk_with_non_zero_act_visited = set()
    apk_ref = set()
    apk_z_ref = set()
    apk_nz_ref = set()
    apk_dyn = set()
    apk_z_dyn = set()
    apk_nz_dyn = set()

    nb_dload = 0
    nb_dload_fb = 0
    nb_dload_goo = 0
    nb_dload_appsflyer = 0
    dload_hashes_occ = {}
    dload_hashes_ty = {}
    dload_hashes_apps = {}
    for apk, apk_data in summary["apks"].items():
        for h, dload in apk_data["dyn_loaded_files"].items():
            if h not in dload_hashes_occ:
                dload_hashes_occ[h] = 0
            dload_hashes_occ[h] += 1
            if dload["facebook_ads"]:
                dload_hashes_ty[h] = "fb ads"
            elif dload["google_ads"]:
                dload_hashes_ty[h] = "gg ads"
            elif dload["appsflyer"]:
                dload_hashes_ty[h] = "appsflyer"
            else:
                dload_hashes_ty[h] = "other"

            dload_hashes_apps[h] = apk

            nb_dload += 1
            if dload["facebook_ads"]:
                nb_dload_fb += 1
            if dload["google_ads"]:
                nb_dload_goo += 1
            if dload["appsflyer"]:
                nb_dload_appsflyer += 1
        if apk_data["nb_visited_activity"] == 0:
            apk_with_zero_act_visited.add(apk)
            if apk_data["does_reflection"]:
                apk_ref.add(apk)
                apk_z_ref.add(apk)
            if apk_data["nb_dyn_loading"] != 0:
                apk_dyn.add(apk)
                apk_z_dyn.add(apk)
        else:
            apk_with_non_zero_act_visited.add(apk)
            if apk_data["does_reflection"]:
                apk_ref.add(apk)
                apk_nz_ref.add(apk)
            if apk_data["nb_dyn_loading"] != 0:
                apk_dyn.add(apk)
                apk_nz_dyn.add(apk)

    if list_uniq_nonads:
        print("Unique bytecode files not recognized as ads / telemetry:")
        print(" Bytecode Hash                                                    | apk")
        for h, apk in dload_hashes_apps.items():
            if dload_hashes_occ[h] == 1 and dload_hashes_ty[h] == "other":
                print(f" {h} | {apk}")

    if show_dload_ads:
        print(
            f"number of dyn load                                            {nb_dload}"
        )
        print(
            f"number of dyn load of fb ads                                  {nb_dload_fb}"
        )
        print(
            f"number of dyn load of google ads                              {nb_dload_goo}"
        )
        print(
            f"number of dyn load of appsflyer code                          {nb_dload_appsflyer}"
        )
        print()
        hashes = list(dload_hashes_occ.keys())
        hashes.sort(key=lambda x: dload_hashes_occ[x], reverse=True)
        i = len(hashes)
        print(
            f"bytecode hash                                                     | number of occurence | content"
        )
        for h in hashes:
            occ = dload_hashes_occ[h]
            if occ <= 1:
                print(f"{i} other unique bytecode files")
                break
            i -= 1
            print(f" {h} | {occ:3}                 | {dload_hashes_ty[h]} ")

    if show_distribution:
        print(
            "                  | nb apk | nb failled | nb 0 activity | nb non zero activities "
        )
        print(
            f"                  | {nb_failed+len(apk_with_zero_act_visited)+len(apk_with_non_zero_act_visited):5}  | {nb_failed:5}      | {len(apk_with_zero_act_visited):5}         | {len(apk_with_non_zero_act_visited):5} "
        )
        print(
            f" With Reflection  | {len(apk_ref):5}  |      X     | {len(apk_z_ref):5}         | {len(apk_nz_ref):5} "
        )
        print(
            f" With Dyn Loading | {len(apk_dyn):5}  |      X     | {len(apk_z_dyn):5}         | {len(apk_nz_dyn):5} "
        )

    if list_apks_nz_dyn:
        for apk in apk_nz_dyn:
            print(apk)


def main():
    parser = argparse.ArgumentParser(
        prog="get_app_runtime_result_distribution",
        description="check the result of the dynamic analysis and look at class collision",
    )
    parser.add_argument(
        "summary_runtime",
        type=Path,
        help="Summary computed by check_runtimedata.py",
    )
    parser.add_argument("--list-apks-nz-dyn", action="store_true")
    parser.add_argument("--show-distribution", action="store_true")
    parser.add_argument("--show-ads", action="store_true")
    parser.add_argument("--list-uniq-nonads", action="store_true")
    args = parser.parse_args()
    run(
        args.summary_runtime,
        args.show_distribution,
        args.list_apks_nz_dyn,
        args.show_ads,
        args.list_uniq_nonads,
    )


if __name__ == "__main__":
    main()
