# discor_lora_b/client.py

import asyncio
import aiohttp
import json

class Client:
    """
    العميل الرئيسي للاتصال بواجهة برمجة تطبيقات (API) ديسكورد والـ Gateway.
    """
    def __init__(self, token: str):
        self.token = token
        self.loop = asyncio.get_event_loop()
        self.http_session = aiohttp.ClientSession()
        self.websocket = None
        self.listeners = {}
        self.commands = {}
        self.heartbeat_interval = None
        self.seq = None
        
    async def start(self):
        """
        يبدأ الاتصال بالـ API والـ Gateway.
        """
        print("Starting client...")
        try:
            await self._connect_to_gateway()
        except aiohttp.ClientError as e:
            print(f"فشل الاتصال: {e}")
        except Exception as e:
            print(f"حدث خطأ غير متوقع: {e}")

    def on_event(self, event_name: str):
        """
        ديكوريتور لتسجيل دوال الأحداث.
        """
        def decorator(func):
            if event_name not in self.listeners:
                self.listeners[event_name] = []
            self.listeners[event_name].append(func)
            return func
        return decorator

    def command(self, name: str = None):
        """
        ديكوريتور لتسجيل الأوامر.
        """
        def decorator(func):
            cmd_name = name or func.__name__
            self.commands[cmd_name] = func
            return func
        return decorator

    async def _connect_to_gateway(self):
        """
        ينشئ اتصال WebSocket ويقوم بمعالجة الاتصالات الأولية.
        """
        gateway_url = "wss://gateway.discord.gg/?v=10&encoding=json"
        
        async with self.http_session.ws_connect(gateway_url) as ws:
            self.websocket = ws
            await self._identify()
            await self._listen_for_messages()
            
    async def _identify(self):
        """
        يرسل رسالة IDENTIFY للـ Gateway للتعريف بالبوت.
        """
        payload = {
            "op": 2,
            "d": {
                "token": self.token,
                "intents": 513,
                "properties": {
                    "$os": "linux",
                    "$browser": "discor-lora-b",
                    "$device": "discor-lora-b"
                }
            }
        }
        await self.websocket.send_json(payload)

    async def _listen_for_messages(self):
        """
        حلقة رئيسية تستقبل وتعالج الرسائل من الـ Gateway.
        """
        async for msg in self.websocket:
            if msg.type == aiohttp.WSMsgType.TEXT:
                data = json.loads(msg.data)
                op = data.get("op")
                s = data.get("s")
                t = data.get("t")
                d = data.get("d")
                
                if s is not None:
                    self.seq = s
                    
                if op == 10:  # HELLO
                    self.heartbeat_interval = d.get("heartbeat_interval") / 1000
                    asyncio.create_task(self._send_heartbeats())
                elif op == 0:  # DISPATCH
                    await self._dispatch_event(t, d)
                elif op == 1:  # HEARTBEAT_ACK
                    pass
            elif msg.type == aiohttp.WSMsgType.CLOSED:
                print("تم إغلاق الاتصال.")
                break
                
    async def _dispatch_event(self, event_name: str, data: dict):
        """
        يستدعي الدوال المسجلة لحدث معين أو يعالج الأوامر.
        """
        if event_name == "MESSAGE_CREATE":
            await self._process_commands(data)
        
        if event_name in self.listeners:
            for func in self.listeners[event_name]:
                asyncio.create_task(func(data))

    async def _process_commands(self, data: dict):
        """
        يعالج الأوامر الواردة من الرسائل.
        """
        content = data.get("content", "")
        author_id = data["author"]["id"]
        
        # تجاهل رسائل البوت نفسه
        if author_id == (await self._get_self_id()):
            return
            
        if content.startswith("!"):
            parts = content.split(" ")
            command_name = parts[0][1:]
            args = parts[1:]
            
            if command_name in self.commands:
                func = self.commands[command_name]
                await func(data, *args)
                
    async def _send_heartbeats(self):
        """
        يرسل نبضات قلب دورية للحفاظ على الاتصال.
        """
        while True:
            await asyncio.sleep(self.heartbeat_interval)
            payload = {
                "op": 1,
                "d": self.seq
            }
            await self.websocket.send_json(payload)
            
    async def send_message(self, channel_id: int, content: str):
        """
        يرسل رسالة إلى قناة معينة باستخدام HTTP.
        """
        url = f"https://discord.com/api/v10/channels/{channel_id}/messages"
        headers = {"Authorization": f"Bot {self.token}", "Content-Type": "application/json"}
        payload = {"content": content}
        
        try:
            async with self.http_session.post(url, headers=headers, json=payload) as resp:
                resp.raise_for_status()
                print(f"تم إرسال الرسالة بنجاح إلى القناة {channel_id}")
        except aiohttp.ClientResponseError as e:
            print(f"خطأ HTTP عند إرسال الرسالة: {e.status} - {e.message}")
        except Exception as e:
            print(f"حدث خطأ أثناء إرسال الرسالة: {e}")

    async def _get_self_id(self):
        """
        يحصل على مُعرّف (ID) البوت الحالي.
        """
        if hasattr(self, '_self_id'):
            return self._self_id

        url = "https://discord.com/api/v10/users/@me"
        headers = {"Authorization": f"Bot {self.token}"}
        
        async with self.http_session.get(url, headers=headers) as resp:
            resp.raise_for_status()
            data = await resp.json()
            self._self_id = data.get("id")
            return self._self_id