"""CLI entry point for MCP Proxy.

This module provides the command-line interface for running the MCP Proxy
as a standalone process with argparse-based configuration options.

Requirements satisfied:
- 7.4: Support environment variable configuration
- 7.5: Provide default values for optional configuration parameters
"""

import argparse
import asyncio
import os
import sys
from typing import Optional

from .proxy import McpProxy
from .models import ProxyConfig
from .logging_config import get_logger, configure_logging
from .exceptions import ConfigurationError

# Version information
__version__ = "0.1.0"

logger = get_logger(__name__)


def create_parser() -> argparse.ArgumentParser:
    """Create and configure the argument parser.
    
    Returns:
        Configured ArgumentParser instance
    """
    parser = argparse.ArgumentParser(
        prog="mcp-proxy",
        description=(
            "MCP Proxy with OAuth Dynamic Client Registration support. "
            "Translates between stdio MCP (for Kiro) and HTTP streamable MCP "
            "(for backend servers) while managing OAuth DCR authentication."
        ),
        epilog=(
            "Configuration can be provided via command-line arguments or "
            "environment variables. Command-line arguments take precedence. "
            "Environment variables: MCP_SERVER_URL, OAUTH_PROVIDER_URL, "
            "MCP_CLIENT_NAME, MCP_SCOPES, MCP_CONNECTION_TIMEOUT, "
            "MCP_RETRY_ATTEMPTS, MCP_LOG_LEVEL, MCP_MAX_BACKOFF_SECONDS"
        ),
        formatter_class=argparse.RawDescriptionHelpFormatter,
    )
    
    # Version information
    parser.add_argument(
        "--version",
        action="version",
        version=f"%(prog)s {__version__}",
        help="Show version information and exit",
    )
    
    # Required configuration (can also come from environment variables)
    parser.add_argument(
        "--mcp-server-url",
        type=str,
        default=None,
        metavar="URL",
        help=(
            "URL of the HTTP MCP server to connect to "
            "(env: MCP_SERVER_URL, required if not set via environment)"
        ),
    )
    
    parser.add_argument(
        "--oauth-provider-url",
        type=str,
        default=None,
        metavar="URL",
        help=(
            "URL of the OAuth provider for DCR "
            "(env: OAUTH_PROVIDER_URL, required if not set via environment)"
        ),
    )
    
    # Optional configuration
    parser.add_argument(
        "--client-name",
        type=str,
        default=None,
        metavar="NAME",
        help=(
            "OAuth client name for DCR "
            "(env: MCP_CLIENT_NAME, default: mcp-proxy-client)"
        ),
    )
    
    parser.add_argument(
        "--scopes",
        type=str,
        default=None,
        metavar="SCOPE1,SCOPE2",
        help=(
            "Comma-separated list of OAuth scopes "
            "(env: MCP_SCOPES, default: mcp:read,mcp:write)"
        ),
    )
    
    parser.add_argument(
        "--connection-timeout",
        type=int,
        default=None,
        metavar="SECONDS",
        help=(
            "HTTP connection timeout in seconds "
            "(env: MCP_CONNECTION_TIMEOUT, default: 30)"
        ),
    )
    
    parser.add_argument(
        "--retry-attempts",
        type=int,
        default=None,
        metavar="COUNT",
        help=(
            "Number of retry attempts for failed requests "
            "(env: MCP_RETRY_ATTEMPTS, default: 3)"
        ),
    )
    
    parser.add_argument(
        "--max-backoff",
        type=int,
        default=None,
        metavar="SECONDS",
        help=(
            "Maximum backoff time in seconds for retries "
            "(env: MCP_MAX_BACKOFF_SECONDS, default: 60)"
        ),
    )
    
    parser.add_argument(
        "--log-level",
        type=str,
        choices=["debug", "info", "warn", "error"],
        default=None,
        metavar="LEVEL",
        help=(
            "Logging level (debug, info, warn, error) "
            "(env: MCP_LOG_LEVEL, default: info)"
        ),
    )
    
    # Operational flags
    parser.add_argument(
        "--validate-config",
        action="store_true",
        help="Validate configuration and exit without starting the proxy",
    )
    
    parser.add_argument(
        "--show-config",
        action="store_true",
        help="Show the effective configuration and exit",
    )
    
    return parser


def load_config_from_args(args: argparse.Namespace) -> Optional[ProxyConfig]:
    """Load configuration from command-line arguments and environment variables.
    
    Command-line arguments take precedence over environment variables.
    If neither is provided for required parameters, returns None to trigger
    the default environment-based loading in ConfigurationManager.
    
    Args:
        args: Parsed command-line arguments
        
    Returns:
        ProxyConfig if sufficient configuration is provided, None otherwise
        
    Raises:
        ConfigurationError: If configuration is invalid
    """
    # Get MCP server URL (CLI arg or env var)
    mcp_server_url = args.mcp_server_url or os.getenv("MCP_SERVER_URL")
    
    # Get OAuth provider URL (CLI arg or env var)
    oauth_provider_url = args.oauth_provider_url or os.getenv("OAUTH_PROVIDER_URL")
    
    # If required parameters are missing, return None to use default loading
    if not mcp_server_url or not oauth_provider_url:
        return None
    
    # Build configuration dictionary
    config_dict = {
        "mcp_server_url": mcp_server_url,
        "oauth_provider_url": oauth_provider_url,
    }
    
    # Optional parameters (CLI args take precedence over env vars)
    if args.client_name:
        config_dict["client_name"] = args.client_name
    elif os.getenv("MCP_CLIENT_NAME"):
        config_dict["client_name"] = os.getenv("MCP_CLIENT_NAME")
    
    if args.scopes:
        config_dict["scopes"] = [s.strip() for s in args.scopes.split(",") if s.strip()]
    elif os.getenv("MCP_SCOPES"):
        scopes_str = os.getenv("MCP_SCOPES")
        config_dict["scopes"] = [s.strip() for s in scopes_str.split(",") if s.strip()]
    
    if args.connection_timeout is not None:
        config_dict["connection_timeout"] = args.connection_timeout
    elif os.getenv("MCP_CONNECTION_TIMEOUT"):
        try:
            config_dict["connection_timeout"] = int(os.getenv("MCP_CONNECTION_TIMEOUT"))
        except ValueError:
            raise ConfigurationError(
                f"Invalid MCP_CONNECTION_TIMEOUT: {os.getenv('MCP_CONNECTION_TIMEOUT')}"
            )
    
    if args.retry_attempts is not None:
        config_dict["retry_attempts"] = args.retry_attempts
    elif os.getenv("MCP_RETRY_ATTEMPTS"):
        try:
            config_dict["retry_attempts"] = int(os.getenv("MCP_RETRY_ATTEMPTS"))
        except ValueError:
            raise ConfigurationError(
                f"Invalid MCP_RETRY_ATTEMPTS: {os.getenv('MCP_RETRY_ATTEMPTS')}"
            )
    
    if args.max_backoff is not None:
        config_dict["max_backoff_seconds"] = args.max_backoff
    elif os.getenv("MCP_MAX_BACKOFF_SECONDS"):
        try:
            config_dict["max_backoff_seconds"] = int(os.getenv("MCP_MAX_BACKOFF_SECONDS"))
        except ValueError:
            raise ConfigurationError(
                f"Invalid MCP_MAX_BACKOFF_SECONDS: {os.getenv('MCP_MAX_BACKOFF_SECONDS')}"
            )
    
    if args.log_level:
        config_dict["log_level"] = args.log_level
    elif os.getenv("MCP_LOG_LEVEL"):
        config_dict["log_level"] = os.getenv("MCP_LOG_LEVEL")
    
    try:
        return ProxyConfig(**config_dict)
    except Exception as e:
        raise ConfigurationError(f"Invalid configuration: {e}")


def show_config(config: ProxyConfig) -> None:
    """Display the effective configuration.
    
    Args:
        config: Configuration to display
    """
    print("MCP Proxy Configuration")
    print("=" * 60)
    print(f"MCP Server URL:        {config.mcp_server_url}")
    print(f"OAuth Provider URL:    {config.oauth_provider_url}")
    print(f"Client Name:           {config.client_name}")
    print(f"Scopes:                {', '.join(config.scopes)}")
    print(f"Connection Timeout:    {config.connection_timeout}s")
    print(f"Retry Attempts:        {config.retry_attempts}")
    print(f"Max Backoff:           {config.max_backoff_seconds}s")
    print(f"Log Level:             {config.log_level}")
    print("=" * 60)


async def main() -> int:
    """Main entry point for the MCP Proxy CLI.
    
    Returns:
        Exit code (0 for success, non-zero for error)
    """
    # Parse command-line arguments
    parser = create_parser()
    args = parser.parse_args()
    
    # Set up logging early if specified
    if args.log_level:
        configure_logging(args.log_level)
    
    try:
        # Load configuration from CLI args and environment
        config = load_config_from_args(args)
        
        # Handle --validate-config flag
        if args.validate_config:
            if config is None:
                # Try to load from environment using ConfigurationManager
                from .config.manager import ConfigurationManagerImpl
                config_manager = ConfigurationManagerImpl()
                config = await config_manager.load()
            
            print("Configuration is valid ✓")
            show_config(config)
            return 0
        
        # Handle --show-config flag
        if args.show_config:
            if config is None:
                # Try to load from environment using ConfigurationManager
                from .config.manager import ConfigurationManagerImpl
                config_manager = ConfigurationManagerImpl()
                config = await config_manager.load()
            
            show_config(config)
            return 0
        
        # Create and run the proxy
        logger.info("Starting MCP Proxy")
        proxy = McpProxy(config=config)
        await proxy.run()
        return 0
        
    except KeyboardInterrupt:
        logger.info("Received keyboard interrupt, shutting down")
        return 0
    
    except ConfigurationError as e:
        logger.error(f"Configuration error: {e}")
        print(f"\nError: {e}", file=sys.stderr)
        print("\nUse --help for usage information", file=sys.stderr)
        return 1
        
    except Exception as e:
        logger.error(f"Fatal error: {e}", exc_info=True)
        print(f"\nFatal error: {e}", file=sys.stderr)
        return 1


def cli_main() -> None:
    """CLI entry point wrapper for setuptools."""
    exit_code = asyncio.run(main())
    sys.exit(exit_code)


if __name__ == "__main__":
    cli_main()
