import os
import sys
import click
from slack_bolt import App
from slack_bolt.adapter.socket_mode import SocketModeHandler
from dotenv import load_dotenv

# Add project root to path
sys.path.append(os.getcwd())

from health.utils.logging_config import setup_logger
from health.utils.env_loader import load_env_with_extras
from slack_bot.dispatcher import MessageDispatcher
from slack_bot.context.storage import ContextStorage

logger = setup_logger(__name__)

# Load environment variables
load_env_with_extras()


@click.command()
@click.option("--model", default=None, help="Gemini model to use (overrides .env)")
def main(model: str):
    """Butler Slack Bot - Gemini Edition."""

    # Override model in environment only if specified via CLI
    if model:
        os.environ["GEMINI_MODEL"] = model
        logger.info(f"Using model from CLI: {model}")

    # Get the actual model being used (from CLI or .env)
    actual_model = os.environ.get("GEMINI_MODEL", "gemini-2.0-flash-exp")
    base_url = os.environ.get("GEMINI_BASE_URL", "Not set (will use direct API)")
    config_path = os.environ.get("GEMINI_CONFIG_PATH", ".env")

    logger.info(f"Starting Butler Bot with configuration:")
    logger.info(f"  Config file: {config_path}")
    logger.info(f"  Model: {actual_model}")
    logger.info(f"  Base URL: {base_url}")
    logger.info(f"  Using proxy: {'Yes' if base_url and 'http' in base_url else 'No (Direct Google API)'}")

    # Initialize Slack App
    bot_token = os.environ.get("SLACK_BOT_TOKEN")
    app_token = os.environ.get("SLACK_APP_TOKEN")

    if not bot_token or not app_token:
        logger.error("Missing SLACK_BOT_TOKEN or SLACK_APP_TOKEN in .env")
        sys.exit(1)

    app = App(token=bot_token)

    # Tool mode: 'none' (no tools), 'light' (5), 'standard' (10), 'full' (15), 'all' (21)
    # Use 'none' if your proxy doesn't support function calling
    tool_mode = os.environ.get("TOOL_MODE", "light")
    dispatcher = MessageDispatcher(tool_mode=tool_mode)
    logger.info(f"Dispatcher initialized in '{tool_mode}' mode")

    # Message deduplication: Track processed message IDs
    processed_messages = set()
    MAX_TRACKED_MESSAGES = 1000

    # Command Handler: Clear Context
    @app.message(r"^/(clear|reset)$")
    def handle_clear_context(message, say):
        """Clear conversation context for the current channel."""
        try:
            channel = message["channel"]
            storage = ContextStorage(channel)

            # Get context size before clearing
            old_context = storage.get_context()
            old_count = len(old_context)

            storage.clear()

            logger.info(f"✅ Context cleared for channel {channel} (removed {old_count} messages)")
            say(f"✅ 对话历史已清空,我们重新开始!\n\n_Context cleared ({old_count} messages removed). Starting fresh conversation._")
        except Exception as e:
            logger.error(f"Error clearing context: {e}", exc_info=True)
            say(f"❌ 清空对话历史失败: {e}")

    # Command Handler: Show Context Stats
    @app.message(r"^/stats$")
    def handle_context_stats(message, say):
        """Show conversation context statistics."""
        try:
            channel = message["channel"]
            storage = ContextStorage(channel)
            context = storage.get_context()

            # Calculate token estimate (rough: 1 token ≈ 3 chars for Chinese/English mix)
            total_chars = sum(len(msg.get("content", "")) for msg in context)
            estimated_tokens = total_chars // 3

            stats_msg = (
                f"📊 **对话上下文统计 (Context Stats)**\n\n"
                f"• 消息数量 (Messages): {len(context)}\n"
                f"• 总字符数 (Total chars): {total_chars:,}\n"
                f"• 预估 Token (Est. tokens): ~{estimated_tokens:,}\n\n"
                f"_使用 `/clear` 可以清空对话历史_"
            )

            say(stats_msg)
            logger.info(f"Context stats for {channel}: {len(context)} messages, ~{estimated_tokens} tokens")
        except Exception as e:
            logger.error(f"Error getting context stats: {e}", exc_info=True)
            say(f"❌ 获取统计信息失败: {e}")

    # Message Handler
    @app.event("message")
    def handle_message(message, say):

        try:
            # Skip command messages (they're handled by command handlers)
            text = message.get("text", "")
            if text.startswith("/clear") or text.startswith("/reset") or text.startswith("/stats"):
                logger.debug("Skipping command message in general handler")
                return

            # Deduplicate using client_msg_id or event_ts
            msg_id = message.get("client_msg_id") or message.get("ts")

            if msg_id in processed_messages:
                logger.debug(f"Skipping duplicate message: {msg_id}")
                return

            # Add to processed set
            processed_messages.add(msg_id)

            # Limit memory usage by keeping only recent message IDs
            if len(processed_messages) > MAX_TRACKED_MESSAGES:
                # Remove oldest half
                to_remove = list(processed_messages)[:MAX_TRACKED_MESSAGES // 2]
                for old_id in to_remove:
                    processed_messages.discard(old_id)

            text = message.get("text", "")
            channel = message["channel"]
            user = message["user"]
            files = message.get("files", [])

            # Generate Request ID
            import uuid
            import time
            request_id = str(uuid.uuid4())[:8]
            start_time = time.time()
            
            logger.info(f"[{request_id}] 📥 Received message from {user} in {channel}: {text} (Files: {len(files)})")

            # Send temporary "Processing..." message
            ack_response = say(f"⏳ Butler is thinking...")
            ack_ts = ack_response["ts"]

            # Dispatch to Gemini with the timestamp to update
            dispatcher.dispatch(text, channel, user, response_ts=ack_ts, request_id=request_id, files=files)
            
            elapsed = time.time() - start_time
            logger.info(f"[{request_id}] ✅ Request completed in {elapsed:.2f}s")

        except Exception as e:
            logger.error(f"Error handling message: {e}", exc_info=True)
            try:
                say(f"🐛 Butler encountered an error: {e}")
            except Exception:
                pass

    # Start Socket Mode
    try:
        handler = SocketModeHandler(app, app_token)
        logger.info("⚡️ Butler (Gemini) is connected to Slack!")
        handler.start()
    except Exception as e:
        logger.error(f"Failed to start SocketModeHandler: {e}")
        sys.exit(1)


if __name__ == "__main__":
    main()
