#!/usr/bin/env python3
"""
Core Telegram Bot - Handles only bot setup, authentication, and basic messaging.
"""

import asyncio
import logging
import telegram # Import telegram to check version
from datetime import datetime
from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup
from telegram.ext import Application, ContextTypes, CommandHandler, CallbackQueryHandler, MessageHandler, filters

from src.config.config import Config
from src.trading.trading_engine import TradingEngine
from src.monitoring.market_monitor import MarketMonitor
from src.notifications.notification_manager import NotificationManager
from src.commands.trading_commands import TradingCommands
from src.commands.info_commands import InfoCommands
from src.commands.management_commands import ManagementCommands

logger = logging.getLogger(__name__)

class TelegramTradingBot:
    """Core Telegram bot handling only authentication, messaging, and command routing."""
    
    def __init__(self):
        """Initialize the core bot with minimal responsibilities."""
        # Core bot attributes
        self.application = None
        self.version = "Unknown"
        
        # Initialize subsystems
        self.trading_engine = TradingEngine()
        self.notification_manager = NotificationManager()
        self.market_monitor = MarketMonitor(self.trading_engine, self.notification_manager)
        
        # Initialize command handlers
        self.info_commands = InfoCommands(self.trading_engine)
        self.management_commands = ManagementCommands(self.trading_engine, self.market_monitor)
        # Pass info and management command handlers to TradingCommands
        self.trading_commands = TradingCommands(self.trading_engine, self.notification_manager, 
                                              info_commands_handler=self.info_commands, 
                                              management_commands_handler=self.management_commands)
        
    def is_authorized(self, chat_id: str) -> bool:
        """Check if the chat ID is authorized to use the bot."""
        authorized = str(chat_id) == str(Config.TELEGRAM_CHAT_ID)
        logger.info(f"Authorization check: Incoming chat_id='{chat_id}', Configured TELEGRAM_CHAT_ID='{Config.TELEGRAM_CHAT_ID}', Authorized={authorized}")
        return authorized
    
    async def send_message(self, text: str, parse_mode: str = 'HTML') -> None:
        """Send a message to the authorized chat."""
        if self.application and Config.TELEGRAM_CHAT_ID:
            try:
                await self.application.bot.send_message(
                    chat_id=Config.TELEGRAM_CHAT_ID,
                    text=text,
                    parse_mode=parse_mode
                )
            except Exception as e:
                logger.error(f"Failed to send message: {e}")
    
    def setup_handlers(self):
        """Set up command handlers for the bot."""
        if not self.application:
            return
        
        # Basic bot commands (directly on application for v20.x)
        self.application.add_handler(CommandHandler("start", self.start_command))
        self.application.add_handler(CommandHandler("help", self.help_command))
        
        # Trading commands
        self.application.add_handler(CommandHandler("long", self.trading_commands.long_command))
        self.application.add_handler(CommandHandler("short", self.trading_commands.short_command))
        self.application.add_handler(CommandHandler("exit", self.trading_commands.exit_command))
        self.application.add_handler(CommandHandler("sl", self.trading_commands.sl_command))
        self.application.add_handler(CommandHandler("tp", self.trading_commands.tp_command))
        self.application.add_handler(CommandHandler("coo", self.trading_commands.coo_command))
        
        # Info commands
        self.application.add_handler(CommandHandler("balance", self.info_commands.balance_command))
        self.application.add_handler(CommandHandler("positions", self.info_commands.positions_command))
        self.application.add_handler(CommandHandler("orders", self.info_commands.orders_command))
        self.application.add_handler(CommandHandler("stats", self.info_commands.stats_command))
        self.application.add_handler(CommandHandler("trades", self.info_commands.trades_command))
        self.application.add_handler(CommandHandler("cycles", self.info_commands.cycles_command))
        self.application.add_handler(CommandHandler("market", self.info_commands.market_command))
        self.application.add_handler(CommandHandler("price", self.info_commands.price_command))
        self.application.add_handler(CommandHandler("performance", self.info_commands.performance_command))
        self.application.add_handler(CommandHandler("daily", self.info_commands.daily_command))
        self.application.add_handler(CommandHandler("weekly", self.info_commands.weekly_command))
        self.application.add_handler(CommandHandler("monthly", self.info_commands.monthly_command))
        self.application.add_handler(CommandHandler("risk", self.info_commands.risk_command))
        self.application.add_handler(CommandHandler("balance_adjustments", self.info_commands.balance_adjustments_command))
        self.application.add_handler(CommandHandler("commands", self.info_commands.commands_command))
        self.application.add_handler(CommandHandler("c", self.info_commands.commands_command))  # Alias
        
        # Management commands
        self.application.add_handler(CommandHandler("monitoring", self.management_commands.monitoring_command))
        self.application.add_handler(CommandHandler("alarm", self.management_commands.alarm_command))
        self.application.add_handler(CommandHandler("logs", self.management_commands.logs_command))
        self.application.add_handler(CommandHandler("debug", self.management_commands.debug_command))
        self.application.add_handler(CommandHandler("version", self.management_commands.version_command))
        self.application.add_handler(CommandHandler("keyboard", self.management_commands.keyboard_command))
        
        # Callback and message handlers
        self.application.add_handler(CallbackQueryHandler(self.trading_commands.button_callback))
        
    async def start_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
        """Handle the /start command."""
        logger.info(f"/start command triggered by chat_id: {update.effective_chat.id}")
        logger.debug(f"Full Update object in start_command: {update}")

        chat_id = update.effective_chat.id
        if not self.is_authorized(chat_id):
            logger.warning(f"Unauthorized access attempt by chat_id: {chat_id} in /start.")
            try:
                await context.bot.send_message(chat_id=chat_id, text="❌ Unauthorized access.")
            except Exception as e:
                logger.error(f"Error sending unauthorized message in /start: {e}")
            return
        
        # Determine risk management and stop loss details from Config
        risk_enabled = getattr(Config, 'RISK_MANAGEMENT_ENABLED', False)
        stop_loss_percentage = getattr(Config, 'STOP_LOSS_PERCENTAGE', 0)
        bot_heartbeat = getattr(Config, 'BOT_HEARTBEAT_SECONDS', 10)

        welcome_text = f"""
🤖 <b>Welcome to Hyperliquid Trading Bot v{self.version}</b>

📱 <b>Quick Actions:</b>
• Trading: /long {Config.DEFAULT_TRADING_TOKEN} 100 or /short {Config.DEFAULT_TRADING_TOKEN} 50
• Exit: /exit {Config.DEFAULT_TRADING_TOKEN} (closes position)
• Info: /balance, /positions, /orders

📊 <b>Market Data:</b>
• /market - Detailed market overview
• /price - Quick price check

<b>⚡ Quick Commands:</b>
• /balance - Account balance  
• /positions - Open positions
• /orders - Active orders
• /market - Market data & prices

<b>🚀 Trading:</b>
• /long {Config.DEFAULT_TRADING_TOKEN} 100 - Long position
• /long {Config.DEFAULT_TRADING_TOKEN} 100 45000 - Limit order
• /long {Config.DEFAULT_TRADING_TOKEN} 100 sl:44000 - With stop loss
• /short {Config.DEFAULT_TRADING_TOKEN} 50 - Short position  
• /short {Config.DEFAULT_TRADING_TOKEN} 50 3500 sl:3600 - With stop loss
• /exit {Config.DEFAULT_TRADING_TOKEN} - Close position
• /coo {Config.DEFAULT_TRADING_TOKEN} - Cancel open orders

<b>🛡️ Risk Management:</b>
• Enabled: {'✅ Yes' if risk_enabled else '❌ No'}
• Auto Stop Loss: {stop_loss_percentage}%
• Order Stop Loss: Use sl:price parameter
• /sl {Config.DEFAULT_TRADING_TOKEN} 44000 - Manual stop loss
• /tp {Config.DEFAULT_TRADING_TOKEN} 50000 - Take profit order

<b>📈 Performance & Analytics:</b>
• /stats - Complete trading statistics
• /performance - Token performance ranking & detailed stats
• /daily - Daily performance (last 10 days)
• /weekly - Weekly performance (last 10 weeks)
• /monthly - Monthly performance (last 10 months)
• /risk - Sharpe ratio, drawdown, VaR
• /version - Bot version & system information
• /trades - Recent trade history

<b>🔔 Price Alerts:</b>
• /alarm - List all active alarms
• /alarm {Config.DEFAULT_TRADING_TOKEN} 50000 - Set alarm for {Config.DEFAULT_TRADING_TOKEN} at $50,000
• /alarm {Config.DEFAULT_TRADING_TOKEN} - Show all {Config.DEFAULT_TRADING_TOKEN} alarms
• /alarm 3 - Remove alarm ID 3

<b>🔄 Automatic Monitoring:</b>
• Real-time order fill alerts
• Position opened/closed notifications  
• P&L calculations on trade closure
• Price alarm triggers
• External trade detection & sync
• Auto stats synchronization
• Automatic stop loss placement
• {bot_heartbeat}-second monitoring interval

<b>📊 Universal Trade Tracking:</b>
• Bot trades: Full logging & notifications
• Platform trades: Auto-detected & synced
• Mobile app trades: Monitored & recorded
• API trades: Tracked & included in stats

Type /help for detailed command information.

<b>🔄 Order Monitoring:</b>
• /monitoring - View monitoring status
• /logs - View log file statistics and cleanup

<b>⚙️ Configuration:</b>
• Default Token: {Config.DEFAULT_TRADING_TOKEN}
• Network: {'Testnet' if Config.HYPERLIQUID_TESTNET else 'Mainnet'}

<b>🛡️ Safety Features:</b>
• All trades logged automatically
• Comprehensive performance tracking
• Real-time balance monitoring
• Risk metrics calculation
• Automatic stop loss protection

<b>📱 Mobile Optimized:</b>
• Quick action buttons via /commands
• Instant notifications
• Clean, readable layout

<b>💡 Quick Access:</b>
• /commands or /c - One-tap button menu for all commands

For support, contact your bot administrator.
        """
        
        logger.debug(f"In /start, update.message is: {update.message}, update.effective_chat.id is: {chat_id}")
        try:
            await context.bot.send_message(chat_id=chat_id, text=welcome_text, parse_mode='HTML')
        except Exception as e:
            logger.error(f"Error sending welcome message in /start: {e}")
    
    async def help_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
        """Handle the /help command."""
        logger.info(f"/help command triggered by chat_id: {update.effective_chat.id}")
        logger.debug(f"Full Update object in help_command: {update}")

        chat_id = update.effective_chat.id
        if not self.is_authorized(chat_id):
            logger.warning(f"Unauthorized access attempt by chat_id: {chat_id} in /help.")
            try:
                await context.bot.send_message(chat_id=chat_id, text="❌ Unauthorized access.")
            except Exception as e:
                logger.error(f"Error sending unauthorized message in /help: {e}")
            return
        
        help_text = """
📖 <b>Complete Command Reference</b>

🔄 <b>Trading Commands:</b>
• /long [token] [USDC] [price] [sl:price] - Open long position
• /short [token] [USDC] [price] [sl:price] - Open short position
• /exit [token] - Close position (market order)
• /sl [token] [price] - Set stop loss order
• /tp [token] [price] - Set take profit order
• /coo [token] - Cancel all open orders

📊 <b>Account Info:</b>
• /balance - Account balance and equity
• /positions - Open positions with P&L
• /orders - Active orders
• /trades - Recent trade history
• /stats - Comprehensive trading statistics

📈 <b>Market Data:</b>
• /market [token] - Market data and orderbook
• /price [token] - Quick price check

⚙️ <b>Management:</b>
• /monitoring - View/toggle order monitoring
• /alarm [token] [price] - Set price alerts
• /logs - View recent bot logs
• /debug - Bot internal state (troubleshooting)

For support or issues, check the logs or contact the administrator.
        """
        
        logger.debug(f"In /help, update.message is: {update.message}, update.effective_chat.id is: {chat_id}")
        try:
            await context.bot.send_message(chat_id=chat_id, text=help_text, parse_mode='HTML')
        except Exception as e:
            logger.error(f"Error sending help message in /help: {e}")
    
    async def run(self):
        """Run the Telegram bot with manual initialization and shutdown (v20.x style)."""
        if not Config.TELEGRAM_BOT_TOKEN:
            logger.error("❌ TELEGRAM_BOT_TOKEN not configured")
            return
        
        if not Config.TELEGRAM_CHAT_ID:
            logger.error("❌ TELEGRAM_CHAT_ID not configured")
            return
        
        logger.info(f"🔧 Using python-telegram-bot version: {telegram.__version__} (Running in v20.x style)")

        # Create application
        self.application = Application.builder().token(Config.TELEGRAM_BOT_TOKEN).build()
        
        # Connect notification manager to the bot application
        self.notification_manager.set_bot_application(self.application)
        
        # Set up handlers
        self.setup_handlers()

        keep_running_future = asyncio.Future() # Future to keep the bot alive

        try:
            logger.info("🚀 Initializing bot application (v20.x style)...")
            await self.application.initialize()
            
            logger.info(f"🚀 Starting Telegram trading bot v{self.version} (v20.x style)...")
            
            await self.send_message(
                f"🤖 <b>Manual Trading Bot v{self.version} Started (v20.x style)</b>\n\n"
                f"✅ Connected to Hyperliquid {('Testnet' if Config.HYPERLIQUID_TESTNET else 'Mainnet')}\n"
                f"📊 Default Symbol: {Config.DEFAULT_TRADING_TOKEN}\n"
                f"🔄 All systems ready!\n\n"
                "Use /start for quick actions or /help for all commands."
            )
            
            await self.market_monitor.start()
            
            logger.info("▶️ Starting PTB application's internal tasks (update processing, job queue).")
            await self.application.start() # This is non-blocking and starts the Application's processing loop.

            if self.application.updater:
                logger.info(f"▶️ Activating PTB updater to fetch updates (drop_pending_updates={Config.TELEGRAM_DROP_PENDING_UPDATES}).")
                # updater.start_polling is an async method that starts fetching updates and populates the application's update_queue.
                # It needs to run as a background task, managed by the existing event loop.
                # We don't await it directly here if we want other code (like keep_running_future) to proceed.
                # However, for graceful shutdown, we'll manage its lifecycle.
                # For this structure, we expect the main script to keep the event loop running.
                await self.application.updater.start_polling(drop_pending_updates=Config.TELEGRAM_DROP_PENDING_UPDATES)
            else:
                logger.error("❌ Critical: Application updater is not initialized. Bot cannot receive Telegram updates.")
                # If updater is critical, we might want to stop here or raise an error.
                # For now, we'll let keep_running_future potentially handle the stop.
                if not keep_running_future.done():
                    keep_running_future.set_exception(RuntimeError("Updater not available"))


            logger.info("✅ Bot is initialized and updater is polling. Awaiting stop signal via keep_running_future or Ctrl+C.")
            await keep_running_future 
                    
        except (KeyboardInterrupt, SystemExit) as e: # Added SystemExit here
            logger.info(f"🛑 Bot run interrupted by {type(e).__name__}. Initiating shutdown (v20.x style)...")
            if not keep_running_future.done():
                keep_running_future.set_exception(e if isinstance(e, SystemExit) else KeyboardInterrupt())
        except asyncio.CancelledError:
            logger.info("🛑 Bot run task cancelled. Initiating shutdown (v20.x style)...")
            if not keep_running_future.done():
                keep_running_future.cancel()
        except Exception as e:
            logger.error(f"❌ Unhandled error in bot run loop (v20.x style): {e}", exc_info=True)
            if not keep_running_future.done():
                keep_running_future.set_exception(e)
        finally:
            logger.info("🔌 Starting graceful shutdown sequence in TelegramTradingBot.run (v20.x style)...")
            try:
                logger.info("Stopping market monitor...")
                await self.market_monitor.stop()
                logger.info("Market monitor stopped.")

                if self.application:
                    # Stop the updater first if it's running
                    if self.application.updater and self.application.updater.running:
                        logger.info("Stopping PTB updater polling...")
                        await self.application.updater.stop()
                        logger.info("PTB updater polling stopped.")
                    
                    # Then stop the application's own processing
                    if self.application.running: # Check if application was started
                        logger.info("Stopping PTB application components (handlers, job queue)...")
                        await self.application.stop() 
                        logger.info("PTB application components stopped.")
                    
                    # Finally, shutdown the application
                    logger.info("Shutting down PTB application (bot, persistence, etc.)...")
                    await self.application.shutdown()
                    logger.info("PTB application shut down.")
                else:
                    logger.warning("Application object was None during shutdown in TelegramTradingBot.run.")
                
                logger.info("✅ Graceful shutdown sequence in TelegramTradingBot.run (v20.x style) complete.")
                
            except Exception as e:
                logger.error(f"💥 Error during shutdown sequence in TelegramTradingBot.run (v20.x style): {e}", exc_info=True)