import requests
import time
import threading
import jwt
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
from google.protobuf import json_format
from . import my_pb2
from . import jwt_generator_pb2

class N1LUXGenerator:
    def __init__(self):
        self.AES_KEY = b'Yg&tc%DEuh6%Zc^8'
        self.AES_IV = b'6oyZDr22E3ychjM%'
        self.version_cache = None
        self.version_time = 0
        self.CACHE_DURATION = 300
        self.lock = threading.Lock()

    def _encrypt_message(self, plaintext):
        cipher = AES.new(self.AES_KEY, AES.MODE_CBC, self.AES_IV)
        padded_message = pad(plaintext, AES.block_size)
        return cipher.encrypt(padded_message)

    def _fetch_live_version(self):
        current = time.time()
        with self.lock:
            if self.version_cache and (current - self.version_time) < self.CACHE_DURATION:
                return self.version_cache
            
            try:
                url = "https://bdversion.ggbluefox.com/live/ver.php?version=1.108.3&lang=ar&device=android&channel=android&appstore=googleplay&region=ME&whitelist_version=1.3.0&whitelist_sp_version=1.0.0"
                response = requests.get(url, timeout=5)
                data = response.json()
                ob_version = data.get('latest_release_version')
                if ob_version:
                    self.version_cache = ob_version
                    self.version_time = current
                    return ob_version
            except:
                pass
            return "OB52"

    def get_open_id(self, access_token):
        try:
            uid_url = "https://prod-api.reward.ff.garena.com/redemption/api/auth/inspect_token/"
            uid_headers = {
                "authority": "prod-api.reward.ff.garena.com",
                "access-token": access_token,
                "user-agent": "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36"
            }
            uid_res = requests.get(uid_url, headers=uid_headers, timeout=5)
            uid = uid_res.json().get("uid")
            
            if not uid:
                return None
            
            openid_url = "https://shop2game.com/api/auth/player_id_login"
            openid_headers = {
                "Content-Type": "application/json",
                "User-Agent": "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Mobile Safari/537.36",
                "Cookie": "source=mb; region=MA; language=ar"
            }
            payload = {"app_id": 100067, "login_id": str(uid)}
            openid_res = requests.post(openid_url, headers=openid_headers, json=payload, timeout=5)
            return openid_res.json().get("open_id")
        except:
            return None

    def login_guest(self, uid, password):
        try:
            oauth_url = "https://100067.connect.garena.com/oauth/guest/token/grant"
            payload = {
                'uid': uid,
                'password': password,
                'response_type': "token",
                'client_type': "2",
                'client_secret': "2ee44819e9b4598845141067b281621874d0d5d7af9d8f7e00c1e54715b7d1e3",
                'client_id': "100067"
            }
            headers = {'User-Agent': "GarenaMSDK/4.0.19P9(SM-M526B ;Android 13;pt;BR;)"}
            resp = requests.post(oauth_url, data=payload, headers=headers, timeout=5)
            data = resp.json()
            if 'access_token' in data:
                return data['access_token'], data.get('open_id', '')
            return None, None
        except:
            return None, None

    def generate_token(self, access_token=None, uid=None, password=None):
        open_id = None        
        if access_token:
            open_id = self.get_open_id(access_token)
            if not open_id:
                return {"status": "error", "message": "Invalid Access Token or Failed to fetch OpenID"}
        elif uid and password:
            access_token, open_id = self.login_guest(uid, password)
            if not access_token:
                return {"status": "error", "message": "Invalid UID/Password"}
        
        else:
            return {"status": "error", "message": "Missing credentials"}
        ob_version = self._fetch_live_version()
        platforms = [1, 2, 3, 4, 5, 8, 11]

        for platform_type in platforms:
            try:
                game_data = my_pb2.GameData()
                game_data.timestamp = "2024-12-05 18:15:32"
                game_data.game_name = "free fire"
                game_data.game_version = 1
                game_data.version_code = "1.108.3"
                game_data.os_info = "Android OS 9 / API-28"
                game_data.device_type = "Handheld"
                game_data.connection_type = "WIFI"
                game_data.screen_width = 1280
                game_data.screen_height = 960
                game_data.dpi = "240"
                game_data.cpu_info = "ARMv7 VFPv3 NEON VMH | 2400 | 4"
                game_data.total_ram = 5951
                game_data.gpu_name = "Adreno (TM) 640"
                game_data.gpu_version = "OpenGL ES 3.0"
                game_data.ip_address = "1.1.1.1"
                game_data.language = "en"
                game_data.open_id = open_id
                game_data.access_token = access_token
                game_data.platform_type = platform_type
                game_data.field_99 = str(platform_type)
                game_data.field_100 = str(platform_type)

                serialized_data = game_data.SerializeToString()
                encrypted_data = self._encrypt_message(serialized_data)

                url = "https://loginbp.ggpolarbear.com/MajorLogin"
                headers = {
                    'User-Agent': "Dalvik/2.1.0 (Linux; U; Android 9; ASUS_Z01QD Build/PI)",
                    'Content-Type': "application/octet-stream",
                    'X-Unity-Version': "2022.3.47f1",
                    'X-GA': "v1 1",
                    'ReleaseVersion': str(ob_version),
                }

                response = requests.post(url, data=encrypted_data, headers=headers, timeout=5)

                if response.status_code == 200:
                    msg = jwt_generator_pb2.NR_CODEX()
                    msg.ParseFromString(response.content)

                    token_value = msg.token
                    if not token_value:
                        continue

                    decoded_token = jwt.decode(token_value, options={"verify_signature": False})
                    data_dict = json_format.MessageToDict(msg, preserving_proto_field_name=True)

                    server_url = (msg.api or data_dict.get('api') or data_dict.get('serverUrl') or "0")
                    lock_region = (msg.region or data_dict.get('region') or decoded_token.get("lock_region"))

                    return {
                        "status": "success",
                        "account_id": str(msg.account_id) if msg.account_id else decoded_token.get("account_id"),
                        "nickname": decoded_token.get('nickname', ''),
                        "token": token_value,
                        "region": lock_region,
                        "server_url": server_url,
                        "access_token": access_token
                    }

            except Exception as e:
                continue
        
        return {"status": "error", "message": "Failed to generate token on all platforms"}