"""
==========================================================
BlackAuth Python 3.x Client SDK - Enterprise Hardened
Integrated Anti-Cracking, Anti-Debugging & Process Watchdog
Supports Windows, Linux, macOS with automatic HWID generation
==========================================================
"""

import json
import urllib.request
import urllib.error
import hashlib
import platform
import subprocess
import os
import sys

class BlackAuth:
    def __init__(self, name: str, ownerid: str, secret: str, version: str = "1.0", url: str = "https://blackauth.online/api/v1"):
        self.name = name
        self.ownerid = ownerid
        self.secret = secret
        self.version = version
        self.url = url.rstrip('/')
        self.sessionid = None
        self.enckey = None
        self.response = {"success": False, "message": ""}
        self.user_data = {}
        self.hwid = self._get_hwid()

    # ======================================================
    # Anti-Cracking & Threat Defense Subsystem
    # ======================================================

    def check_security(self, auto_terminate: bool = True) -> bool:
        """Detects debuggers, reverse engineering tools, and memory sniffers"""
        threat = ""

        # 1. Native Windows Debugger Detection
        if platform.system() == "Windows":
            try:
                import ctypes
                if ctypes.windll.kernel32.IsDebuggerPresent():
                    threat = "Active debugger detected (IsDebuggerPresent)"
                
                if not threat:
                    is_remote = ctypes.c_bool(False)
                    ctypes.windll.kernel32.CheckRemoteDebuggerPresent(
                        ctypes.windll.kernel32.GetCurrentProcess(),
                        ctypes.byref(is_remote)
                    )
                    if is_remote.value:
                        threat = "Remote debugger attached (CheckRemoteDebuggerPresent)"
            except Exception:
                pass

        # 2. Cracking & Reverse Engineering Tool Watchdog (Zero-subprocess in-memory check)
        if not threat and platform.system() == "Windows":
            blacklist = [
                "x64dbg", "x32dbg", "ida", "ida64", "ollydbg",
                "http debugger", "fiddler", "wireshark",
                "cheat engine", "process hacker", "ksdumper", "scylla", "dnspy"
            ]
            try:
                import ctypes
                user32 = ctypes.windll.user32
                found_title = []
                def enum_callback(hwnd, extra):
                    length = user32.GetWindowTextLengthW(hwnd)
                    if length > 0:
                        buff = ctypes.create_unicode_buffer(length + 1)
                        user32.GetWindowTextW(hwnd, buff, length + 1)
                        title_lower = buff.value.lower()
                        for bad in blacklist:
                            if bad in title_lower:
                                found_title.append(buff.value)
                                return False
                    return True

                WNDENUMPROC = ctypes.WINFUNCTYPE(ctypes.c_bool, ctypes.c_void_p, ctypes.c_void_p)
                user32.EnumWindows(WNDENUMPROC(enum_callback), 0)
                if found_title:
                    threat = f"Cracking tool window active: {found_title[0]}"
            except Exception:
                pass

        if threat:
            if auto_terminate:
                self.panic(threat)
            return False

        return True

    def panic(self, threat: str):
        """Notifies BlackAuth server to auto-blacklist the intruder and terminates process immediately"""
        try:
            if self.sessionid:
                self._post("/log", {
                    "sessionid": self.sessionid,
                    "message": f"[SECURITY ALERT] Tamper attempt: {threat}",
                    "hwid": self.hwid
                })
        except Exception:
            pass

        # Unrecoverable exit without cleanup to prevent debug tracing
        os._exit(1)

    # ======================================================
    # Authentication & Core Operations
    # ======================================================

    def init(self) -> bool:
        """Initialize session handshake with BlackAuth server"""
        self.check_security(True)

        payload = {
            "name": self.name,
            "ownerid": self.ownerid,
            "secret": self.secret,
            "version": self.version,
            "hwid": self.hwid
        }
        res = self._post("/init", payload)
        self.response = res
        if res.get("success"):
            self.sessionid = res.get("sessionid")
            self.enckey = res.get("enckey")
            return True
        return False

    def license(self, key: str) -> bool:
        """Authenticate using license key only"""
        self.check_security(True)

        if not self.sessionid:
            self.response = {"success": False, "message": "Call init() first"}
            return False

        payload = {
            "sessionid": self.sessionid,
            "key": key,
            "hwid": self.hwid
        }
        res = self._post("/license", payload)
        self.response = res
        if res.get("success"):
            self.user_data = res
            return True
        return False

    def login(self, username: str, password: str) -> bool:
        """Login with username & password"""
        self.check_security(True)

        if not self.sessionid:
            self.response = {"success": False, "message": "Call init() first"}
            return False

        payload = {
            "sessionid": self.sessionid,
            "username": username,
            "password": password,
            "hwid": self.hwid
        }
        res = self._post("/login", payload)
        self.response = res
        if res.get("success"):
            self.user_data = res
            return True
        return False

    def register(self, username: str, password: str, key: str) -> bool:
        """Register a new user with a license key"""
        self.check_security(True)

        if not self.sessionid:
            self.response = {"success": False, "message": "Call init() first"}
            return False

        payload = {
            "sessionid": self.sessionid,
            "username": username,
            "password": password,
            "key": key,
            "hwid": self.hwid
        }
        res = self._post("/register", payload)
        self.response = res
        if res.get("success"):
            self.user_data = res
            return True
        return False

    def check(self) -> bool:
        """Session keep-alive heartbeat check"""
        self.check_security(True)

        if not self.sessionid:
            return False

        payload = {"sessionid": self.sessionid}
        res = self._post("/check", payload)
        self.response = res
        return bool(res.get("success"))

    def var(self, varid: str) -> str:
        """Retrieve a secure Cloud Variable from memory"""
        self.check_security(True)

        if not self.sessionid:
            return ""

        payload = {
            "sessionid": self.sessionid,
            "varid": varid
        }
        res = self._post("/var", payload)
        self.response = res
        if res.get("success"):
            return res.get("response", "")
        return ""

    def file(self, fileid: str) -> bytes:
        """Download protected executable memory payload"""
        self.check_security(True)

        if not self.sessionid:
            return b""

        payload = {
            "sessionid": self.sessionid,
            "fileid": fileid
        }
        res = self._post("/file", payload)
        if isinstance(res, dict) and res.get("success"):
            import base64
            contents = res.get("contents", "")
            try:
                return base64.b64decode(contents)
            except Exception:
                return contents.encode("utf-8")
        elif isinstance(res, bytes):
            return res
        return b""

    def log(self, message: str):
        """Telemetry logger"""
        if not self.sessionid:
            return
        self._post("/log", {
            "sessionid": self.sessionid,
            "message": message,
            "hwid": self.hwid
        })

    def _get_hwid(self) -> str:
        try:
            if platform.system() == "Windows":
                try:
                    import winreg
                    with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r"SOFTWARE\Microsoft\Cryptography") as key:
                        guid, _ = winreg.QueryValueEx(key, "MachineGuid")
                        if guid:
                            return str(guid).strip()
                except Exception:
                    pass
            elif platform.system() == "Linux":
                if os.path.exists("/etc/machine-id"):
                    with open("/etc/machine-id", "r") as f:
                        return f.read().strip()
        except Exception:
            pass
        return hashlib.sha256((platform.node() + platform.processor()).encode()).hexdigest()

    def _post(self, endpoint: str, data: dict) -> dict:
        full_url = self.url + endpoint
        json_data = json.dumps(data).encode("utf-8")
        req = urllib.request.Request(
            full_url,
            data=json_data,
            headers={
                "Content-Type": "application/json",
                "User-Agent": "BlackAuthPythonClient/2.4"
            },
            method="POST"
        )
        try:
            with urllib.request.urlopen(req, timeout=10) as resp:
                return json.loads(resp.read().decode("utf-8"))
        except urllib.error.HTTPError as e:
            try:
                return json.loads(e.read().decode("utf-8"))
            except Exception:
                return {"success": False, "message": f"HTTP Error {e.code}"}
        except Exception as e:
            return {"success": False, "message": f"Connection error: {str(e)}"}
