# Self.py
from telethon import TelegramClient, errors
import asyncio
import threading
import os
import Selfing   # ← چون اسم فایل تغییر کرده

API_ID = 22522465
API_HASH = "306070eecdd024ce0a64e5dd3ca7f070"

phone_hashes = {}
pending_clients = {}  # کلاینت‌هایی که منتظر رمز دومرحله‌ای هستن
clients = {}

# =========================================================
# 🔑 مهم‌ترین فیکس: یک event loop دائمی برای کل عمر ربات
# چون asyncio.run() هر بار loop رو می‌سازه و بعد از تموم شدن
# تابع، بلافاصله می‌بندش - و این باعث می‌شد تسک‌های پس‌زمینه
# (قابلیت‌های سلف + نگه‌داشتن کلاینت زنده) قبل از اجرا نابود بشن.
# با این loop دائمی، کلاینت‌ها و قابلیت‌هاشون تا وقتی ربات روشنه
# زنده می‌مونن.
# =========================================================
_loop = asyncio.new_event_loop()


def _start_background_loop():
    asyncio.set_event_loop(_loop)
    _loop.run_forever()


_loop_thread = threading.Thread(target=_start_background_loop, daemon=True)
_loop_thread.start()


def _run_coro(coro):
    """یک کوروتین رو روی loop دائمی اجرا می‌کنه و منتظر نتیجه می‌مونه"""
    future = asyncio.run_coroutine_threadsafe(coro, _loop)
    return future.result()


def login(phone, code=None, password=None):
    return _run_coro(_login(phone, code, password))


async def _login(phone, code, password):
    os.makedirs("sessions", exist_ok=True)
    session_path = f"sessions/{phone}"

    if phone in clients:
        try:
            await clients[phone].disconnect()
        except Exception:
            pass
        clients.pop(phone, None)

    # =========================================================
    # مسیر دستی (دکمه فعالسازی) همیشه باید کامل شماره+کد رو طی کنه
    # پس اگه سشن قدیمی از قبل هست (چه معتبر چه نیمه‌کاره)، پاک می‌شه
    # تا لاگین از صفر و تمیز انجام بشه
    # =========================================================
    if code is None and os.path.exists(session_path + ".session"):
        os.remove(session_path + ".session")
        phone_hashes.pop(phone, None)
        print(f"[DEBUG] phone={phone} | old session removed, starting fresh login")

    client = TelegramClient(session_path, API_ID, API_HASH)

    # اتصال اولیه
    try:
        await client.connect()
    except:
        return "CONNECTION_ERROR"

    if not client.is_connected():
        try:
            await client.connect()
        except:
            return "CONNECTION_ERROR"

    # مرحله ارسال کد
    if code is None:
        print(f"[DEBUG] phone={phone} | sending code request now...")
        try:
            sent = await client.send_code_request(phone)
            phone_hashes[phone] = sent.phone_code_hash
            print(f"[DEBUG] phone={phone} | CODE_SENT ok, phone_code_hash={sent.phone_code_hash[:6]}...")
            return "CODE_SENT"
        except errors.AuthRestartError:
            if os.path.exists(session_path + ".session"):
                os.remove(session_path + ".session")
            return "RESTART_AUTH"
        except:
            return "CONNECTION_ERROR"

    # مرحله ورود با کد
    clean_code = code.replace(".", "").replace(" ", "")
    try:
        await client.sign_in(
            phone=phone,
            code=clean_code,
            phone_code_hash=phone_hashes[phone]
        )
    except errors.SessionPasswordNeededError:
        pending_clients[phone] = client
        return "NEED_PASSWORD"
    except errors.PhoneCodeInvalidError:
        return "INVALID_CODE"
    except errors.AuthRestartError:
        if os.path.exists(session_path + ".session"):
            os.remove(session_path + ".session")
        return "RESTART_AUTH"
    except:
        return "CONNECTION_ERROR"

    # مرحله رمز دومرحله‌ای
    if password is not None:
        try:
            await client.sign_in(password=password)
        except errors.PasswordHashInvalidError:
            return "INVALID_PASSWORD"
        except:
            return "CONNECTION_ERROR"

    # =========================================================
    # 🔑 فیکس مشکل ۲ و ۳ (حل مشکل ۲ و ۳):
    # دیگه اینجا await client.run_until_disconnected() صدا زده نمی‌شه
    # چون این خط برای همیشه بلاک می‌مونه و باعث می‌شه:
    #   - تابع login() هیچ‌وقت "OK" برنگردونه (مشکل ۲)
    #   - تردهای محدود ربات (پیش‌فرض ۲ تا) قفل بشن و باعث رفتار
    #     غیرقابل‌پیش‌بینی برای کاربرهای دیگه بشه (مشکل ۳)
    # به‌جاش زنده‌نگه‌داشتن کلاینت به یک تسک جدا در پس‌زمینه سپرده می‌شه
    # =========================================================
    clients[phone] = client
    asyncio.create_task(Selfing.start_selfbot(client, phone))
    asyncio.create_task(_keep_alive(client, phone))

    return "OK"


async def _keep_alive(client, phone):
    """کلاینت رو در پس‌زمینه زنده نگه می‌داره بدون بلاک کردن تابع login"""
    try:
        await client.run_until_disconnected()
    except Exception as e:
        print(f"Client {phone} disconnected: {e}")
    finally:
        clients.pop(phone, None)


# =========================================================
#   بازیابی خودکار سشن‌های قبلی (فقط موقع روشن شدن ربات)
#   این تابع هیچ‌وقت کد جدید نمی‌فرسته، فقط اگه سشن معتبر
#   از قبل موجود باشه بی‌صدا وصلش می‌کنه
# =========================================================
def login_2fa(phone, password):
    return _run_coro(_login_2fa(phone, password))

async def _login_2fa(phone, password):
    client = pending_clients.get(phone) or clients.get(phone)
    if client is None:
        return "CONNECTION_ERROR"
    try:
        await client.sign_in(password=password)
    except errors.PasswordHashInvalidError:
        return "INVALID_PASSWORD"
    except:
        return "CONNECTION_ERROR"
    pending_clients.pop(phone, None)
    clients[phone] = client
    asyncio.create_task(Selfing.start_selfbot(client, phone))
    asyncio.create_task(_keep_alive(client, phone))
    return "OK"

def restore_session(phone):
    return _run_coro(_restore_session(phone))


async def _restore_session(phone):
    session_path = f"sessions/{phone}"

    if phone in clients:
        return "OK_SESSION"

    if not os.path.exists(session_path + ".session"):
        return "NO_SESSION"

    client = TelegramClient(session_path, API_ID, API_HASH)

    try:
        await client.connect()
    except:
        return "CONNECTION_ERROR"

    try:
        if await client.is_user_authorized():
            clients[phone] = client
            asyncio.create_task(Selfing.start_selfbot(client, phone))
            asyncio.create_task(_keep_alive(client, phone))
            return "OK_SESSION"
        else:
            await client.disconnect()
            return "NOT_AUTHORIZED"
    except Exception as e:
        print(f"[DEBUG] restore_session error for {phone}: {e}")
        try:
            await client.disconnect()
        except:
            pass
        return "ERROR"


# ===========================
#     خاموش کردن سلف‌بات
# ===========================
def stop(phone):
    if phone in clients:
        try:
            future = asyncio.run_coroutine_threadsafe(clients[phone].disconnect(), _loop)
            future.result(timeout=10)
            print(f"SELF BOT STOPPED ON {phone}")
        except Exception as e:
            print(f"STOP ERROR for {phone}: {e}")