"""D5 last pass: the endpoint table (call-id -> URL), CreatePack's URL builder,
who sets the CreatePack purchase MODE, and the PurchaseItems response defaults.

HYPOTHESES
 H9: every FUT ServerCall carries a numeric id (CreatePack=0x4b, PurchaseItems=0x4c,
     passed to FUN_18016be60) and a table near 0x18021e100 maps id -> URL format
     string ("ut/%s/store", "ut/%s/purchased", ...).
 H10: FUN_180124ad0 is CreatePack's URL builder and it emits the "store/transaction"
     path we already see on the wire.
 H11: the mode field at +0x20 of the CreatePack call (0=COINS,1=MTX,2=POINTS,4=preorder)
     is set by whoever constructs it; callers of FUN_1801623d0 will show the choice.

CONTROL: dec(0x180162530) reprinted (known: writes packId/useCredits/usePreOrder/currency).
"""
import traceback, os, struct

OUT = "/tmp/claude-1000/-home-alex-Documents-OpenFUT/8e521ca1-ca3e-4138-bb96-df1744dd1d30/scratchpad/packres"

def w(name, text):
    p = os.path.join(OUT, name)
    with open(p, "w") as f:
        f.write(text)
    print("WROTE %s (%d bytes)" % (p, len(text)))

try:
    buf = []
    def P(*a):
        s = " ".join(str(x) for x in a)
        print(s); buf.append(s)

    s = dec(0x180162530)
    P("CONTROL dec(0x180162530) len=%d has_MTX=%s has_COINS=%s"
      % (len(s), '"MTX"' in s, '"COINS"' in s))

    P("")
    P("=== endpoint table 0x18021e080..0x18021e900 ===")
    a = 0x18021e080
    while a < 0x18021e900:
        try:
            q = qword(a)
        except Exception as e:
            P("  %#x ERR %s" % (a, e)); a += 8; continue
        f = fm.getFunctionAt(addr(q)) if 0x180000000 <= q < 0x181000000 else None
        extra = ""
        if 0x180000000 <= q < 0x181000000 and f is None:
            try:
                t = rd_str(q, 60)
                if t and all(32 <= ord(c) < 127 for c in t):
                    extra = "->str %r" % t
            except Exception:
                pass
        P("  %#x -> %#x %s %s" % (a, q, f.getName() if f else "", extra))
        a += 8

    P("")
    P("=== createpack req vtable 0x180214d40..0x180214e10 ===")
    a = 0x180214d40
    while a < 0x180214e10:
        q = qword(a)
        f = fm.getFunctionAt(addr(q)) if 0x180000000 <= q < 0x181000000 else None
        P("  +%03x %#x -> %#x %s" % (a - 0x180214d40, a, q, f.getName() if f else ""))
        a += 8

    P("")
    for callee, tag in ((0x1801623d0, "createpack_call_ctor"),
                        (0x1801263a0, "purchaseitems_call_ctor"),
                        (0x18016be60, "servercall_base_ctor"),
                        (0x180124ad0, "maybe_createpack_url")):
        try:
            cs = callers(callee)
        except Exception as e:
            P("CALLERS %s ERR %s" % (tag, e)); continue
        P("CALLERS of %-26s %#x : %s" % (tag, callee, [("%#x" % c, n) for c, n in cs][:30]))
        try:
            xs = xrefs_to(callee)
            P("   xrefs: %s" % [("%#x" % f2, t, n) for f2, t, n, e2 in xs][:30])
        except Exception:
            pass

    w("d5_q5_notes.txt", "\n".join(buf) + "\n")

    TG = {"createpack_url_180124ad0": 0x180124ad0,
          "createpack_x_180162c90": 0x180162c90,
          "servercall_base_ctor_18016be60": 0x18016be60,
          "purchaseitems_resp_ctor_18002d460": 0x18002d460,
          "fp_18002ee50": 0x18002ee50,
          "fp_18002ed20": 0x18002ed20,
          "fp_18002f1b0": 0x18002f1b0,
          "fp_18002f0b0": 0x18002f0b0,
          "fp_18002f920": 0x18002f920,
          "generic_180068320": 0x180068320,
          "packtypes_url_180123430": 0x180123430}
    for tag, va in sorted(TG.items()):
        try:
            src = dec(va)
        except Exception as e:
            src = "// ERR %s" % e
        w("d5_q5_dec_%s.txt" % tag, "// %s %#x len=%d\n" % (tag, va, len(src)) + src)

    # who constructs the createpack call -> the mode
    ctor_callers = set()
    for c, n in callers(0x1801623d0):
        ctor_callers.add(int(c))
    for frm, typ, fn, ent in xrefs_to(0x1801623d0):
        if ent:
            ctor_callers.add(int(ent))
    txt = []
    for e in sorted(ctor_callers):
        src = dec(e)
        txt.append("// ===== caller of createpack ctor %#x %s len=%d\n%s" % (e, fname(e), len(src), src))
    w("d5_q5_createpack_callers.txt", "\n".join(txt) if txt else "// none found\n")

    w("d5_q5_notes.txt", "\n".join(buf) + "\n")
    print("DONE")
except Exception:
    traceback.print_exc()
