#!/usr/bin/env python3
# src/chuk_mcp_math_server/cli.py
"""
Command line interface for the MCP Math Server.
"""

import argparse
import json
import logging
import sys
from typing import Dict, Any

# Early logging configuration for stdio mode
# This must happen BEFORE any other imports to catch import-time logs
if "--transport" not in sys.argv and "stdio" not in sys.argv:
    # Default is stdio, so configure early if not explicitly http
    if "--verbose" not in sys.argv and "-v" not in sys.argv:
        logging.basicConfig(level=logging.WARNING, force=True)
        logging.getLogger("chuk_mcp_math").setLevel(logging.WARNING)
elif "--transport" in sys.argv:
    # Check if stdio is specified
    try:
        transport_idx = sys.argv.index("--transport")
        if transport_idx + 1 < len(sys.argv) and sys.argv[transport_idx + 1] == "stdio":
            if "--verbose" not in sys.argv and "-v" not in sys.argv:
                logging.basicConfig(level=logging.WARNING, force=True)
                logging.getLogger("chuk_mcp_math").setLevel(logging.WARNING)
    except (ValueError, IndexError):
        pass

from .math_config import MathServerConfig, load_math_configuration_from_sources
from .math_server import ConfigurableMCPMathServer

logger = logging.getLogger(__name__)


def create_argument_parser() -> argparse.ArgumentParser:
    """Create the command line argument parser."""
    parser = argparse.ArgumentParser(
        description="Configurable Chuk MCP Math Server - Highly Customizable Mathematical Function Server",
        formatter_class=argparse.RawDescriptionHelpFormatter,
    )

    # Transport settings
    transport_group = parser.add_argument_group("Transport Settings")
    transport_group.add_argument(
        "--transport",
        "-t",
        choices=["stdio", "http"],
        default="stdio",
        help="Transport method to use (default: stdio)",
    )
    transport_group.add_argument(
        "--port",
        "-p",
        type=int,
        default=8000,
        help="Port for HTTP transport (default: 8000)",
    )
    transport_group.add_argument(
        "--host",
        default="0.0.0.0",  # nosec B104
        help="Host for HTTP transport (default: 0.0.0.0)",
    )

    # Feature toggles
    feature_group = parser.add_argument_group("Feature Control")
    feature_group.add_argument(
        "--disable-tools",
        action="store_true",
        help="Disable mathematical tool registration",
    )
    feature_group.add_argument(
        "--disable-prompts", action="store_true", help="Disable prompt registration"
    )
    feature_group.add_argument(
        "--disable-resources", action="store_true", help="Disable resource registration"
    )

    # Function filtering
    filter_group = parser.add_argument_group("Function Filtering")
    filter_group.add_argument(
        "--functions",
        nargs="+",
        help="Whitelist specific functions (e.g., --functions is_prime fibonacci)",
    )
    filter_group.add_argument(
        "--exclude-functions",
        nargs="+",
        help="Blacklist specific functions (e.g., --exclude-functions slow_function)",
    )
    filter_group.add_argument(
        "--domains",
        nargs="+",
        choices=["arithmetic", "number_theory", "trigonometry"],
        help="Whitelist mathematical domains",
    )
    filter_group.add_argument(
        "--exclude-domains",
        nargs="+",
        choices=["arithmetic", "number_theory", "trigonometry"],
        help="Blacklist mathematical domains",
    )
    filter_group.add_argument(
        "--categories",
        nargs="+",
        help="Whitelist function categories (e.g., --categories core primes)",
    )
    filter_group.add_argument(
        "--exclude-categories", nargs="+", help="Blacklist function categories"
    )

    # Performance settings
    perf_group = parser.add_argument_group("Performance Settings")
    perf_group.add_argument(
        "--cache-strategy",
        choices=["none", "memory", "smart"],
        default="smart",
        help="Caching strategy (default: smart)",
    )
    perf_group.add_argument(
        "--cache-size",
        type=int,
        default=1000,
        help="Cache size for mathematical functions (default: 1000)",
    )
    perf_group.add_argument(
        "--timeout",
        type=float,
        default=30.0,
        help="Computation timeout in seconds (default: 30.0)",
    )

    # Logging and debugging
    log_group = parser.add_argument_group("Logging")
    log_group.add_argument(
        "--verbose", "-v", action="store_true", help="Enable verbose debug logging"
    )
    log_group.add_argument(
        "--quiet", "-q", action="store_true", help="Minimize logging output"
    )

    # Configuration file
    config_group = parser.add_argument_group("Configuration")
    config_group.add_argument(
        "--config", "-c", help="Load configuration from file (YAML or JSON)"
    )
    config_group.add_argument(
        "--save-config", help="Save current configuration to file and exit"
    )
    config_group.add_argument(
        "--show-config", action="store_true", help="Show current configuration and exit"
    )

    return parser


def args_to_config_overrides(args) -> Dict[str, Any]:
    """Convert command line arguments to configuration overrides."""
    cli_overrides = {
        "transport": args.transport,
        "port": args.port,
        "host": args.host,
        "enable_tools": not args.disable_tools,
        "enable_prompts": not args.disable_prompts,
        "enable_resources": not args.disable_resources,
        "verbose": args.verbose,
        "quiet": args.quiet,
        "cache_strategy": args.cache_strategy,
        "cache_size": args.cache_size,
        "computation_timeout": args.timeout,
    }

    # Handle list arguments
    list_overrides = {}
    if args.functions:
        list_overrides["function_allowlist"] = args.functions
    if args.exclude_functions:
        list_overrides["function_denylist"] = args.exclude_functions
    if args.domains:
        list_overrides["domain_allowlist"] = args.domains
    if args.exclude_domains:
        list_overrides["domain_denylist"] = args.exclude_domains
    if args.categories:
        list_overrides["category_allowlist"] = args.categories
    if args.exclude_categories:
        list_overrides["category_denylist"] = args.exclude_categories

    # Handle log level
    if args.verbose:
        cli_overrides["log_level"] = "DEBUG"
    elif args.quiet:
        cli_overrides["log_level"] = "WARNING"

    # Merge with list overrides
    cli_overrides.update(list_overrides)

    # Filter out None values
    return {k: v for k, v in cli_overrides.items() if v is not None}


def check_dependencies():
    """Check and report on required dependencies."""
    # All dependencies are required and checked at import time
    # If we get here, they're all available
    return True


def run_server(config: MathServerConfig):
    """Run the server with the given configuration."""
    try:
        # Create and run server
        server = ConfigurableMCPMathServer(config)

        logger.info("✨ Configurable MCP Math Server starting...")
        logger.info(f"🎯 Transport: {config.transport}")
        if config.transport == "http":
            logger.info(f"🌐 Host: {config.host}:{config.port}")

        # Show filtering info
        stats = server.get_function_stats()
        if stats["filtering_active"]:
            logger.info(
                f"🔍 Function filtering active: {stats['total_filtered']}/{stats['total_available']} functions"
            )
        else:
            logger.info(f"📊 All {stats['total_available']} functions available")

        server.run()

    except KeyboardInterrupt:
        logger.info("🛑 Server interrupted by user")
    except Exception as e:
        logger.error(f"💥 Server failed: {e}")
        raise


def main():
    """Main entry point for the CLI."""
    parser = create_argument_parser()
    args = parser.parse_args()

    # Configure logging early for stdio mode to reduce noise
    # This happens before config loading to catch all import-time logs
    if args.transport == "stdio" and not args.verbose:
        # Set WARNING level for stdio to reduce noise
        logging.basicConfig(level=logging.WARNING, force=True)
        logging.getLogger("chuk_mcp_math").setLevel(logging.WARNING)
        logging.getLogger("chuk_mcp_math_server").setLevel(logging.WARNING)

    # Check dependencies first
    check_dependencies()

    try:
        # Load configuration
        cli_overrides = args_to_config_overrides(args)
        config = load_math_configuration_from_sources(
            config_file=args.config, cli_overrides=cli_overrides
        )

        # For stdio mode, default to WARNING level unless explicitly set
        if config.transport == "stdio" and not args.verbose and not args.quiet:
            config.log_level = "WARNING"

        # Handle special options
        if args.save_config:
            try:
                config.save_to_file(args.save_config)
                print(f"✅ Configuration saved to {args.save_config}")
                return
            except Exception as e:
                print(f"❌ Failed to save configuration: {e}")
                sys.exit(1)

        if args.show_config:
            print("📊 Current Configuration:")
            print(json.dumps(config.model_dump(), indent=2))
            return

        # Run the server
        run_server(config)

    except Exception as e:
        logger.error(f"💥 CLI failed: {e}")
        sys.exit(1)


if __name__ == "__main__":
    main()
