import csv
import asyncio
import time
from telethon import TelegramClient
from tqdm import tqdm  # Import tqdm for progress bar
from telethon.tl.functions.channels import JoinChannelRequest
from telethon.tl.functions.messages import ImportChatInviteRequest
from telethon.errors.rpcerrorlist import InviteHashExpiredError
from flask import Flask, jsonify, send_from_directory
# Directory for storing files
from flask import Flask, render_template, send_from_directory
from telethon.tl.functions.channels import GetParticipantsRequest
from telethon.tl.types import ChannelParticipantsSearch
from telethon.errors import FloodWaitError, UserAdminInvalidError
import json
import asyncio
import nest_asyncio
import logging
from telethon import TelegramClient, events
from supabase import create_client, Client
from flask import Flask, jsonify
from threading import Thread
from multiprocessing import Process, Queue
import unicodedata
from telegram.helpers import escape_markdown
import re
import os

from telethon.tl.functions.channels import JoinChannelRequest, InviteToChannelRequest
from telethon.tl.functions.channels import EditBannedRequest
from telethon.tl.types import ChatBannedRights
from telethon.errors.rpcerrorlist import UserAdminInvalidError, UserNotParticipantError
from telethon.errors.rpcerrorlist import InviteHashExpiredError, UserAlreadyParticipantError
from telethon.tl.types import Channel, Chat

logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s - %(levelname)s - %(message)s",
    handlers=[
        logging.FileHandler("join_groups.log"),  # Log to a file
        logging.StreamHandler()  # Log to console
    ])


# Replace with your API credentials (from https://my.telegram.org/apps) , "session/mbot1"
API_ID = 25216912  # Your API ID  
API_HASH = "f65f6050fe9b342a4996c59e4283ab5e"
PHONE_NUMBERS = [
    "+967730426743",
    "+967730446721",
     "+967730436848"
    
    ]  # Your phone numbers with country code
OUTPUT_CSV = "groups_with_status.csv"
# Path to your CSV file
CSV_FILENAME = "8.csv"
SESSION_DIRS = [ 
                "session/mbot1",
                "session/mbot2",
                "session/mbot3"
                
                ]
FILE_DIRECTORY = os.getcwd()  # Current working directory

SLEEP_TIME = 280

# Flask App
app = Flask(__name__)

# 🔹 Flask API Endpoints
@app.route('/')
def index():
    """Show available files for download as an HTML page."""
    files = os.listdir(FILE_DIRECTORY)
    return render_template("index.html", files=files)


@app.route('/download/<filename>')
def download_file(filename):
    """Allow downloading any file from the directory."""
    return send_from_directory(FILE_DIRECTORY, filename, as_attachment=True)


def run_flask():
    app.run(host='0.0.0.0', port=7860)


USER_CSV = "user_list.csv"
# SLEEP_TIME = 280  # Delay between adding users

# Logging setup
logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")

BATCH_SIZE = 30  # Fetch 200 users at a time (Telegram's limit)
MAX_USERS = 200  # Set your desired limit here

def split_csv(csvfile, num_parts):
    """
    Splits the CSV file into `num_parts` chunks.
    :param csvfile: Path to the CSV file.
    :param num_parts: Number of parts to split the CSV into.
    :return: List of lists, where each sublist contains rows for a specific part.
    """
    with open(csvfile, mode="r", encoding="utf-8") as file:
        reader = csv.reader(file)
        rows = list(reader)
    
    # Split rows into `num_parts` chunks
    chunk_size = len(rows) // num_parts
    chunks = [rows[i:i + chunk_size] for i in range(0, len(rows), chunk_size)]
    
    return chunks

async def add_users_to_destination_group_username(destination_group, user_chunk, session_dir, phone_number):
    """
    Adds users from a specific chunk to the destination group using their usernames.
    :param destination_group: The destination group username or ID.
    :param user_chunk: A list of rows (users) from the CSV file.
    :param session_dir: The session directory for the Telegram client.
    :param phone_number: The phone number associated with the Telegram account.
    """
    logging.info(f"Adding users to {destination_group} from chunk...")

    async with TelegramClient(session_dir, API_ID, API_HASH) as client:
        await client.start(phone_number)

        try:
            # Get the destination group entity
            dest_entity = await client.get_entity(destination_group)

            # Get the destination group entity
            dest_entity = await client.get_entity(destination_group)

            # Fetch existing members in the destination group
            existing_usernames = set()
            async for user in client.iter_participants(dest_entity, limit=None):
                existing_usernames.add(user.id)
            logging.info(f"Fetched {len(existing_usernames)} existing users from {destination_group}.")


            # Filter out users already in the destination group
            users = []
            for row in user_chunk:
                try:
                    user_id = int(row[0].strip())
                    user_name = row[1].strip()
                except ValueError:
                    logging.debug(f"Skipping row with non-numeric user_id: {row}")
                    continue
                if user_id not in existing_usernames and user_name != 'N/A':
                    users.append(user_name)

            logging.info(f"Filtered chunk: {len(users)} users to add after removing existing members.")

            count = 0
            for index, username in enumerate(users, start=1):
                try
                    time.sleep(SLEEP_TIME)
                    logging.info(f"[{index}/{len(users)}] Adding user @{username} to {destination_group}...")

                    # Resolve the username to an input entity
                    user_entity = await client.get_input_entity(username)
                    await client(InviteToChannelRequest(dest_entity, [user_entity]))
                    logging.info(f"✅ Successfully added user @{username}.")

                    count += 1
                    if count % BATCH_SIZE == 0:  # Pause after each batch to avoid rate limits
                        logging.info(f"⏳ Waiting {SLEEP_TIME} seconds to avoid rate limits...")
                        await asyncio.sleep(SLEEP_TIME)

                except FloodWaitError as e:
                    logging.warning(f"⚠️ FloodWait: Waiting {e.seconds} seconds...")
                    await asyncio.sleep(e.seconds)

                except UserAdminInvalidError:
                    logging.error(f"❌ Cannot add @{username}: Bot lacks admin rights.")

                except Exception as e:
                    logging.error(f"❌ Failed to add @{username}: {e}")

            logging.info(f"✅ Process completed: Added {count} new users to {destination_group}.")

        except Exception as e:
            logging.error(f"❌ Failed to add users to {destination_group}: {e}")

async def add_users_to_destination_group(destination_group, user_chunk, session_dir, phone_number):
    """
    Adds users from a specific chunk to the destination group while handling rate limits.
    :param destination_group: The destination group username or ID.
    :param user_chunk: A list of rows (users) from the CSV file.
    :param session_dir: The session directory for the Telegram client.
    :param phone_number: The phone number associated with the Telegram account.
    """
    logging.info(f"Adding users to {destination_group} from chunk...")

    async with TelegramClient(session_dir, API_ID, API_HASH) as client:
        await client.start(phone_number)

        try:
            # Get the destination group entity
            dest_entity = await client.get_entity(destination_group)

            # Fetch existing members in the destination group
            existing_user_ids = set()
            async for user in client.iter_participants(dest_entity, limit=None):
                existing_user_ids.add(user.id)
            logging.info(f"Fetched {len(existing_user_ids)} existing users from {destination_group}.")

            # Filter out users already in the destination group
            users = []
            for row in user_chunk:
                try:
                    user_id = int(row[0].strip())
                    user_name = row[1].strip()
                except ValueError:
                    logging.debug(f"Skipping row with non-numeric user_id: {row}")
                    continue
                if user_id not in existing_user_ids and user_name != 'N/A':
                    users.append(user_id)

            logging.info(f"Filtered chunk: {len(users)} users to add after removing existing members.")

            count = 0
            for index, user_id in enumerate(users, start=1):
                try:
                    time.sleep(SLEEP_TIME)
                    logging.info(f"[{index}/{len(users)}] Adding user {user_id} to {destination_group}...")
                    await client(InviteToChannelRequest(dest_entity, [user_id]))
                    logging.info(f"✅ Successfully added user {user_id}.")

                    count += 1
                    if count % BATCH_SIZE == 0:  # Pause after each batch to avoid rate limits
                        logging.info(f"⏳ Waiting {SLEEP_TIME} seconds to avoid rate limits...")
                        await asyncio.sleep(SLEEP_TIME)

                except FloodWaitError as e:
                    logging.warning(f"⚠️ FloodWait: Waiting {e.seconds} seconds...")
                    await asyncio.sleep(e.seconds)

                except UserAdminInvalidError:
                    logging.error(f"❌ Cannot add {user_id}: Bot lacks admin rights.")

                except Exception as e:
                    logging.error(f"❌ Failed to add {user_id}: {e}")

            logging.info(f"✅ Process completed: Added {count} new users to {destination_group}.")

        except Exception as e:
            logging.error(f"❌ Failed to add users to {destination_group}: {e}")


def run_telegram_mov2(session_dir, phone_number, user_chunk):
    asyncio.run(add_users_to_destination_group_username("@searchai090", user_chunk, session_dir, phone_number))


if __name__ == "__main__":
    # Split the CSV file into chunks for each account
    user_chunks = split_csv('UT_CHEM.csv', len(PHONE_NUMBERS))

    # Start Flask server
    p1 = Process(target=run_flask)
    p1.start()

    # Start Telegram processes
    processes = []
    for i, (session_dir, phone_number) in enumerate(zip(SESSION_DIRS, PHONE_NUMBERS)):
        p = Process(target=run_telegram_mov2, args=(session_dir, phone_number, user_chunks[i]))
        p.start()
        processes.append(p)

    # Wait for all processes to finish
    p1.join()
    for p in processes:
        p.join()