"""
CLI Bot Testing Tool for Butler Health Bot.

Provides an interactive REPL interface to test bot functionality without Slack.
Supports data isolation, real/mock LLM modes, and automated testing.
"""

import os
import sys
import time
import uuid
import shutil
import argparse
from pathlib import Path
from typing import Optional, List, Dict, Any

# Add project root to path
sys.path.insert(0, str(Path(__file__).parent.parent))

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

logger = setup_logger(__name__)


class CLIClient:
    """Mock Slack WebClient that prints messages to terminal."""

    def chat_postMessage(self, channel: str, text: str, **kwargs) -> Dict[str, Any]:
        """Print bot message to stdout."""
        print(f"\n[Bot]: {text}\n")
        return {"ts": f"cli_{int(time.time() * 1000)}", "ok": True}

    def chat_update(self, channel: str, ts: str, text: str, **kwargs) -> Dict[str, Any]:
        """Print updated bot message to stdout."""
        print(f"\n[Bot Updated]: {text}\n")
        return {"ts": ts, "ok": True}


class CLIBot:
    """CLI wrapper for MessageDispatcher with test data isolation."""

    def __init__(
        self,
        use_real_llm: bool = True,
        session_id: Optional[str] = None,
        test_data_dir: str = "/tmp/butler_test_data"
    ):
        """
        Initialize CLI bot.

        Args:
            use_real_llm: If True, use real Gemini API. If False, use mock (future)
            session_id: Unique session identifier (auto-generated if None)
            test_data_dir: Directory for isolated test data
        """
        # Set up test environment
        self.test_data_dir = Path(test_data_dir)
        os.environ["DATA_DIR"] = str(self.test_data_dir)

        # Create isolated test directory structure
        self._setup_test_env()

        # Generate unique session ID
        self.session_id = session_id or f"cli_{uuid.uuid4().hex[:8]}"
        self.use_real_llm = use_real_llm

        # Initialize dispatcher with fake token
        self.dispatcher = MessageDispatcher(bot_token="cli_fake_token")

        # Replace Slack client with CLI mock
        self.dispatcher.client = CLIClient()

        logger.info(f"CLI Bot initialized - Session: {self.session_id}, LLM: {'Real' if use_real_llm else 'Mock'}")
        logger.info(f"Test data directory: {self.test_data_dir}")

    def _setup_test_env(self) -> None:
        """Create isolated test directory structure."""
        self.test_data_dir.mkdir(parents=True, exist_ok=True)

        # Create subdirectories matching production structure
        subdirs = [
            "slack_context",
            "manual_logs",
            "daily_metrics",
            "body_metrics/weight",
            "activities"
        ]

        for subdir in subdirs:
            (self.test_data_dir / subdir).mkdir(parents=True, exist_ok=True)

        logger.info(f"Test environment created at {self.test_data_dir}")

    def start_repl(self) -> None:
        """Start interactive REPL for testing bot conversations."""
        print("=" * 60)
        print("🤖 Butler CLI Bot - Interactive Testing Tool")
        print("=" * 60)
        print(f"Session ID: {self.session_id}")
        print(f"LLM Mode: {'Real Gemini API' if self.use_real_llm else 'Mock'}")
        print(f"Test Data: {self.test_data_dir}")
        print("\nCommands:")
        print("  'exit' or 'quit' - Exit REPL")
        print("  'clear'          - Clear conversation context")
        print("  'help'           - Show this help message")
        print("  'stats'          - Show session statistics")
        print("=" * 60)
        print()

        message_count = 0

        while True:
            try:
                user_input = input("[You]: ").strip()

                if not user_input:
                    continue

                if user_input.lower() in ["exit", "quit"]:
                    print("\n👋 Exiting CLI Bot. Goodbye!\n")
                    break

                elif user_input.lower() == "clear":
                    storage = ContextStorage(self.session_id)
                    storage.clear()
                    print("\n✓ Context cleared\n")
                    message_count = 0
                    continue

                elif user_input.lower() == "help":
                    self._print_help()
                    continue

                elif user_input.lower() == "stats":
                    self._print_stats(message_count)
                    continue

                else:
                    # Send message to bot
                    self.send_message(user_input)
                    message_count += 1

            except KeyboardInterrupt:
                print("\n\n👋 Interrupted. Exiting...\n")
                break
            except EOFError:
                print("\n\n👋 EOF detected. Exiting...\n")
                break
            except Exception as e:
                logger.error(f"Error in REPL: {e}", exc_info=True)
                print(f"\n❌ Error: {e}\n")

    def send_message(
        self,
        text: str,
        files: Optional[List[Dict]] = None
    ) -> None:
        """
        Send a message to the bot.

        Args:
            text: User message text
            files: Optional list of file attachments (not yet implemented)
        """
        request_id = f"cli_{int(time.time() * 1000)}"

        try:
            self.dispatcher.dispatch(
                message_text=text,
                channel_id=self.session_id,
                user_id="cli_user",
                response_ts=None,
                request_id=request_id,
                files=files
            )
        except Exception as e:
            logger.error(f"Failed to send message: {e}", exc_info=True)
            print(f"\n❌ Error processing message: {e}\n")

    def _print_help(self) -> None:
        """Print help information."""
        print("\n" + "=" * 60)
        print("📚 Butler CLI Bot Help")
        print("=" * 60)
        print("\nExample queries:")
        print("  - '昨天的睡眠怎么样？' - Query yesterday's sleep")
        print("  - '今天中午吃了两个卤蛋' - Log diet")
        print("  - 'sync garmin data' - Sync Garmin data")
        print("  - '过去30天的HRV趋势' - Get HRV trends")
        print("\nCommands:")
        print("  clear  - Clear conversation context")
        print("  stats  - Show session statistics")
        print("  help   - Show this help message")
        print("  exit   - Exit the REPL")
        print("=" * 60)
        print()

    def _print_stats(self, message_count: int) -> None:
        """Print session statistics."""
        storage = ContextStorage(self.session_id)
        context = storage.get_context()

        print("\n" + "=" * 60)
        print("📊 Session Statistics")
        print("=" * 60)
        print(f"Session ID:       {self.session_id}")
        print(f"Messages Sent:    {message_count}")
        print(f"Context Size:     {len(context)} messages")
        print(f"Test Data Dir:    {self.test_data_dir}")
        print(f"Data Dir Exists:  {self.test_data_dir.exists()}")

        # Count files in test data
        if self.test_data_dir.exists():
            file_count = sum(1 for _ in self.test_data_dir.rglob('*') if _.is_file())
            print(f"Test Files:       {file_count}")

        print("=" * 60)
        print()

    @staticmethod
    def clean_test_data(test_data_dir: str = "/tmp/butler_test_data") -> None:
        """Clean test data directory."""
        test_dir = Path(test_data_dir)
        if test_dir.exists():
            shutil.rmtree(test_dir)
            print(f"✓ Test data cleaned: {test_dir}")
        else:
            print(f"ℹ️  Test data directory does not exist: {test_dir}")


def main():
    """Main entry point for CLI bot."""
    parser = argparse.ArgumentParser(
        description="Butler CLI Testing Tool - Interactive bot testing without Slack",
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="""
Examples:
  # Interactive mode (uses real Gemini API)
  python tools/cli_bot.py

  # Mock mode (for testing without API calls)
  python tools/cli_bot.py --mock

  # Send single message and exit
  python tools/cli_bot.py --message "昨天的睡眠怎么样？"

  # Clean test data
  python tools/cli_bot.py --clean

  # Custom test data directory
  python tools/cli_bot.py --data-dir /tmp/my_test_data
        """
    )

    parser.add_argument(
        "--mock",
        action="store_true",
        help="Use mock LLM (not yet implemented, currently ignored)"
    )

    parser.add_argument(
        "--message",
        type=str,
        help="Send single message and exit (non-interactive mode)"
    )

    parser.add_argument(
        "--clean",
        action="store_true",
        help="Clean test data directory and exit"
    )

    parser.add_argument(
        "--data-dir",
        type=str,
        default="/tmp/butler_test_data",
        help="Test data directory path (default: /tmp/butler_test_data)"
    )

    parser.add_argument(
        "--session-id",
        type=str,
        help="Custom session ID (default: auto-generated)"
    )

    args = parser.parse_args()

    # Handle --clean flag
    if args.clean:
        CLIBot.clean_test_data(args.data_dir)
        sys.exit(0)

    # Create bot instance
    bot = CLIBot(
        use_real_llm=not args.mock,
        session_id=args.session_id,
        test_data_dir=args.data_dir
    )

    # Handle single message mode
    if args.message:
        print(f"[You]: {args.message}\n")
        bot.send_message(args.message)
        sys.exit(0)

    # Start interactive REPL
    bot.start_repl()


if __name__ == "__main__":
    main()
