"""
Free Fire account information retrieval.
"""

import asyncio
import aiohttp
import ssl
from datetime import datetime
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad

# Relative imports
from .xPARA import Uaa, DecodE_HeX, EnC_PacKeT, xAuThSTarTuP
from .xHeaders import AuToUpDaTE
from .Pb2 import MajoRLoGinrEq_pb2, MajoRLoGinrEs_pb2, PorTs_pb2

# Helper functions (copied from main.py with relative imports)
async def encrypted_proto(proto_bytes: bytes) -> bytes:
    key = b'Yg&tc%DEuh6%Zc^8'
    iv = b'6oyZDr22E3ychjM%'
    cipher = AES.new(key, AES.MODE_CBC, iv)
    padded = pad(proto_bytes, AES.block_size)
    return cipher.encrypt(padded)

async def GeNeRaTeAccEss(uid: str, password: str):
    url = "https://100067.connect.garena.com/oauth/guest/token/grant"
    headers = {
        "Host": "100067.connect.garena.com",
        "User-Agent": Uaa(),   # Uaa is synchronous, but okay for now
        "Content-Type": "application/x-www-form-urlencoded",
        "Accept-Encoding": "gzip, deflate, br",
        "Connection": "close"
    }
    data = {
        "uid": uid,
        "password": password,
        "response_type": "token",
        "client_type": "2",
        "client_secret": "2ee44819e9b4598845141067b281621874d0d5d7af9d8f7e00c1e54715b7d1e3",
        "client_id": "100067"
    }
    async with aiohttp.ClientSession() as session:
        async with session.post(url, headers=headers, data=data) as resp:
            if resp.status != 200:
                return None, None
            js = await resp.json()
            open_id = js.get("open_id")
            access_token = js.get("access_token")
            return (open_id, access_token) if open_id and access_token else (None, None)

async def EncRypTMajoRLoGin(open_id: str, access_token: str, version: str) -> bytes:
    major = MajoRLoGinrEq_pb2.MajorLogin()
    major.event_time = str(datetime.now())[:-7]
    major.game_name = "free fire"
    major.platform_id = 1
    major.client_version = version
    major.system_software = "Android OS 9 / API-28 (PQ3B.190801.10101846/G9650ZHU2ARC6)"
    major.system_hardware = "Handheld"
    major.telecom_operator = "Verizon"
    major.network_type = "WIFI"
    major.screen_width = 1920
    major.screen_height = 1080
    major.screen_dpi = "280"
    major.processor_details = "ARM64 FP ASIMD AES VMH | 2865 | 4"
    major.memory = 3003
    major.gpu_renderer = "Adreno (TM) 640"
    major.gpu_version = "OpenGL ES 3.1 v1.46"
    major.unique_device_id = "Google|34a7dcdf-a7d5-4cb6-8d7e-3b0e448a0c57"
    major.client_ip = "223.191.51.89"
    major.language = "en"
    major.open_id = open_id
    major.open_id_type = "4"
    major.device_type = "Handheld"
    major.memory_available.version = 55
    major.memory_available.hidden_value = 81
    major.access_token = access_token
    major.platform_sdk_id = 1
    major.network_operator_a = "Verizon"
    major.network_type_a = "WIFI"
    major.client_using_version = "7428b253defc164018c604a1ebbfebdf"
    major.external_storage_total = 36235
    major.external_storage_available = 31335
    major.internal_storage_total = 2519
    major.internal_storage_available = 703
    major.game_disk_storage_available = 25010
    major.game_disk_storage_total = 26628
    major.external_sdcard_avail_storage = 32992
    major.external_sdcard_total_storage = 36235
    major.login_by = 3
    major.library_path = "/data/app/com.dts.freefireth-YPKM8jHEwAJlhpmhDhv5MQ==/lib/arm64"
    major.reg_avatar = 1
    major.library_token = "5b892aaabd688e571f688053118a162b|/data/app/com.dts.freefireth-YPKM8jHEwAJlhpmhDhv5MQ==/base.apk"
    major.channel_type = 3
    major.cpu_type = 2
    major.cpu_architecture = "64"
    major.client_version_code = "2019118695"
    major.graphics_api = "OpenGLES2"
    major.supported_astc_bitset = 16383
    major.login_open_id_type = 4
    major.analytics_detail = b"FwQVTgUPX1UaUllDDwcWCRBpWAUOUgsvA1snWlBaO1kFYg=="
    major.loading_time = 13564
    major.release_channel = "android"
    major.extra_info = "KqsHTymw5/5GB23YGniUYN2/q47GATrq7eFeRatf0NkwLKEMQ0PK5BKEk72dPflAxUlEBir6Vtey83XqF593qsl8hwY="
    major.android_engine_init_flag = 110009
    major.if_push = 1
    major.is_vpn = 1
    major.origin_platform_type = "4"
    major.primary_platform_type = "4"

    raw = major.SerializeToString()
    return await encrypted_proto(raw)

async def MajorLogin(base_url: str, payload: bytes, headers: dict) -> bytes:
    url = f"{base_url}MajorLogin"
    ssl_ctx = ssl.create_default_context()
    ssl_ctx.check_hostname = False
    ssl_ctx.verify_mode = ssl.CERT_NONE
    async with aiohttp.ClientSession() as session:
        async with session.post(url, data=payload, headers=headers, ssl=ssl_ctx) as resp:
            if resp.status == 200:
                return await resp.read()
            return None

async def DecRypTMajoRLoGin(data: bytes):
    proto = MajoRLoGinrEs_pb2.MajorLoginRes()
    proto.ParseFromString(data)
    return proto

async def GetLoginData(base_url: str, payload: bytes, token: str, headers: dict) -> bytes:
    url = f"{base_url}/GetLoginData"
    ssl_ctx = ssl.create_default_context()
    ssl_ctx.check_hostname = False
    ssl_ctx.verify_mode = ssl.CERT_NONE
    headers['Authorization'] = f"Bearer {token}"
    async with aiohttp.ClientSession() as session:
        async with session.post(url, data=payload, headers=headers, ssl=ssl_ctx) as resp:
            if resp.status == 200:
                return await resp.read()
            return None

async def DecRypTLoGinDaTa(data: bytes):
    proto = PorTs_pb2.GetLoginData()
    proto.ParseFromString(data)
    return proto

# Public API
async def get_account_info(uid: str, password: str) -> dict:
    """
    Obtain full account information from Free Fire.

    Args:
        uid (str): Account UID (as string)
        password (str): Account password

    Returns:
        dict: Account details including:
            - open_id (str)
            - access_token (str)
            - major_url (str)          # base URL for further requests
            - major_token (str)        # token from MajorLogin
            - account_uid (int)
            - key (bytes)              # raw key for AES
            - iv (bytes)               # raw IV for AES
            - timestamp (int)
            - auth_token (str)         # the packet for TCP authentication (hex)
            - region (str)
            - account_name (str)
            - online_ip (str)
            - online_port (int)
            - chat_ip (str)
            - chat_port (int)
    """
    # 1. Get server version and base URL
    login_url, ob_version, game_version = AuToUpDaTE()

    # 2. Build headers (using synchronous Uaa from xPARA)
    headers = {
        'User-Agent': Uaa(),
        'Connection': "Keep-Alive",
        'Accept-Encoding': "gzip",
        'Content-Type': "application/x-www-form-urlencoded",
        'Expect': "100-continue",
        'X-Unity-Version': "2018.4.11f1",
        'X-GA': "v1 1",
        'ReleaseVersion': ob_version
    }

    # 3. Get OAuth tokens
    open_id, access_token = await GeNeRaTeAccEss(uid, password)
    if not open_id or not access_token:
        raise Exception("Invalid credentials or network error")

    # 4. Build encrypted MajorLogin payload
    payload = await EncRypTMajoRLoGin(open_id, access_token, game_version)

    # 5. Send MajorLogin
    major_resp = await MajorLogin(login_url, payload, headers)
    if not major_resp:
        raise Exception("MajorLogin request failed")

    # 6. Parse MajorLogin response
    major_info = await DecRypTMajoRLoGin(major_resp)

    # 7. Get login data (IPs, ports, region, name)
    login_data_resp = await GetLoginData(major_info.url, payload, major_info.token, headers)
    if not login_data_resp:
        raise Exception("GetLoginData request failed")

    # 8. Parse login data
    login_data = await DecRypTLoGinDaTa(login_data_resp)

    # 9. Extract information
    online_ip, online_port = login_data.Online_IP_Port.split(":")
    chat_ip, chat_port = login_data.AccountIP_Port.split(":")

    # 10. Compute the authentication token (the packet to send to TCP servers)
    auth_token = await xAuThSTarTuP(int(major_info.account_uid),
                                    major_info.token,
                                    int(major_info.timestamp),
                                    major_info.key,
                                    major_info.iv)

    result = {
        "open_id": open_id,
        "access_token": access_token,
        "major_url": major_info.url,
        "major_token": major_info.token,
        "account_uid": major_info.account_uid,
        "key": major_info.key,               # raw bytes
        "iv": major_info.iv,                 # raw bytes
        "timestamp": major_info.timestamp,
        "auth_token": auth_token,
        "region": login_data.Region,
        "account_name": login_data.AccountName,
        "online_ip": online_ip,
        "online_port": int(online_port),
        "chat_ip": chat_ip,
        "chat_port": int(chat_port),
    }
    return result