from urllib.parse import urlparse
from instagrapi import Client
from instagrapi.exceptions import ChallengeRequired, ClientError
import time
import random
import os
import sys
import logging
import json
from pathlib import Path
from colorama import Fore, Style, init

# تهيئة colorama لعرض الألوان في الطرفية
init(autoreset=True)

# إعداد سجل الأحداث
logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")

def extract_username(link: str) -> str:
    """
    تستخلص اسم المستخدم من رابط حساب إنستغرام باستخدام مكتبة urllib.parse.
    تتجاهل المعاملات (query parameters) إذا وجدت.
    """
    if link.startswith("http"):
        parsed = urlparse(link)
        path = parsed.path.rstrip("/")
        if path:
            return path.split("/")[-1]
        return link
    return link

class InstagramGrowthBot:
    MAX_ACTIONS = 100
    DELAY_RANGE = (15, 35)
    SESSION_FILE = "ig_session.json"
    
    def __init__(self):
        self.cl = Client()
        self.cl.delay_range = [1, 3]  # تأخير عشوائي بين الطلبات
        self.actions_today = 0
        self.username = ""
        self.user_id = None
        self.safe_login()

    def load_session(self) -> bool:
        """تحميل الجلسة من ملف إذا كان موجوداً."""
        session_path = Path(self.SESSION_FILE)
        if session_path.exists():
            try:
                self.cl.load_settings(self.SESSION_FILE)
                account = self.cl.account_info()
                self.username = account.username
                self.user_id = account.pk
                logging.info("✅ تم تحميل الجلسة بنجاح")
                return True
            except Exception as e:
                logging.error(f"❌ فشل تحميل الجلسة: {e}")
                try:
                    os.remove(self.SESSION_FILE)
                    logging.info("🗑️ تم حذف ملف الجلسة التالف.")
                except Exception as remove_error:
                    logging.error(f"❌ فشل حذف ملف الجلسة: {remove_error}")
        return False

    def save_session(self) -> None:
        """حفظ الجلسة في ملف."""
        try:
            self.cl.dump_settings(self.SESSION_FILE)
            logging.info("🔒 تم حفظ الجلسة!")
        except Exception as e:
            logging.error(f"❌ فشل حفظ الجلسة: {e}")

    def safe_login(self) -> None:
        """تسجيل الدخول بشكل آمن مع معالجة التحديات والجلسات."""
        if self.load_session():
            return

        logging.info("=" * 30)
        self.username = input("أدخل اسم المستخدم: ").strip()
        password = input("أدخل كلمة المرور: ").strip()

        try:
            self.cl.login(self.username, password)
            account = self.cl.account_info()
            self.user_id = account.pk
            logging.info(f"✅ تم تسجيل الدخول كـ @{self.username}")
            self.save_session()
        except ChallengeRequired:
            self.handle_challenge()
        except ClientError as e:
            logging.error(f"❌ خطأ في تسجيل الدخول: {e}")
            sys.exit(1)
        except Exception as e:
            logging.error(f"❌ خطأ غير متوقع أثناء تسجيل الدخول: {e}")
            sys.exit(1)

    def handle_challenge(self) -> None:
        """معالجة تحدي تسجيل الدخول من Instagram."""
        logging.warning("⚠️ يلزم تأكيد الهوية (تم إرسال رمز إلى بريدك/هاتفك)")
        code = input("أدخل الرمز المكون من 6 أرقام: ").strip()
        try:
            challenge = self.cl.last_json.get('challenge')
            self.cl.challenge_resolve(challenge, code)
            logging.info("✅ تم التأكيد بنجاح!")
            self.save_session()
        except Exception as e:
            logging.error(f"❌ فشل التأكيد: {e}")
            sys.exit(1)

    def get_targets_from_post(self) -> list:
        """
        يستقبل من المستخدم رابط المنشور وعدد المستخدمين المطلوب استخراجهم،
        ويستخدم الطريقة الخاصة (media_likers) لاستخلاص قائمة الأسماء.
        """
        post_url = input("أدخل رابط المنشور: ").strip()
        try:
            max_users = int(input("أدخل عدد المستخدمين المطلوب استخراجهم: ").strip())
        except ValueError:
            logging.error(f"{Fore.RED}رقم غير صالح. الرجاء إدخال قيمة صحيحة.")
            return []
        try:
            media_pk = self.cl.media_pk_from_url(post_url)
            likers = self.cl.media_likers(media_pk)
            if not likers:
                logging.info(f"{Fore.YELLOW}لم يتم العثور على إعجابات أو المنشور غير متاح.")
                return []
            # استخراج الأسماء من الكائنات
            targets = [user.username for user in likers][:max_users]
            logging.info(f"{Fore.GREEN}تم استخراج {len(targets)} حساب من المنشور.")
            return targets
        except Exception as e:
            logging.error(f"{Fore.RED}خطأ أثناء استخراج الحسابات من المنشور: {e}")
            return []

    def smart_follow(self, targets: list) -> None:
        """متابعة الحسابات بناءً على قائمة الأهداف المُعطاة."""
        if not targets:
            logging.error("❌ لم يتم توفير قائمة حسابات للمتابعة.")
            return

        logging.info(f"⏳ بدء المتابعة لـ {len(targets)} حساب...")
        
        for idx, target in enumerate(targets, start=1):
            if self.actions_today >= self.MAX_ACTIONS:
                logging.warning("⚠️ وصلت للحد اليومي للعمليات.")
                break
            
            # تأكيد استخراج اسم المستخدم (قد يكون الرابط قد تم معالجته مسبقاً)
            username = extract_username(target)
            success = False
            attempts = 0
            
            while not success and attempts < 3:
                attempts += 1
                try:
                    # استخدام الطريقة الخاصة للحصول على معلومات المستخدم
                    user_info = self.cl.user_info_by_username(username)
                    if hasattr(user_info, "friendship_status"):
                        if not user_info.friendship_status.following:
                            self.cl.user_follow(user_info.pk)
                            logging.info(f"✅ [{idx}] متابعة @{username}")
                            self.actions_today += 1
                        else:
                            logging.info(f"ℹ️ الحساب @{username} متابع بالفعل.")
                    else:
                        self.cl.user_follow(user_info.pk)
                        logging.info(f"✅ [{idx}] متابعة @{username} (حالة المتابعة غير معروفة)")
                        self.actions_today += 1
                    success = True
                    self.human_delay()
                except json.JSONDecodeError:
                    logging.warning(f"⚠️ خطأ في بيانات @{username}. المحاولة {attempts} من 3. إعادة المحاولة...")
                    time.sleep(5)
                except ClientError as e:
                    logging.error(f"❌ خطأ في @{username}: {str(e)}")
                    success = True
                    self.human_delay()
                except Exception as e:
                    logging.error(f"❌ خطأ غير محدد في @{username}: {str(e)}")
                    success = True
                    self.human_delay()

    def smart_unfollow(self) -> None:
        """إلغاء متابعة الحسابات بشكل ذكي."""
        try:
            if not self.user_id:
                logging.error("❌ معرف المستخدم غير متوفر.")
                return

            following = self.cl.user_following(self.user_id)
            if not following:
                logging.info("ℹ️ لا توجد حسابات لمتابعتها.")
                return

            logging.info(f"⏳ بدء إلغاء المتابعة لـ {len(following)} حساب...")
            
            for idx, user_id in enumerate(following.keys(), start=1):
                if self.actions_today >= self.MAX_ACTIONS:
                    logging.warning("⚠️ وصلت للحد اليومي للعمليات.")
                    break
                
                try:
                    user_info = self.cl.user_info(user_id)
                    self.cl.user_unfollow(user_id)
                    logging.info(f"✅ [{idx}] إلغاء متابعة @{user_info.username}")
                    self.actions_today += 1
                    self.human_delay()
                except ClientError as e:
                    logging.error(f"❌ خطأ في @{user_info.username}: {e}")
                    self.human_delay()
                except Exception as e:
                    logging.error(f"❌ خطأ في @{user_info.username}: {str(e)[:50]}")
                    self.human_delay()
        except Exception as e:
            logging.error(f"❌ فشل العملية: {e}")

    def human_delay(self) -> None:
        """تأخير عشوائي لمحاكاة سلوك المستخدم."""
        delay = random.randint(*self.DELAY_RANGE)
        logging.info(f"⏳ انتظر {delay} ثانية...")
        time.sleep(delay)

    def show_menu(self) -> None:
        """عرض القائمة الرئيسية ومعالجة اختيار المستخدم."""
        while True:
            logging.info("=" * 30)
            print("🛠️ قائمة إدارة الحسابات")
            print("1. متابعة الحسابات من منشور")
            print("2. إلغاء المتابعة")
            print("3. الخروج")
            choice = input("اختر خيارًا (1-3): ").strip()
            
            if choice == "1":
                targets = self.get_targets_from_post()
                self.smart_follow(targets)
            elif choice == "2":
                self.smart_unfollow()
            elif choice == "3":
                try:
                    self.cl.logout()
                    logging.info("✅ تم الخروج بنجاح!")
                except Exception as e:
                    logging.error(f"❌ خطأ أثناء تسجيل الخروج: {e}")
                sys.exit(0)
            else:
                logging.warning("⚠️ خيار غير متوفر حالياً")

    def get_targets_from_post(self) -> list:
        """يدعو دالة استخراج الحسابات من منشور ويعيد القائمة."""
        return self.get_targets_from_post = self.get_targets_from_post  # placeholder

if __name__ == "__main__":
    bot = InstagramGrowthBot()
    bot.show_menu()
صلح جميع الاخطاء واعطيني سكريبت احترافي كامل متقن