"""
HexBot - Telegram Bot Interface for FlawHunt CLI
Allows remote command execution via Telegram using the HUNTER agent.
"""
import asyncio
import logging
import os
from typing import Optional, List
from datetime import datetime

try:
    from telegram import Update
    from telegram.ext import (
        Application,
        CommandHandler,
        MessageHandler,
        ContextTypes,
        filters
    )
    TELEGRAM_AVAILABLE = True
except ImportError:
    TELEGRAM_AVAILABLE = False
    # Define dummy types for when telegram is not available
    Update = None
    ContextTypes = None
    print("Warning: python-telegram-bot not installed. Install with: pip install python-telegram-bot")

from rich.console import Console
from rich.panel import Panel

console = Console()


def clean_markdown(text: str) -> str:
    """
    Clean markdown formatting from text for Telegram display.
    Removes ** (bold), __ (italic), ``` (code blocks), ### (headers), etc.
    """
    import re
    
    if not text:
        return text
    
    # Remove code block markers
    text = re.sub(r'```[\w]*\n?', '', text)
    
    # Remove bold markers
    text = re.sub(r'\*\*([^\*]+)\*\*', r'\1', text)
    
    # Remove italic markers
    text = re.sub(r'__([^_]+)__', r'\1', text)
    text = re.sub(r'_([^_]+)_', r'\1', text)
    
    # Remove header markers
    text = re.sub(r'^#{1,6}\s+', '', text, flags=re.MULTILINE)
    
    # Remove inline code markers
    text = re.sub(r'`([^`]+)`', r'\1', text)
    
    # Remove strikethrough
    text = re.sub(r'~~([^~]+)~~', r'\1', text)
    
    # Clean up multiple newlines
    text = re.sub(r'\n{3,}', '\n\n', text)
    
    return text.strip()


class HexBot:
    """Telegram bot interface for FlawHunt CLI."""
    
    def __init__(self, agent_harness, bot_token: str, authorized_users: List[int], state: dict):
        """
        Initialize HexBot.
        
        Args:
            agent_harness: AgentHarness instance (HUNTER agent)
            bot_token: Telegram bot token from BotFather
            authorized_users: List of authorized Telegram user IDs
            state: Application state dictionary
        """
        if not TELEGRAM_AVAILABLE:
            raise ImportError("python-telegram-bot is required. Install with: pip install python-telegram-bot")
        
        self.agent = agent_harness
        self.bot_token = bot_token
        self.authorized_users = set(authorized_users)
        self.state = state
        self.application = None
        
        # Configure logging
        logging.basicConfig(
            format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
            level=logging.INFO
        )
        self.logger = logging.getLogger(__name__)
        
    def is_authorized(self, user_id: int) -> bool:
        """Check if user is authorized to use the bot."""
        return user_id in self.authorized_users
    
    async def start_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
        """Handle /start command."""
        user = update.effective_user
        
        if not self.is_authorized(user.id):
            await update.message.reply_text(
                "⛔ Unauthorized access attempt detected.\n"
                f"Your user ID: {user.id}\n\n"
                "Contact the bot administrator to get authorized."
            )
            self.logger.warning(f"Unauthorized access attempt by user {user.id} ({user.username})")
            return
        
        welcome_message = (
            "🤖 **HexBot - FlawHunt CLI Remote Interface**\n\n"
            "Welcome to HexBot! I'm your remote command execution interface powered by the HUNTER agent.\n\n"
            "**How to use:**\n"
            "• Send me any command or request in natural language\n"
            "• I'll process it using the HUNTER agent on the connected machine\n"
            "• You'll receive the output right here in Telegram\n\n"
            "**Commands:**\n"
            "/start - Show this welcome message\n"
            "/help - Show available commands\n"
            "/status - Check bot and agent status\n"
            "/info - Show your authorization info\n\n"
            "**Example requests:**\n"
            "• `list files in current directory`\n"
            "• `scan network for open ports`\n"
            "• `install nmap`\n"
            "• `what are the best tools for web testing?`\n\n"
            "⚠️ **Security:** Safe mode is enforced for remote execution."
        )
        
        await update.message.reply_text(welcome_message, parse_mode='Markdown')
        self.logger.info(f"User {user.id} ({user.username}) started the bot")
    
    async def help_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
        """Handle /help command."""
        user = update.effective_user
        
        if not self.is_authorized(user.id):
            await update.message.reply_text("⛔ Unauthorized. Use /start to see your user ID.")
            return
        
        help_text = (
            "🔧 **HexBot Commands**\n\n"
            "**Bot Commands:**\n"
            "/start - Welcome message and introduction\n"
            "/help - Show this help message\n"
            "/status - Check bot and agent status\n"
            "/info - Show your authorization info\n\n"
            "**Using HexBot:**\n"
            "Simply send any message with your command or request. "
            "The HUNTER agent will process it and return the results.\n\n"
            "**Examples:**\n"
            "• `list files`\n"
            "• `show system information`\n"
            "• `install and configure nmap`\n"
            "• `explain what is SQL injection`\n"
            "• `create a python script to parse logs`\n\n"
            "**Safety:**\n"
            "• Safe mode is always enabled for remote execution\n"
            "• Dangerous commands require confirmation\n"
            "• All actions are logged\n"
        )
        
        await update.message.reply_text(help_text, parse_mode='Markdown')
    
    async def status_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
        """Handle /status command."""
        user = update.effective_user
        
        if not self.is_authorized(user.id):
            await update.message.reply_text("⛔ Unauthorized. Use /start to see your user ID.")
            return
        
        status_text = (
            f"✅ **HexBot Status**\n\n"
            f"**Bot:** Online and operational\n"
            f"**Agent:** HUNTER mode active\n"
            f"**Safe Mode:** {self.state.get('safe_mode', True)}\n"
            f"**Verbose Mode:** {self.state.get('verbose', False)}\n"
            f"**Model:** {self.state.get('model', 'N/A')}\n"
            f"**Provider:** {self.state.get('provider', 'N/A')}\n"
            f"**Timestamp:** {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n"
        )
        
        await update.message.reply_text(status_text, parse_mode='Markdown')
    
    async def info_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
        """Handle /info command."""
        user = update.effective_user
        
        info_text = (
            f"👤 **Your Information**\n\n"
            f"**User ID:** `{user.id}`\n"
            f"**Username:** @{user.username if user.username else 'N/A'}\n"
            f"**First Name:** {user.first_name}\n"
            f"**Authorized:** {'✅ Yes' if self.is_authorized(user.id) else '⛔ No'}\n"
        )
        
        await update.message.reply_text(info_text, parse_mode='Markdown')
    
    async def handle_message(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
        """Handle incoming messages (commands from user)."""
        user = update.effective_user
        message_text = update.message.text
        
        # Check authorization
        if not self.is_authorized(user.id):
            await update.message.reply_text(
                "⛔ Unauthorized. Use /start to see your user ID and contact the administrator."
            )
            self.logger.warning(f"Unauthorized message from user {user.id}: {message_text}")
            return
        
        self.logger.info(f"Processing command from {user.username} ({user.id}): {message_text}")
        
        # Send "processing" message
        processing_msg = await update.message.reply_text("🔄 Processing your request...")
        
        try:
            # Execute command using HUNTER agent
            # Note: agent.ask() is synchronous, so we run it in executor
            loop = asyncio.get_event_loop()
            response = await loop.run_in_executor(
                None, 
                self.agent.ask, 
                message_text,
                True  # use_history
            )
            
            # Clean markdown formatting from response
            clean_response = clean_markdown(response)
            
            # Delete processing message
            await processing_msg.delete()
            
            # Send response (handle long messages)
            await self.send_long_message(update, clean_response)
            
            self.logger.info(f"Successfully processed command from {user.username}")
            
        except Exception as e:
            self.logger.error(f"Error processing command: {str(e)}", exc_info=True)
            await processing_msg.delete()
            await update.message.reply_text(
                f"❌ Error processing your request:\n\n{str(e)}\n\n"
                "Please try again or contact the administrator."
            )
    
    async def send_long_message(self, update: Update, text: str, max_length: int = 4000):
        """
        Send a long message, splitting it into multiple messages if needed.
        Telegram has a 4096 character limit per message.
        """
        if len(text) <= max_length:
            await update.message.reply_text(text)
            return
        
        # Split into chunks
        chunks = []
        current_chunk = ""
        
        for line in text.split('\n'):
            if len(current_chunk) + len(line) + 1 > max_length:
                chunks.append(current_chunk)
                current_chunk = line + '\n'
            else:
                current_chunk += line + '\n'
        
        if current_chunk:
            chunks.append(current_chunk)
        
        # Send chunks
        for i, chunk in enumerate(chunks):
            if i == 0:
                await update.message.reply_text(f"📄 **Response (Part {i+1}/{len(chunks)}):**\n\n{chunk}")
            else:
                await update.message.reply_text(f"📄 **Part {i+1}/{len(chunks)}:**\n\n{chunk}")
    
    async def error_handler(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
        """Handle errors."""
        self.logger.error(f"Update {update} caused error {context.error}", exc_info=context.error)
        
        if update and update.effective_message:
            await update.effective_message.reply_text(
                "❌ An unexpected error occurred. Please try again later."
            )
    
    def build_application(self):
        """Build the Telegram application with handlers."""
        self.application = Application.builder().token(self.bot_token).build()
        
        # Add command handlers
        self.application.add_handler(CommandHandler("start", self.start_command))
        self.application.add_handler(CommandHandler("help", self.help_command))
        self.application.add_handler(CommandHandler("status", self.status_command))
        self.application.add_handler(CommandHandler("info", self.info_command))
        
        # Add message handler for all text messages
        self.application.add_handler(
            MessageHandler(filters.TEXT & ~filters.COMMAND, self.handle_message)
        )
        
        # Add error handler
        self.application.add_error_handler(self.error_handler)
        
        self.logger.info("HexBot application built successfully")
    
    async def start(self):
        """Start the bot."""
        if not self.application:
            self.build_application()
        
        console.print(Panel.fit(
            "[bold green]🤖 HexBot Started![/bold green]\n\n"
            f"[cyan]Bot is now running and listening for commands...[/cyan]\n"
            f"[dim]Authorized users: {len(self.authorized_users)}[/dim]\n"
            f"[dim]Press Ctrl+C to stop[/dim]",
            title="HexBot Status",
            border_style="green"
        ))
        
        self.logger.info("Starting HexBot...")
        
        # Start polling
        await self.application.initialize()
        await self.application.start()
        await self.application.updater.start_polling(drop_pending_updates=True)
        
        # Keep running until interrupted
        try:
            # Run forever
            await asyncio.Event().wait()
        except (KeyboardInterrupt, SystemExit):
            self.logger.info("Shutting down HexBot...")
        finally:
            await self.stop()
    
    async def stop(self):
        """Stop the bot gracefully."""
        if self.application:
            await self.application.updater.stop()
            await self.application.stop()
            await self.application.shutdown()
        
        console.print("[yellow]HexBot stopped.[/yellow]")
        self.logger.info("HexBot stopped")
    
    def run(self):
        """Run the bot (blocking)."""
        try:
            asyncio.run(self.start())
        except KeyboardInterrupt:
            console.print("\n[yellow]Shutting down HexBot...[/yellow]")
