import asyncio
import os
import re
import time
import traceback
from collections import defaultdict
from dotenv import load_dotenv
from pyrogram import Client, filters
from pyrogram.errors import FloodWait
from pyrogram.types import Message

load_dotenv()

API_ID = int(os.getenv("API_ID"))
API_HASH = os.getenv("API_HASH")
BASE_DOWNLOAD_DIR = os.getenv("DOWNLOAD_DIR", "./downloads")

TEST_GROUP_ID = -1001155301071

app = Client("my_account", api_id=API_ID, api_hash=API_HASH)


def sanitize_filename(name: str) -> str:
    clean_name = re.sub(r'[\\/*?:"<>|\n\r]', "_", name).strip()
    return clean_name[:100]


def fa_to_en_digits(text: str) -> str:
    fa_digits = "۰۱۲۳۴۵۶۷۸۹"
    ar_digits = "٠١٢٣٤٥٦٧٨٩"
    en_digits = "0123456789"
    for i in range(10):
        text = text.replace(fa_digits[i], en_digits[i]).replace(ar_digits[i], en_digits[i])
    return text


async def force_find_chat(target_id: int):
    async for dialog in app.get_dialogs():
        if dialog.chat.id == target_id:
            return dialog.chat
    raise ValueError(f"چت با آیدی {target_id} در گفتگوهای اکانت یافت نشد.")


async def resolve_target(target_raw: str):
    target_raw = fa_to_en_digits(target_raw.strip())

    private_link_match = re.search(r"t\.me/c/(\d+)", target_raw)
    if private_link_match:
        raw_id = private_link_match.group(1)
        channel_id = int(f"-100{raw_id}")
        try:
            return await app.get_chat(channel_id)
        except Exception:
            return await force_find_chat(channel_id)

    public_link_match = re.search(r"t\.me/([^/]+)", target_raw)
    if public_link_match:
        username = public_link_match.group(1)
        return await app.get_chat(username)

    try:
        if target_raw.lstrip("-").isdigit():
            val = int(target_raw)
            try:
                return await app.get_chat(val)
            except Exception:
                pass

            if not str(val).startswith("-100"):
                target_id = int(f"-100{val}")
                try:
                    return await app.get_chat(target_id)
                except Exception:
                    return await force_find_chat(target_id)

            return await force_find_chat(val)
        else:
            return await app.get_chat(target_raw)
    except Exception as e:
        raise ValueError(f"امکان شناسایی چت وجود ندارد: {e}")


async def download_from_channel(chat_obj, max_files: int, status_msg: Message):
    print(f"🔄 شروع عملیات دانلود برای: {chat_obj.title} (ID: {chat_obj.id})")

    channel_name = sanitize_filename(chat_obj.title or str(chat_obj.id))
    channel_dir = os.path.join(BASE_DOWNLOAD_DIR, channel_name)
    os.makedirs(channel_dir, exist_ok=True)

    await status_msg.edit_text(f"🔍 در حال بررسی آرشیو «{chat_obj.title}»...")

    try:
        raw_messages = []
        async for msg in app.get_chat_history(chat_obj.id):
            if msg.audio or msg.document or msg.video or msg.voice:
                raw_messages.append(msg)

        raw_messages.reverse()

        # پیدا کردن کپشن مشترک برای آلبوم‌ها (media_group_id)
        media_group_captions = {}
        for msg in raw_messages:
            if msg.media_group_id and msg.caption and msg.caption.strip():
                if msg.media_group_id not in media_group_captions:
                    media_group_captions[msg.media_group_id] = msg.caption.strip()

        # شمارنده برای شماره‌گذاری فایل‌های درون یک گالری
        media_group_counters = defaultdict(int)

        downloaded_count = 0
        already_downloaded_count = 0
        last_update_time = time.time()

        for message in raw_messages:
            if max_files and downloaded_count >= max_files:
                break

            media = message.audio or message.document or message.video or message.voice

            # استخراج پسوند فایل
            file_ext = ""
            if getattr(media, "file_name", None) and "." in media.file_name:
                file_ext = "." + media.file_name.split(".")[-1]
            elif message.audio:
                file_ext = ".mp3"
            elif message.video:
                file_ext = ".mp4"

            # تعیین نام پایه و مدیریت گالری
            caption_to_use = None
            gallery_suffix = ""

            if message.media_group_id:
                media_group_counters[message.media_group_id] += 1
                gallery_suffix = f" _ gallery{media_group_counters[message.media_group_id]}"
                caption_to_use = message.caption or media_group_captions.get(message.media_group_id)

            else:
                caption_to_use = message.caption

            if caption_to_use and caption_to_use.strip():
                base_name = sanitize_filename(caption_to_use)
                file_name = f"{base_name}{gallery_suffix}{file_ext}"
            else:
                raw_name = getattr(media, "file_name", None) or f"file_{message.id}"
                file_name = sanitize_filename(raw_name)
                if not file_name.endswith(file_ext):
                    file_name += file_ext

            file_path = os.path.join(channel_dir, file_name)

            if os.path.exists(file_path):
                already_downloaded_count += 1
                continue

            if time.time() - last_update_time > 4:
                await status_msg.edit_text(
                    f"🚀 در حال دانلود از «{chat_obj.title}»...\n"
                    f"📥 دانلود شده: {downloaded_count} فایل\n"
                    f"📄 فایل جاری: `{file_name}`"
                )
                last_update_time = time.time()

            try:
                print(f"📥 دانلود فایل: {file_name}")
                await app.download_media(message, file_name=file_path)
                downloaded_count += 1
                await asyncio.sleep(4)

            except FloodWait as e:
                await status_msg.edit_text(f"⚠️ محدودیت تلگرام. صبر به مدت {e.value} ثانیه...")
                await asyncio.sleep(e.value)
            except Exception as e:
                print(f"❌ خطا در دریافت فایل {file_name}: {e}")

        if downloaded_count == 0:
            await status_msg.edit_text(
                f"✨ **پایان عملیات برای «{chat_obj.title}»**\n"
                f"هیچ فایل جدیدی یافت نشد (همه {already_downloaded_count} فایل قبلاً موجود بودند)."
            )
        else:
            await status_msg.edit_text(
                f"🎉 **دانلود کانال «{chat_obj.title}» تکمیل شد!**\n\n"
                f"✅ فایل‌های جدید دانلود شده: {downloaded_count}\n"
                f"⏩ فایل‌های از قبل موجود: {already_downloaded_count}\n"
                f"📂 پوشه ذخیره: `{channel_dir}`"
            )
    except Exception as e:
        print(f"💥 خطای غیرمنتظره: {e}")
        traceback.print_exc()
        await status_msg.edit_text(f"❌ خطای غیرمنتظره: {e}")


@app.on_message(filters.chat(TEST_GROUP_ID) & (filters.me | ~filters.me))
async def handle_commands(client: Client, message: Message):
    raw_text = (message.text or message.caption or "").strip()
    text = fa_to_en_digits(raw_text)
    print(f"📩 دستور دریافتی در گروه تست: {text}")

    target_raw = None
    max_files = None

    if text.lower().startswith("dl "):
        parts = text.split()
        if len(parts) >= 2:
            target_raw = parts[1]
            max_files = int(parts[2]) if len(parts) > 2 and parts[2].isdigit() else None
    elif "t.me/" in text:
        target_raw = text.split()[0]

    if target_raw:
        status_msg = await message.reply_text(f"⏳ در حال شناسایی هدف: `{target_raw}`...")
        try:
            chat_obj = await resolve_target(target_raw)
            print(f"✅ هدف پیدا شد: {chat_obj.title} (ID: {chat_obj.id})")
            asyncio.create_task(download_from_channel(chat_obj, max_files, status_msg))
        except Exception as e:
            await status_msg.edit_text(f"❌ خطا در شناسایی کانال/چت:\n`{e}`")


if __name__ == "__main__":
    print("🚀 در حال استارت ربات...")
    app.start()

    print("👀 ربات آماده شنود دستورات است...")
    from pyrogram.sync import idle
    idle()
    app.stop()