import os
import asyncio 
from typing import Dict

from pyrogram import Client
from pyrogram.errors import FloodWait, RPCError
from watchfiles import awatch

from config.main_config import (
    SESSIONS_DIR
)

from session.session_data_manager import (
    session_data_manager
)

from core.delay_engine import delay_engine
from core.execution_tracker import ExecutionTracker


class MultiSessionRunner:

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

    # ==================================================
    # INITIAL LOAD
    # ==================================================

    async def load_all(self):
        async with self._lock:
            await self._sync_with_disk()

    # ==================================================
    # SYNC CORE
    # ==================================================

    async def _sync_with_disk(self):

        disk_phones = set()

        for file in os.listdir(SESSIONS_DIR):
            if file.endswith("_data.json"):
                phone = file.replace("_data.json", "")
                disk_phones.add(phone)

        current_phones = set(self.clients.keys())

        # ---- NEW SESSIONS ----
        for phone in disk_phones - current_phones:
            self.clients[phone] = self._create_client(phone)
            print(f"[INOTIFY] Added → {phone}")

        # ---- REMOVED SESSIONS ----
        for phone in current_phones - disk_phones:
            client = self.clients.pop(phone)
            try:
                await client.stop()
            except:
                pass
            print(f"[INOTIFY] Removed → {phone}")

    # ==================================================
    # CLIENT FACTORY
    # ==================================================

    def _create_client(self, phone):

        data = session_data_manager.load(phone)
        device = data["device"]

        return Client(
            name=os.path.join(SESSIONS_DIR, phone),
            api_id=device["api_id"],
            api_hash=device["api_hash"],
            device_model=device["device_model"],
            system_version=device["system_version"],
            app_version=device["app_version"],
            lang_code=device["lang_code"]
        )

    # ==================================================
    # REALTIME WATCHER (inotify)
    # ==================================================

    async def start_watcher(self):

        if self._watch_task:
            return

        async def watcher():
            async for changes in awatch(SESSIONS_DIR):
                async with self._lock:
                    await self._sync_with_disk()

        self._watch_task = asyncio.create_task(watcher())
        print("🔥 inotify watcher started")

    # ==================================================
    # RUN ACTION
    # ==================================================

    async def run_action(
        self,
        action_func,
        progress_message=None
    ):

        async with self._lock:

            tracker = ExecutionTracker()
            total = len(self.clients)
            tracker.start(total)

            for index, (phone, app) in enumerate(
                self.clients.items(),
                start=1
            ):

                try:

                    status = f"[{index}/{total}] {phone} → Running"
                    print(status)

                    if progress_message:
                        await progress_message.edit_text(status)

                    await app.start()
                    await action_func(phone, app)
                    await app.stop()

                    tracker.record(phone, "success")
                    status = f"[{index}/{total}] {phone} → Success"

                except FloodWait as e:
                    tracker.record(phone, "flood", e)
                    status = f"[{index}/{total}] {phone} → Flood"

                except RPCError as e:
                    tracker.record(phone, "rpc", e)
                    status = f"[{index}/{total}] {phone} → RPC"

                except Exception as e:
                    tracker.record(phone, "failed", e)
                    status = f"[{index}/{total}] {phone} → Failed"

                print(status)

                if progress_message:
                    await progress_message.edit_text(status)

                await delay_engine.wait()

            report = tracker.summary_text()

            if progress_message:
                await progress_message.edit_text(report)

            return tracker