import requests
import struct
import time

def create_amf_request(version_string="Public 0.53.1"):
    """
    Membuat paket binary AMF (Action Message Format) secara manual.
    Format ini digunakan oleh Flash/AIR untuk komunikasi client-server.
    """
    # 1. Header AMF0
    # ------------------------------------------------
    packet = b'\x00\x03'  # Versi AMF (AMF3)
    packet += b'\x00\x00' # Header Count (0 header)
    packet += b'\x00\x01' # Body Count (1 body)
    
    # 2. Target & Response URI
    # ------------------------------------------------
    # Target: Method yang dipanggil di server (SystemLogin.checkVersion)
    target = b"SystemLogin.checkVersion"
    packet += struct.pack(">H", len(target)) + target
    
    # Response: Client ID / Counter (biasanya /1, /2, dst)
    response = b"/1"
    packet += struct.pack(">H", len(response)) + response
    
    # Content Length (Placeholder, tidak wajib presisi untuk server ini)
    # packet += b'\xff\xff\xff\xff' 
    
    # 3. Body Content (AMF3)
    # ------------------------------------------------
    # Byte 0x11 menandakan isi body adalah format AMF3
    body = b'\x11' 
    
    # Struktur Array AMF3 [Argumen Fungsi]
    # 0x09 = Tipe Array
    # 0x03 = (Jumlah elemen 1 << 1) | 1. Ini encoding U29.
    #        1 elemen -> 1<<1 = 2 -> 2|1 = 3.
    # 0x01 = Penanda akhir array asosiatif (empty string)
    body += b'\x09\x03\x01'
    
    # Elemen 1: String Versi
    # 0x06 = Tipe String
    body += b'\x06'
    
    # Panjang String (U29 Encoded)
    # Bitwise shift: (Panjang << 1) | 1
    l = len(version_string)
    encoded_len = (l << 1) | 1
    body += bytes([encoded_len])
    
    # Isi String
    body += version_string.encode('utf-8')
    
    # Gabungkan panjang body + isi body ke packet
    packet += struct.pack(">I", len(body))
    packet += body
    
    return packet

def parse_amf_response(data):
    """
    Membaca respon binary dari server dan mencari nilai penting.
    Kita mencari pola byte (byte signature) daripada menggunakan library berat.
    """
    print(f"\n[Analisis Respon AMF]")
    # print(f"Raw Hex: {data.hex()}")
    
    try:
        # Cari data Token (__)
        # Pola: 0x05 (Double?) tidak, string kuncinya '__'
        # '__' length 2 -> (2<<1)|1 = 5. Hex: 05 5f 5f
        # Diikuti tipe datanya. Biasanya String (0x06).
        token_marker = data.find(b'\x05\x5f\x5f\x06')
        if token_marker != -1:
            # Byte setelah marker adalah panjang string token
            len_byte = data[token_marker+4]
            token_len = len_byte >> 1 # Decode U29 length
            
            # Ambil string token
            token = data[token_marker+5 : token_marker+5+token_len].decode('utf-8')
            print(f"✅ Token (__): {token}")
            print(f"   (Token ini wajib dipakai untuk login berikutnya)")

        # Cari Server Timestamp (_)
        # Pola: Key '_' (Length 1 -> 3. Hex: 03 5f)
        # Diikuti tipe Double (0x05)
        # Jadi kita cari: 03 5f 05
        ts_marker = data.find(b'\x03\x5f\x05')
        if ts_marker != -1:
            # Double adalah 8 byte floating point
            double_bytes = data[ts_marker+3 : ts_marker+3+8]
            timestamp = struct.unpack(">d", double_bytes)[0]
            print(f"✅ Server Time (_): {timestamp}")
            print(f"   (Waktu: {time.ctime(timestamp)})")
            
        # Parse '_rm'
        rm_idx = data.find(b'_rm')
        if rm_idx != -1:
            val_type_idx = rm_idx + 3
            if data[val_type_idx] == 0x02:
                print(f"Remember Me (_rm): False")
            elif data[val_type_idx] == 0x03:
                print(f"Remember Me (_rm): True")

    except Exception as e:
        print(f"Parsing error: {e}")

def main():
    url = "https://play.ninjasage.id/amf"
    headers = {
        "Content-Type": "application/x-amf",
        "User-Agent": "Mozilla/5.0 (Windows; U; en) AppleWebKit/533.19.4 (KHTML, like Gecko) AdobeAIR/51.1",
        "Referer": "app:/NinjaSage.swf",
        "x-flash-version": "51,1,3,10"
    }
    
    payload = create_amf_request()
    
    print(f"Sending AMF request to {url}...")
    try:
        response = requests.post(url, headers=headers, data=payload, verify=False)
        print(f"Status Code: {response.status_code}")
        
        if response.status_code == 200:
            parse_amf_response(response.content)
        else:
            print("Request failed")
            print(response.text)
            
    except Exception as e:
        print(f"Connection error: {e}")

if __name__ == "__main__":
    main()
