import asyncio
import hashlib
import json
import os
import re
from collections import deque
from telethon import TelegramClient, events

# مشخصات اتصال تلگرام
api_id = 2040
api_hash = 'b18441a1ff607e10a989891a5462e627'

CONFIG_FILE = 'config.json'

default_config = {
    "sources": ["KH_B2", "NE_WG", "News1Fori", "khbar1fori"],
    "targets": ["DorooghSetiz"],
    "my_id": "@DorooghSetiz",
    "is_active": True,
    "bad_words": [
        "فارکس", "ترید", "لایت فایننس", "litefinance", "ثبت‌نام کن", "ثبت نام کن",
        "کسب درآمد", "صرافی", "ارز دیجیتال", "سیگنال", "تخفیف ویژه",
        "خرید آنلاین", "پشتیبانی تبلیغات", "رزرو تبلیغ", "تبلیغات:", "وب‌سایت:", "وبسایت:"
    ]
}

def load_config():
    if not os.path.exists(CONFIG_FILE):
        with open(CONFIG_FILE, 'w', encoding='utf-8') as f:
            json.dump(default_config, f, ensure_ascii=False, indent=4)
        return default_config
    try:
        with open(CONFIG_FILE, 'r', encoding='utf-8') as f:
            cfg = json.load(f)
            if "targets" not in cfg:
                cfg["targets"] = [cfg.get("target", "DorooghSetiz")]
            if "bad_words" not in cfg:
                cfg["bad_words"] = default_config["bad_words"]
            return cfg
    except Exception:
        return default_config

def save_config(cfg):
    with open(CONFIG_FILE, 'w', encoding='utf-8') as f:
        json.dump(cfg, f, ensure_ascii=False, indent=4)

config = load_config()

client = TelegramClient(
    'forwarder_session',
    api_id=api_id,
    api_hash=api_hash,
    connection_retries=None,
    auto_reconnect=True,
    retry_delay=2
)

grouped_messages = {}

# حافظه چرخشی تاریخچه پست‌ها
SEEN_POSTS_CACHE = deque(maxlen=1000)

def extract_keywords(text):
    """استخراج کلمات کلیدی خبر برای بررسی تشابه متنی"""
    if not text:
        return set()
    text = re.sub(r'(@[a-zA-Z0-9_]+|https?://[^\s]+)', '', text)
    words = re.findall(r'[\w]{3,}', text.lower())
    stop_words = {'است', 'برای', 'این', 'شدند', 'خواهد', 'بود', 'گفت', 'کرد', 'شوند', 'های', 'شده', 'دارد', 'نخواهد'}
    return set(w for w in words if w not in stop_words)

def get_media_fingerprint(msg):
    """تولید شناسه اثرانگشت پایدار از روی مدیا (ویدیو، عکس، صوت)"""
    if not msg.media:
        return None

    # ۱. بررسی ویدیو یا فایل گیف
    if hasattr(msg.media, 'document') and msg.media.document:
        doc = msg.media.document
        duration = 0
        w, h = 0, 0
        for attr in getattr(doc, 'attributes', []):
            if hasattr(attr, 'duration'):
                duration = attr.duration
            if hasattr(attr, 'w') and hasattr(attr, 'h'):
                w, h = attr.w, attr.h

        # حجم بر حسب ۰.۱ مگابایت (برای خنثی‌سازی نوسانات جزئی چند بایتی)
        size_mb_approx = round(doc.size / (1024 * 1024), 1)

        # اگر ویدیو دارای طول زمانی باشد
        if duration > 0:
            return f"vid_{duration}s_{w}x{h}_{size_mb_approx}mb"
        
        # سایر فایل‌ها بر اساس حجم تقریبی
        return f"doc_{size_mb_approx}mb_{w}x{h}"

    # ۲. بررسی عکس
    if hasattr(msg.media, 'photo') and msg.media.photo:
        photo = msg.media.photo
        # در تلگرام عکس‌ها سایزهای مختلف دارند، بزرگترین سایز را چک می‌کنیم
        return f"photo_{getattr(photo, 'id', '')}"

    return None

def is_duplicate(msg):
    """بررسی جامع و پایدار تکراری بودن مدیا یا متن"""
    # گام اول: بررسی اثرانگشت مدیا (ویدیو با ثانیه و مشخصات یکسان)
    media_fp = get_media_fingerprint(msg)
    if media_fp:
        if media_fp in SEEN_POSTS_CACHE:
            return True, f"ویدیوی مشابه ({media_fp})"
        SEEN_POSTS_CACHE.append(media_fp)

    # گام دوم: بررسی تشابه متن (حتی اگر ترجمه کمی فرق کرده باشد)
    current_keywords = extract_keywords(msg.raw_text or "")
    # اگر کلمات کلیدی مهم وجود داشت (مثلاً نام اشخاص مثل 'تد کروز' یا موضوعات خاص)
    if len(current_keywords) >= 4:
        for item in list(SEEN_POSTS_CACHE):
            if isinstance(item, set) and len(item) >= 4:
                intersection = current_keywords.intersection(item)
                # ضریب اشتراک ساده
                min_len = min(len(current_keywords), len(item))
                if min_len > 0 and (len(intersection) / min_len) >= 0.45:
                    return True, "تشابه بالای کلمات کلیدی خبر"

        SEEN_POSTS_CACHE.append(current_keywords)

    return False, ""

def is_advertisement(msg):
    """شناسایی دکمه‌های شیشه‌ای، لینک‌های خارجی و کلمات تبلیغاتی"""
    if getattr(msg, 'reply_markup', None) is not None:
        return True, "داشتن دکمه شیشه‌ای"

    text = msg.raw_text or ""
    text_lower = text.lower()
    if not text_lower:
        return False, ""

    if re.search(r'https?://[^\s]+(?:\?|&)(?:uid|cid|ref|aff|invite|bonus|utm_)[=a-zA-Z0-9_]+', text, re.IGNORECASE):
        return True, "لینک معرف/ریفرال خارجی"

    external_links = re.findall(r'https?://(?:www\.)?([a-zA-Z0-9.-]+\.[a-zA-Z]{2,})[^\s]*', text)
    for domain in external_links:
        if not domain.endswith(('t.me', 'telegram.me', 'telegram.org')):
            return True, f"لینک سایت خارجی ({domain})"

    for word in config.get("bad_words", []):
        if word.lower() in text_lower:
            return True, f"کلمه ممنوعه '{word}'"

    return False, ""

def clean_text_simple(raw_text, custom_id):
    """پاک‌سازی آیدی‌های منبع و درج برچسب اختصاصی"""
    if not raw_text:
        return f"🏷 {custom_id}" if custom_id else ""

    lines = raw_text.split('\n')

    while lines:
        last = lines[-1].strip()
        if not last or re.search(r'(@[a-zA-Z0-9_]+|t\.me/[a-zA-Z0-9_+/]+)', last):
            lines.pop()
        else:
            break

    cleaned_text = "\n".join(lines).rstrip()
    if custom_id:
        return f"{cleaned_text}\n\n🏷 {custom_id}"
    return cleaned_text

async def send_post_to_target(target, media, raw_text, custom_id):
    final_text = clean_text_simple(raw_text, custom_id)
    try:
        if not media:
            await client.send_message(target, message=final_text)
            return

        if len(final_text) > 1024:
            await client.send_file(target, file=media)
            await client.send_message(target, message=final_text)
        else:
            await client.send_file(target, file=media, caption=final_text)
    except Exception as e:
        print(f"❌ خطا در ارسال به @{target}: {e}")

async def main():
    await client.start()
    me = await client.get_me()
    print("=" * 60)
    print(f"✅ ربات متصل شد: {me.first_name} (@{me.username})")
    print("🎯 الگوریتم فیلتر ویدیوی تکراری (ثانیه + ابعاد + حجم) فعال شد.")
    print("=" * 60)

    # ------------------ پنل مدیریت در Saved Messages ------------------
    @client.on(events.NewMessage(chats='me'))
    async def admin_handler(event):
        text = event.raw_text.strip()

        if text in ['اینجا', 'ثبت', 'افزودن'] and event.is_reply:
            reply_msg = await event.get_reply_message()
            if reply_msg and reply_msg.fwd_from:
                from_id = reply_msg.fwd_from.from_id
                try:
                    chat = await client.get_entity(from_id)
                    chat_id_str = str(chat.id)
                    uname = getattr(chat, 'username', None)

                    if chat_id_str not in config["sources"]:
                        config["sources"].append(chat_id_str)
                    if uname and uname.lower() not in [s.lower() for s in config["sources"]]:
                        config["sources"].append(uname)

                    save_config(config)
                    await event.reply(f"🎯 کانال ثبت شد:\n**{chat.title}** (`@{uname}`)")
                except Exception as e:
                    await event.reply(f"❌ خطا: {e}")
            return

        if text.lower() in ['پینگ', 'ping']:
            await event.reply('پونگ 🏓 ربات کاملاً فعال است.')
            return

        if text == 'پاکسازی حافظه':
            SEEN_POSTS_CACHE.clear()
            await event.reply("🧹 کش تکرارها خالی شد.")
            return

        if text in ['/admin', 'وضعیت']:
            status = "🟢 روشن" if config.get("is_active", True) else "🔴 خاموش"
            targets = config.get("targets", [])
            targets_list = "\n".join([f"• `@{t}`" for t in targets]) if targets else "❌ بدون مقصد"
            sources_list = "\n".join([f"• `{s}`" for s in config.get("sources", [])]) or "هیچ"
            
            msg = (
                f"⚙️ **وضعیت ربات فورواردر**\n\n"
                f"وضعیت: {status}\n"
                f"تعداد رکوردهای فعال ضد تکرار: {len(SEEN_POSTS_CACHE)}\n"
                f"امضای انتهای متن: `{config.get('my_id')}`\n\n"
                f"🎯 **کانال‌های مقصد:**\n{targets_list}\n\n"
                f"📋 **کانال‌های مبدا:**\n{sources_list}"
            )
            await event.reply(msg)
            return

        if text.startswith('مقصد '):
            new_target = text.replace('مقصد ', '').replace('@', '').strip()
            targets = config.get("targets", [])
            if new_target.lower() not in [t.lower() for t in targets]:
                targets.append(new_target)
                config["targets"] = targets
                save_config(config)
                await event.reply(f"🎯 مقصد `@{new_target}` اضافه شد.")
            return

        if text.startswith('حذف مقصد '):
            target_to_remove = text.replace('حذف مقصد ', '').replace('@', '').strip()
            targets = config.get("targets", [])
            matched = [t for t in targets if t.lower() == target_to_remove.lower()]
            if matched:
                for m in matched:
                    targets.remove(m)
                config["targets"] = targets
                save_config(config)
                await event.reply(f"🗑 مقصد `@{target_to_remove}` حذف شد.")
            return

        if text.startswith('امضا '):
            sign = text.replace('امضا ', '').strip()
            config["my_id"] = sign
            save_config(config)
            await event.reply(f"✍️ امضا تنظیم شد:\n`{sign}`")
            return

        if text.startswith('افزودن '):
            ch = text.replace('افزودن ', '').replace('@', '').strip()
            if ch not in config["sources"]:
                config["sources"].append(ch)
                save_config(config)
                await event.reply(f"✅ مبدا `@{ch}` اضافه شد.")
            return

        if text.startswith('حذف '):
            ch = text.replace('حذف ', '').replace('@', '').strip()
            if ch in config["sources"]:
                config["sources"].remove(ch)
                save_config(config)
                await event.reply(f"🗑 مبدا `@{ch}` حذف شد.")
            return

        if text == 'خاموش':
            config["is_active"] = False
            save_config(config)
            await event.reply("🔴 فوروارد متوقف شد.")
            return

        if text == 'روشن':
            config["is_active"] = True
            save_config(config)
            await event.reply("🟢 فوروارد فعال شد.")
            return

    # ------------------ دریافت و فوروارد پست‌ها ------------------
    @client.on(events.NewMessage)
    async def forwarder(event):
        if not config.get("is_active", True):
            return

        targets = config.get("targets", [])
        if not targets:
            return

        chat = await event.get_chat()
        username = getattr(chat, 'username', '') or ''
        chat_id_str = str(getattr(chat, 'id', ''))
        peer_id_str = str(event.chat_id).replace('-100', '')

        sources = [s.lower().replace('@', '') for s in config.get("sources", [])]

        is_matched = False
        if username and username.lower() in sources:
            is_matched = True
        elif chat_id_str in sources or peer_id_str in sources or str(event.chat_id) in sources:
            is_matched = True

        if not is_matched:
            return

        msg = event.message

        # ۱. فیلتر تبلیغات
        is_ad, ad_reason = is_advertisement(msg)
        if is_ad:
            print(f"🚫 پست تبلیغاتی از @{username} رد شد: {ad_reason}")
            return

        # ۲. فیلتر دقیق پست تکراری
        dup, dup_reason = is_duplicate(msg)
        if dup:
            print(f"⚠️ پست تکراری از @{username} متوقف شد! (دلیل: {dup_reason})")
            return

        custom_id = config.get("my_id", "")

        try:
            # مدیریت آلبوم‌ها
            if msg.grouped_id:
                if msg.grouped_id not in grouped_messages:
                    grouped_messages[msg.grouped_id] = [msg]
                    await asyncio.sleep(2)
                    album_items = grouped_messages.pop(msg.grouped_id, [])
                    if album_items:
                        first_item = next((item for item in album_items if item.text), album_items[0])
                        
                        is_album_ad, ad_reason = is_advertisement(first_item)
                        if is_album_ad:
                            return

                        dup_album, _ = is_duplicate(first_item)
                        if dup_album:
                            print(f"⚠️ آلبوم تکراری از @{username} متوقف شد.")
                            return

                        files = [item.media for item in album_items if item.media]
                        caption = first_item.text or ""
                        final_caption = clean_text_simple(caption, custom_id)

                        for target in targets:
                            try:
                                if len(final_caption) > 1024:
                                    await client.send_file(target, file=files)
                                    await client.send_message(target, message=final_caption)
                                else:
                                    await client.send_file(target, file=files, caption=final_caption)
                                print(f"✅ آلبوم به @{target} ارسال شد.")
                            except Exception as e:
                                print(f"❌ خطا در ارسال آلبوم: {e}")
                else:
                    grouped_messages[msg.grouped_id].append(msg)
                return

            # ارسال به همه مقاصد
            for target in targets:
                await send_post_to_target(target, msg.media, msg.raw_text, custom_id)
                print(f"✅ پست به @{target} ارسال شد.")

        except Exception as e:
            print(f"❌ خطا در ارسال: {e}")

    await client.run_until_disconnected()

if __name__ == '__main__':
    with client:
        client.loop.run_until_complete(main())