# -*- coding: utf-8 -*-
"""Frida SG native trace — attach to sg.com.maribankmobile.digitalbank."""
import sys
import time
from datetime import datetime
from pathlib import Path

import frida

PKG = "sg.com.maribankmobile.digitalbank"
HERE = Path(__file__).resolve().parent
LOGS_DIR = HERE.parent / "logs" / "frida"
LOGS_DIR.mkdir(parents=True, exist_ok=True)
SCRIPT = HERE / "trace_maribank_sg_native.js"
LOG = LOGS_DIR / ("sg_native_%s.log" % datetime.now().strftime("%Y%m%d_%H%M%S"))


def on_message(message, data):
    mtype = message.get("type")
    if mtype == "send":
        line = message.get("payload")
    elif mtype == "log":
        line = message.get("payload", message.get("description", ""))
    else:
        line = str(message)
    text = line if isinstance(line, str) else repr(line)
    print(text, flush=True)
    with open(LOG, "a", encoding="utf-8") as f:
        f.write(text + "\n")
    if mtype == "error":
        with open(str(LOG) + ".err", "a", encoding="utf-8") as f:
            f.write(text + "\n")


def wait_for_process(device, pkg, timeout_sec=60):
    deadline = time.time() + timeout_sec
    while time.time() < deadline:
        for app in device.enumerate_applications():
            if app.identifier == pkg and app.pid and app.pid > 0:
                return app.pid
        for proc in device.enumerate_processes():
            if proc.name == pkg:
                return proc.pid
        time.sleep(0.5)
    return None


def launch_app(pkg):
    import subprocess

    adb = r"C:\Users\Administrator\AppData\Local\Android\Sdk\platform-tools\adb.exe"
    subprocess.run([adb, "shell", "am", "force-stop", pkg], check=False, capture_output=True)
    time.sleep(1)
    subprocess.run(
        [
            adb,
            "shell",
            "am",
            "start",
            "-n",
            pkg + "/com.shopee.bke.digitalbank.ui.MainActivity",
        ],
        check=False,
        capture_output=True,
    )


def ensure_frida_server():
    import subprocess

    adb = r"C:\Users\Administrator\AppData\Local\Android\Sdk\platform-tools\adb.exe"
    out = subprocess.run(
        [adb, "shell", "su", "-c", "pgrep frida-server"],
        capture_output=True,
        text=True,
    )
    if out.stdout.strip():
        return
    subprocess.run(
        [adb, "shell", "su", "-c", "/data/local/tmp/frida-server -D &"],
        check=False,
        capture_output=True,
    )
    time.sleep(2)


def main():
    mode = "attach"
    if len(sys.argv) > 1:
        mode = sys.argv[1]

    if not SCRIPT.is_file():
        raise SystemExit("missing script: %s" % SCRIPT)

    ensure_frida_server()
    device = frida.get_usb_device(timeout=10)
    source = SCRIPT.read_text(encoding="utf-8")

    print("Package: %s" % PKG)
    print("Script:  %s" % SCRIPT)
    print("Log:     %s" % LOG)
    print("")
    print("IMPORTANT: keep LSPosed scope ENABLED for SG (bypasses ADB page while tracing)")
    print("")

    if mode == "spawn":
        pid = device.spawn([PKG])
        session = device.attach(pid)
    else:
        pid = wait_for_process(device, PKG, 3)
        if pid is None:
            print("Launching MariBank SG ...")
            launch_app(PKG)
            pid = wait_for_process(device, PKG, 90)
        if pid is None:
            raise SystemExit(
                "SG MariBank not running — open app to Sign up page, then re-run"
            )
        print("Attach pid=%s" % pid)
        session = device.attach(pid)

    script = session.create_script(source)
    script.on("message", on_message)
    script.load()

    if mode == "spawn":
        device.resume(pid)
        print("Spawn resumed, wait JVM 15s ...")
        time.sleep(15)
    else:
        time.sleep(3)

    print("Trace running. Sign up -> +65 -> Next. Ctrl+C to stop.")
    try:
        while True:
            time.sleep(1)
    except KeyboardInterrupt:
        print("Stopping...")
        session.detach()


if __name__ == "__main__":
    main()
