#!/usr/bin/env python3
"""Build an instrumented copy of the current SecroAuth loader for timing."""
from __future__ import annotations
import json
import sys
import urllib.request
from pathlib import Path

ROOT = Path("/opt/ws-remote")
SID = "056e573923205845"
BASE = "https://209.50.60.133.sslip.io"
TOKEN = json.loads((ROOT / "accounts.json").read_text())["users"]["admin"]["token"]


def api(path: str, payload: dict):
    req = urllib.request.Request(
        f"http://127.0.0.1:8080/api/secroauth/{path}",
        data=json.dumps(payload).encode(),
        headers={"Content-Type": "application/json",
                 "Authorization": "Bearer " + TOKEN})
    with urllib.request.urlopen(req, timeout=30) as resp:
        return json.load(resp)


def main():
    key_path = Path("/tmp/opencode/timing_key.txt")
    if key_path.exists() and key_path.read_text().strip():
        key = key_path.read_text().strip()
    else:
        made = api("keys/create", {"script_id": SID, "count": 1, "days": -1,
                                   "hwid_lock": True, "note": "loader timing"})
        key = made["keys"][0]
        key_path.write_text(key)
    template = (ROOT / "luraph_pack/loader_guard.luau").read_text()
    sign_code = (ROOT / "luraph_pack/socket_sign.luau").read_text()
    template = template.replace("-- __SOCKET_SIGN__\n", sign_code)
    clear = (template.replace("__SID__", json.dumps(SID))
             .replace("__WS__", json.dumps(
                 BASE.replace("https://", "wss://", 1) + "/ws?role=secroauth&script_id=" + SID))
             .replace("__SIGN__", json.dumps(
                 __import__("hmac").new(
                     (json.loads((ROOT / "secroauth.json").read_text())["secret"]).encode(),
                     ("socket-v2:" + SID).encode(), __import__("hashlib").sha256).hexdigest())))
    # Timing instrumentation.  These prints are only in this local test build.
    clear = 'script_key = ' + json.dumps(key) + '\n' + clear
    clear = clear.replace(
        "local type, pcall, rawequal, tostring = type, pcall, rawequal, tostring",
        "local __t0 = os.clock()\n"
        "local function __mark(name) print('[lt]', name, string.format('%.3f', os.clock() - __t0)) end\n"
        "__mark('start')\n"
        "local type, pcall, rawequal, tostring = type, pcall, rawequal, tostring")
    clear = clear.replace(
        'if __sign("hello:" .. SCRIPT_ID .. ":" .. nonce) ~= tostring(hello.sig or "") then',
        '__mark("hello")\nif __sign("hello:" .. SCRIPT_ID .. ":" .. nonce) ~= tostring(hello.sig or "") then')
    clear = clear.replace(
        'local enc64 = ""',
        '__mark("auth_sent")\nlocal enc64 = ""')
    clear = clear.replace(
        'elseif data.type == "done" then',
        'elseif data.type == "done" then\n                __mark("done")')
    clear = clear.replace(
        'local encrypted = b64(enc64)',
        '__mark("b64_start")\nlocal encrypted = b64(enc64)\n__mark("b64_done")')
    clear = clear.replace(
        'local source = decrypt(encrypted, xkey)',
        '__mark("decrypt_start")\nlocal source = decrypt(encrypted, xkey)\n__mark("decrypt_done")')
    clear = clear.replace(
        'local loaded, chunk = pcall(L.loader, source)',
        '__mark("loadstring_start")\nlocal loaded, chunk = pcall(L.loader, source)\n__mark("loadstring_done")')
    clear = clear.replace(
        'local ok, err = pcall(chunk)',
        '__mark("run_start")\nlocal ok, err = pcall(chunk)\n__mark("run_done")')
    every = int(__import__("os").environ.get("YIELD_EVERY", "8192"))
    if every <= 0:
        clear = clear.replace("if wait and i % 8192 == 0 then\n            wait(0)\n        end", "")
    elif every != 8192:
        clear = clear.replace("i % 8192 == 0", "i % %d == 0" % every)
    sys.path.insert(0, str(ROOT))
    import secro_mode
    protected = secro_mode.build(clear)
    suffix = "noyield" if every <= 0 else str(every)
    Path(f"/tmp/opencode/loader_timing_{suffix}.lua").write_text(protected, encoding="utf-8")
    print("key", key)
    print("bytes", len(protected.encode()), "yield", every)


if __name__ == "__main__":
    main()
