import os
import time
import json
import logging
import requests
import urllib.parse
import telebot
import threading
from telebot.types import InlineKeyboardMarkup, InlineKeyboardButton
from functools import wraps

TOKEN = "8350472311:AAFd5DBInXDFAfU6NL-u6rwEEOzkUAk2QKk"
CHANNEL_ID = -1003006093715
CHANNEL_USERNAME = "https://t.me/SourceKodo"
DEVELOPER_URL = "https://t.me/DevKodo"
DEVELOPER_ID = 7923164784
USERS_FILE = 'users.json'

bot = telebot.TeleBot(TOKEN)
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

try:
    bot_info = bot.get_me()
    bot_username = f"@{bot_info.username}" if getattr(bot_info, "username", None) else "UsernameBot"
except Exception as e:
    logger.error(f"Could not get bot info: {e}")
    bot_username = "UsernameBot"

def load_users():
    if not os.path.exists(USERS_FILE):
        return {}
    try:
        with open(USERS_FILE, 'r', encoding='utf-8') as f:
            return json.load(f)
    except (IOError, json.JSONDecodeError):
        return {}

def save_users(users_data):
    try:
        with open(USERS_FILE, 'w', encoding='utf-8') as f:
            json.dump(users_data, f, indent=4, ensure_ascii=False)
    except IOError as e:
        logger.error(f"Error saving users data: {e}")

def save_user_data(user):
    users = load_users()
    user_id_str = str(user.id)
    if user_id_str not in users:
        user_info = {
            'name': user.first_name + (f" {user.last_name}" if user.last_name else ""),
            'username': user.username,
            'user_id': user.id
        }
        users[user_id_str] = user_info
        save_users(users)
        logger.info(f"New user saved: {user.id}")

def check_subscription(user_id):
    try:
        member = bot.get_chat_member(CHANNEL_ID, user_id)
        return member.status in ['member', 'administrator', 'creator']
    except Exception as e:
        logger.error(f"Error checking subscription for user {user_id}: {e}")
        return False

def subscription_required(func):
    @wraps(func)
    def wrapped(message, *args, **kwargs):
        if not check_subscription(message.from_user.id):
            bot.send_message(
                message.chat.id,
                f"*يجب عليك الاشتراك في القناة أولاً لاستخدام البوت*:\n\n- {CHANNEL_USERNAME}",
                parse_mode='Markdown'
            )
            return
        return func(message, *args, **kwargs)
    return wrapped

def developer_only(func):
    @wraps(func)
    def wrapped(message, *args, **kwargs):
        user_id = message.from_user.id if isinstance(message, telebot.types.Message) else message.message.chat.id
        if user_id != DEVELOPER_ID:
            bot.reply_to(message, "عذراً، هذا الأمر مخصص للمطور فقط.")
            return
        return func(message, *args, **kwargs)
    return wrapped

def dev_menu_markup():
    markup = InlineKeyboardMarkup()
    markup.row(
        InlineKeyboardButton("الإحصائيات", callback_data='dev_stats'),
        InlineKeyboardButton("إذاعة بالخاص", callback_data='dev_broadcast_start')
    )
    return markup

def send_dev_menu(chat_id, message_id=None):
    text = "عزيزي هذه لوحة التحكم الخاصة بك:"
    markup = dev_menu_markup()
    try:
        if message_id:
            bot.edit_message_text(text, chat_id, message_id, reply_markup=markup)
        else:
            bot.send_message(chat_id, text, reply_markup=markup)
    except Exception as e:
        logger.error(f"Error sending dev menu: {e}")

@bot.message_handler(commands=['dev'])
@developer_only
def handle_dev(message):
    send_dev_menu(message.chat.id)

@bot.callback_query_handler(func=lambda call: call.data.startswith('dev_'))
@developer_only
def handle_dev_callback(call):
    bot.answer_callback_query(call.id)
    chat_id = call.message.chat.id
    message_id = call.message.message_id
    data = call.data
    if data == 'dev_menu':
        bot.clear_step_handler_by_chat_id(chat_id)
        send_dev_menu(chat_id, message_id)
        return
    back_markup = InlineKeyboardMarkup()
    back_markup.add(InlineKeyboardButton("الرجوع للقائمة الرئيسية", callback_data='dev_menu'))
    if data == 'dev_stats':
        users = load_users()
        count = len(users)
        text = f"**إحصائيات المستخدمين**:\n\nعدد المستخدمين: *{count}* مستخدم."
        bot.edit_message_text(text, chat_id, message_id, reply_markup=back_markup, parse_mode='Markdown')
    elif data == 'dev_broadcast_start':
        text = "أرسل الآن الرسالة التي تريد بثها لجميع المستخدمين."
        bot.edit_message_text(text, chat_id, message_id, reply_markup=back_markup)
        bot.register_next_step_handler(call.message, process_broadcast_message, message_id_to_edit=message_id)

def process_broadcast_message(message, message_id_to_edit):
    chat_id = message.chat.id
    if message.from_user.id != DEVELOPER_ID:
        bot.send_message(chat_id, "تم إلغاء العملية. هذا الأمر مخصص للمطور فقط.")
        send_dev_menu(chat_id, message_id_to_edit)
        return
    broadcast_text = message.text
    if not broadcast_text:
        bot.edit_message_text("لم يتم إرسال نص. تم إلغاء الإذاعة.", chat_id, message_id_to_edit, reply_markup=dev_menu_markup())
        return
    users = load_users()
    total_users = len(users)
    sent_count = 0
    failed_count = 0
    bot.edit_message_text(f"بدء عملية الإذاعة لـ {total_users} مستخدم...", chat_id, message_id_to_edit)
    for user_id_str, user_info in users.items():
        try:
            bot.send_message(user_info['user_id'], broadcast_text, parse_mode='Markdown')
            sent_count += 1
            time.sleep(0.05)
        except Exception as e:
            logger.warning(f"Failed to send broadcast to user {user_id_str}: {e}")
            failed_count += 1
    result_text = f"**انتهت عملية الإذاعة**:\n\nتم الإرسال بنجاح إلى: *{sent_count}* مستخدم.\nفشل الإرسال إلى: *{failed_count}* مستخدم."
    back_markup = InlineKeyboardMarkup()
    back_markup.add(InlineKeyboardButton("الرجوع للقائمة الرئيسية", callback_data='dev_menu'))
    bot.edit_message_text(result_text, chat_id, message_id_to_edit, reply_markup=back_markup, parse_mode='Markdown')

def _keep_chat_action(chat_id, action, stop_event, interval=4):
    while not stop_event.is_set():
        try:
            bot.send_chat_action(chat_id, action)
        except Exception:
            pass
        stop_event.wait(interval)

@bot.message_handler(commands=['start'])
@subscription_required
def cmd_start(message):
    save_user_data(message.from_user)
    name = message.from_user.first_name or ""
    keyboard = InlineKeyboardMarkup()
    keyboard.row(
        InlineKeyboardButton("Developer", url=DEVELOPER_URL),
        InlineKeyboardButton("Source Channel", url=CHANNEL_USERNAME)
    )
    text = f"*مرحباً {name}*.\n\n*أرسل لي رابط الفيديو من TikTok وسأرسل لك الفيديو دون العلامة المائية مع صوت الفيديو*.\n\n*أنتظر ردك الآن*…"
    bot.send_message(chat_id=message.chat.id, text=text, parse_mode='Markdown', reply_markup=keyboard)

@bot.message_handler(func=lambda m: True, content_types=['text'])
@subscription_required
def handle_text(message):
    chat_id = message.chat.id
    text = message.text.strip()
    if text.startswith('/'):
        return
    loading_msg = None
    stop_event = threading.Event()
    t = threading.Thread(target=_keep_chat_action, args=(chat_id, 'typing', stop_event))
    t.daemon = True
    t.start()
    try:
        loading_msg = bot.send_message(chat_id, "*جاري التحميل، يرجى الانتظار*...", parse_mode='Markdown')
        api_url = "https://tikwm.com/api/?url=" + urllib.parse.quote(text, safe='')
        resp = requests.get(api_url, timeout=20)
        resp.raise_for_status()
        data = resp.json()
        if not data or 'data' not in data:
            raise Exception("No data returned from API")
        d = data['data']
        videoUrl = d.get('play')
        musicUrl = d.get('music')
        try:
            bot.delete_message(chat_id, loading_msg.message_id)
        except Exception:
            pass
        caption = f"*Uploaded by*:\n- {bot_username}"
        if videoUrl:
            try:
                bot.send_chat_action(chat_id, 'upload_video')
                bot.send_video(chat_id, video=videoUrl, caption=caption, parse_mode='Markdown')
            except Exception:
                bot.send_message(chat_id, f"*لا يمكن إرسال الفيديو مباشرة، إليك الرابط*:\n{videoUrl}", parse_mode='Markdown')
        if musicUrl:
            try:
                bot.send_chat_action(chat_id, 'upload_audio')
                audio_caption = (
                    
                    f"*صوت الفيديو*: {bot_username}\n"
                )
                bot.send_audio(chat_id, audio=musicUrl, caption=audio_caption, parse_mode='Markdown')
            except Exception:
                pass
    except Exception as e:
        logger.error(f"Error handling text message: {e}")
        try:
            if loading_msg:
                bot.delete_message(chat_id, loading_msg.message_id)
        except Exception:
            pass
        bot.send_message(chat_id, "*حدث خطأ أثناء التحميل. يرجى التأكد من أن الرابط صحيح.*", parse_mode='Markdown')
    finally:
        stop_event.set()

if __name__ == "__main__":
    print("Bot is starting...")
    bot.infinity_polling(timeout=10, long_polling_timeout=5)
