import asyncio
import random
import smtplib
import threading
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from datetime import datetime, timedelta
from telethon import TelegramClient, events
from modules.config import ConfigManager
from modules.logger import logger
from modules.database import execute_db, query_db
from modules.scheduler import is_currently_off_time

def register_handlers(client: TelegramClient):
    """Registers incoming private message handlers on the Telethon client."""
    
    # Remove existing handlers first to avoid duplicates
    client.remove_event_handler(handle_new_message)
    client.add_event_handler(handle_new_message, events.NewMessage(incoming=True, func=lambda e: e.is_private))

async def handle_new_message(event):
    """Processes incoming Telegram private messages and decides whether to auto-reply."""
    config = ConfigManager()
    
    # 1. Global check: is system enabled?
    if not config.get('enabled'):
        return

    sender = await event.get_sender()
    if not sender:
        return

    user_id = sender.id
    username = sender.username or ""
    first_name = sender.first_name or ""
    last_name = sender.last_name or ""
    full_name = f"{first_name} {last_name}".strip()
    phone = getattr(sender, 'phone', "") or ""
    message_text = event.text or ""

    # Check if sender is ourselves (self-messages)
    try:
        me = await event.client.get_me()
        if me and sender.id == me.id:
            return
    except Exception as e:
        logger.error(f"Error getting self details: {e}")

    # Determine status
    status = "Replied"

    # 2. Check VIP Ignore Lists (Blacklist and Whitelist)
    # Whitelist logic: If there are whitelist entries, ONLY whitelisted users get auto-replies.
    # Blacklist logic: If sender matches blacklist, they never get auto-replies.
    try:
        # Check blacklist
        blacklist_match = query_db(
            "SELECT id FROM vip_list WHERE list_type = 'blacklist' AND (identifier = ? OR identifier = ? OR identifier = ?)",
            (str(user_id), f"@{username}" if username else "", phone)
        )
        if blacklist_match:
            logger.info(f"Ignored message from {full_name} ({user_id}) - User is blacklisted.")
            log_autoreply(user_id, username, full_name, message_text, "", "Ignored: Blacklisted")
            return

        # Check whitelist
        whitelist_exists = query_db("SELECT id FROM vip_list WHERE list_type = 'whitelist'")
        if whitelist_exists:
            whitelist_match = query_db(
                "SELECT id FROM vip_list WHERE list_type = 'whitelist' AND (identifier = ? OR identifier = ? OR identifier = ?)",
                (str(user_id), f"@{username}" if username else "", phone)
            )
            if not whitelist_match:
                # Whitelist is active, but user is not in it
                logger.info(f"Ignored message from {full_name} ({user_id}) - User is not in Whitelist.")
                log_autoreply(user_id, username, full_name, message_text, "", "Ignored: Non-Whitelisted")
                return
    except Exception as e:
        logger.error(f"Error checking VIP list: {e}")

    # 3. Check Keyword Ignore list
    try:
        keywords = query_db("SELECT keyword FROM keywords_ignore")
        if keywords:
            message_lower = message_text.lower()
            ignored_word = None
            for kw_row in keywords:
                kw = kw_row['keyword'].strip().lower()
                if kw and kw in message_lower:
                    ignored_word = kw_row['keyword']
                    break
            
            if ignored_word:
                logger.info(f"Ignored message from {full_name} ({user_id}) - Found ignored keyword: '{ignored_word}'.")
                log_autoreply(user_id, username, full_name, message_text, "", f"Ignored: Keyword '{ignored_word}'")
                return
    except Exception as e:
        logger.error(f"Error checking ignored keywords: {e}")

    # 4. Schedule check: is it off-time?
    if not is_currently_off_time():
        # Not off-time, so we do not auto-reply
        return

    # 5. Check "Reply Once" constraint
    if config.get('reply_once'):
        hours = config.get('reply_after_hours', 24)
        try:
            # Check if we replied to this user in the last X hours
            time_limit = datetime.now() - timedelta(hours=hours)
            recent_reply = query_db(
                "SELECT id FROM autoreply_logs WHERE user_id = ? AND status = 'Replied' AND timestamp > ?",
                (user_id, time_limit.strftime('%Y-%m-%d %H:%M:%S')),
                one=True
            )
            if recent_reply:
                logger.info(f"Ignored message from {full_name} ({user_id}) - Already replied within {hours} hours.")
                log_autoreply(user_id, username, full_name, message_text, "", "Ignored: Reply Once Rule")
                return
        except Exception as e:
            logger.error(f"Error checking Reply Once rule: {e}")

    # Get reply message from config or database (fallback)
    reply_message = config.get('reply_message', "Hello! I am currently away. I will get back to you as soon as possible. (Auto Reply)")

    # 6. Apply typing delays
    typing_delay = int(config.get('typing_delay', 3))
    rand_min = int(config.get('random_delay_min', 1))
    rand_max = int(config.get('random_delay_max', 3))
    total_delay = typing_delay + random.randint(rand_min, rand_max)

    try:
        # Show "typing..." status to the user
        async with event.client.action(event.chat_id, 'typing'):
            await asyncio.sleep(total_delay)
            
        # Send reply
        await event.reply(reply_message)
        logger.info(f"Sent auto-reply to {full_name} ({user_id}).")
        
        # Log to DB
        log_autoreply(user_id, username, full_name, message_text, reply_message, "Replied")
        
        # 7. Auto Forward (if enabled)
        if config.get('forward_enabled'):
            target = config.get('forward_target', 'saved_messages')
            await forward_message(event.client, event, target)
            
        # 8. Notifications
        dispatch_notifications(full_name, user_id, message_text, reply_message)
        
    except Exception as e:
        logger.error(f"Failed to send auto-reply to {user_id}: {e}")
        log_autoreply(user_id, username, full_name, message_text, reply_message, f"Error: {str(e)}")

def log_autoreply(user_id, username, full_name, original_msg, reply_msg, status):
    """Saves auto-reply event details to SQLite."""
    try:
        execute_db(
            """INSERT INTO autoreply_logs (user_id, username, full_name, original_message, reply_message, status, timestamp) 
               VALUES (?, ?, ?, ?, ?, ?, datetime('now'))""",
            (user_id, username, full_name, original_msg, reply_msg, status)
        )
    except Exception as e:
        logger.error(f"Failed to log auto-reply event to database: {e}")

async def forward_message(client, event, target):
    """Forwards original message to target group/channel/user."""
    try:
        if target == 'saved_messages':
            await client.forward_messages('me', event.message)
        else:
            # target can be username or integer ID
            if target.startswith('-100') or target.isdigit():
                await client.forward_messages(int(target), event.message)
            else:
                await client.forward_messages(target, event.message)
        logger.info(f"Forwarded message to target: {target}")
    except Exception as e:
        logger.error(f"Failed to forward message: {e}")

def dispatch_notifications(sender_name, user_id, original_msg, reply_msg):
    """Helper to route and fire notifications on background threads to prevent blocking."""
    config = ConfigManager()
    
    # 1. Email Notification (SMTP)
    if config.get('email_notification_enabled'):
        threading.Thread(
            target=send_email_notification,
            args=(config, sender_name, user_id, original_msg, reply_msg),
            daemon=True
        ).start()
        
    # 2. Desktop Notification
    if config.get('desktop_notification_enabled'):
        logger.info(f"[DESKTOP NOTIFICATION] Telegram message received from {sender_name}: {original_msg}")

def send_email_notification(config, sender_name, user_id, original_msg, reply_msg):
    """Sends an email notification via SMTP."""
    smtp_server = config.get('smtp_server')
    smtp_port = config.get('smtp_port', 587)
    smtp_user = config.get('smtp_user')
    smtp_pass = config.get('smtp_pass')
    recipient = config.get('smtp_recipient')
    
    if not smtp_server or not smtp_user or not smtp_pass or not recipient:
        logger.warning("SMTP notification parameters are incomplete. Email not sent.")
        return
        
    try:
        msg = MIMEMultipart()
        msg['From'] = smtp_user
        msg['To'] = recipient
        msg['Subject'] = f"TG Auto-Reply: Message from {sender_name}"
        
        body = f"""
        Telegram Auto-Reply System Notification
        
        Sender: {sender_name} (ID: {user_id})
        Time: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
        
        Original Message:
        -----------------
        {original_msg}
        
        Auto-Reply Sent:
        ----------------
        {reply_msg}
        
        -- 
        TG Auto Reply Pro
        """
        msg.attach(MIMEText(body, 'plain', 'utf-8'))
        
        with smtplib.SMTP(smtp_server, int(smtp_port)) as server:
            server.starttls()
            server.login(smtp_user, smtp_pass)
            server.sendmail(smtp_user, recipient, msg.as_string())
        logger.info(f"Email notification successfully sent to {recipient}.")
    except Exception as e:
        logger.error(f"Failed to send email notification: {e}")
