# remottxrea/client/create_client.py

import os
import asyncio
from typing import Dict

from pyrogram import Client
from pyrogram.errors import SessionPasswordNeeded

from ..config.main_config import SESSIONS_DIR
from ..client.device_profile import get_random_device
from ..session.session_data_manager import session_data_manager
from ..config.apis import get_apis


# ==========================================================
# GLOBAL SAFE CLIENT POOL (NO WATCHER / NO SQLITE LOCK)
# ==========================================================

class _ClientPool:
    """
    Production-grade client pool
    - race safe
    - auto reconnect
    - no watcher
    """

    def __init__(self):
        self.clients: Dict[str, Client] = {}
        self._lock = asyncio.Lock()
        self._running = False
        self._reconnect_task = None

    # ---------------- LOCK ----------------

    async def acquire(self):
        await self._lock.acquire()

    def release(self):
        if self._lock.locked():
            self._lock.release()

    def is_locked(self):
        return self._lock.locked()

    # ---------------- REGISTER ----------------

    async def register(self, phone: str, client: Client):

        async with self._lock:

            if phone in self.clients:
                return

            if not client.is_connected:
                await client.start()

            self.clients[phone] = client

    # ---------------- AUTO RECONNECT LOOP ----------------

    async def _reconnect_loop(self):

        while self._running:

            await asyncio.sleep(15)

            async with self._lock:
                for phone, client in list(self.clients.items()):
                    try:
                        if not client.is_connected:
                            await client.start()
                    except Exception:
                        # اگر fail شد حذف نمی‌کنیم
                        # فقط اجازه میدیم سیکل بعدی دوباره تلاش کند
                        pass

    async def start(self):

        if self._running:
            return

        self._running = True
        self._reconnect_task = asyncio.create_task(
            self._reconnect_loop()
        )

    async def stop(self):

        self._running = False

        if self._reconnect_task:
            self._reconnect_task.cancel()

        async with self._lock:
            for client in self.clients.values():
                try:
                    await client.stop()
                except Exception:
                    pass

            self.clients.clear()


# Singleton
client_pool = _ClientPool()


# ==========================================================
# SESSION CREATOR
# ==========================================================

class SessionCreator:

    def __init__(self):
        self.pending = {}  # phone -> {app, phone_code_hash}

    # ======================================================
    # BUILD CLIENT (SAFE)
    # ======================================================

    def build_client(self, phone: str, string_session: str | None = None):

        saved_data = session_data_manager.load(phone)

        if saved_data:
            device = saved_data["device"]
        else:
            device = get_random_device()

        api_id, api_hash = get_apis()

        if string_session:
            session_name = string_session
            in_memory = True
        else:
            session_name = os.path.join(SESSIONS_DIR, phone)
            in_memory = False

        return Client(
            name=session_name,
            api_id=api_id,
            api_hash=api_hash,
            device_model=device["device_model"],
            system_version=device["system_version"],
            app_version=device["app_version"],
            lang_code=device["lang_code"],
            in_memory=in_memory,
            workdir=SESSIONS_DIR,
            workers=1  # جلوگیری از race داخلی Pyrogram
        )

    # ======================================================
    # SEND CODE
    # ======================================================

    async def send_code(self, phone: str):

        app = self.build_client(phone)

        await app.connect()

        sent_code = await app.send_code(phone)

        self.pending[phone] = {
            "app": app,
            "phone_code_hash": sent_code.phone_code_hash
        }

        return True

    # ======================================================
    # LOGIN WITH CODE
    # ======================================================

    async def login_with_code(self, phone: str, code: str):

        data = self.pending.get(phone)
        if not data:
            return False

        app: Client = data["app"]

        try:
            await app.sign_in(
                phone,
                data["phone_code_hash"],
                code
            )

        except SessionPasswordNeeded:
            return "2FA"

        # ✅ ثبت مستقیم session بعد از لاگین
        await self._finalize_login(phone, app, password=None)

        return True

    # ======================================================
    # LOGIN WITH PASSWORD
    # ======================================================

    async def login_with_password(self, phone: str, password: str):

        data = self.pending.get(phone)
        if not data:
            return False

        app: Client = data["app"]

        await app.check_password(password)

        # ✅ ثبت مستقیم session بعد از لاگین
        await self._finalize_login(phone, app, password=password)

        return True

    # ======================================================
    # FINALIZE LOGIN (CORE LOGIC)
    # ======================================================

    async def _finalize_login(self, phone: str, app: Client, password):

        me = await app.get_me()
        session_string = await app.export_session_string()

        api_id, api_hash = get_apis()

        data = {
            "phone": phone,
            "user_id": me.id,
            "username": me.username,
            "session_string": session_string,
            "device": {
                "api_id": api_id,
                "api_hash": api_hash,
                "device_model": app.device_model,
                "system_version": app.system_version,
                "app_version": app.app_version,
                "lang_code": app.lang_code
            },
            "2fa_password": password
        }

        # ذخیره JSON
        session_data_manager.save(phone, data)

        # ثبت مستقیم داخل pool
        await client_pool.register(phone, app)

        # پاک کردن pending
        if phone in self.pending:
            del self.pending[phone]

        # استارت reconnect loop اگر قبلاً شروع نشده
        await client_pool.start()