#!/usr/bin/env python3.12
"""Ambil isi node MEGA hasil import folder publik + dekripsi nama/size, dan unduh file.
Pakai m._api_request (butuh sid) — jangan requests.post langsung ke API.
Usage:
  python3.12 mega_pull.py list
  python3.12 mega_pull.py download [dest_dir]
"""
import os, sys, json, struct
import requests
from mega import Mega
from mega.crypto import (base64_to_a32, base64_url_decode, decrypt_attr,
                         decrypt_key, a32_to_str, a32_to_base64,
                         encrypt_key, base64_url_encode, encrypt_attr)
from Crypto.Cipher import AES
from Crypto.Util import Counter

HANDLE = "HRMAlYzK"
KEY = "IJeN5r2FcnfkWLt7w4ZfzQ"
FOLDER_NAME = "TSC-STOCK-BARU"
DEST_DEFAULT = "/home/mantapman/.hermes/profiles/atun/workspace/tsc_stock_baru"


def walk(m, node_handle, key):
    try:
        data = m._api_request({"a": "f", "c": 1, "r": 1, "p": node_handle})
    except Exception as e:
        print("  list gagal untuk", node_handle, e)
        return []
    out = []
    for n in data.get("f", []):
        keys = {}
        if n.get("k"):
            for part in n["k"].split("/"):
                if ":" in part:
                    h, kk = part.split(":", 1)
                    keys[h] = kk
        nk, name = None, None
        for h, kk in keys.items():
            try:
                cand = decrypt_key(base64_to_a32(kk), key)
                nm = decrypt_attr(base64_url_decode(n.get("a", "")), cand)
                if nm and "n" in nm:
                    nk, name = cand, nm["n"]
                    break
            except Exception:
                continue
        out.append({"h": n["h"], "type": n.get("t"), "size": n.get("s"),
                    "name": name, "key": nk, "ts": n.get("ts")})
        if n.get("t") == 1 and nk:
            out.extend(walk(m, n["h"], nk))
    return out


def download_file(m, handle, key, dest, name):
    data = m._api_request({"a": "g", "g": 1, "p": handle})
    url = data["g"]
    kr = (key[0] ^ key[4], key[1] ^ key[5], key[2] ^ key[6], key[3] ^ key[7])
    ctr = Counter.new(128, initial_value=((key[4] << 32) + key[5]) << 64)
    cipher = AES.new(a32_to_str(kr), AES.MODE_CTR, counter=ctr)
    path = os.path.join(dest, name)
    with requests.get(url, stream=True, timeout=600) as resp:
        resp.raise_for_status()
        with open(path, "wb") as f:
            for chunk in resp.iter_content(chunk_size=1 << 20):
                if chunk:
                    f.write(cipher.decrypt(chunk))
    return path


def main():
    mode = sys.argv[1] if len(sys.argv) > 1 else "list"
    dest = sys.argv[2] if len(sys.argv) > 2 else DEST_DEFAULT
    m = Mega().login()
    key = tuple(base64_to_a32(KEY))
    enc_key = a32_to_base64(encrypt_key(key, m.master_key))
    enc_name = base64_url_encode(encrypt_attr({'n': FOLDER_NAME}, key))
    destnode = m.get_node_by_type(2)[1]
    res = m._api_request({'a': 'p', 't': destnode['h'],
                          'n': [{'ph': HANDLE, 't': 1, 'a': enc_name, 'k': enc_key}]})
    fh = res['f'][0]['h']
    print("folder node:", fh, flush=True)
    items = walk(m, fh, key)
    print(f"\n{len(items)} node:")
    for it in items:
        print(f"  {'DIR ' if it['type'] == 1 else 'FILE'} | {it['size']} | {it['name']} | {it['h']}")
    json.dump([{k: v for k, v in it.items() if k != 'key'} for it in items],
              open("/home/mantapman/.hermes/profiles/atun/workspace/mega_folder_list.json", "w"),
              indent=1, ensure_ascii=False)
    if mode == "download":
        os.makedirs(dest, exist_ok=True)
        for it in items:
            if it["type"] != 0:
                continue
            if not it["name"] or not it["key"]:
                print("skip (nama/key gagal):", it["h"])
                continue
            if os.path.exists(os.path.join(dest, it["name"])):
                print("skip ada:", it["name"])
                continue
            print("unduh:", it["name"], flush=True)
            try:
                download_file(m, it["h"], it["key"], dest, it["name"])
            except Exception as e:
                print("  GAGAL:", type(e).__name__, e, flush=True)
        print("\nhasil:", sorted(os.listdir(dest)))


if __name__ == "__main__":
    main()
