#!/usr/bin/env python3
"""
CLI Utility for MCP Proxy Adapter Configuration Builder
Command-line interface for creating configurations with various parameters.

Author: Vasiliy Zdanovskiy
email: vasilyvz@gmail.com
"""
import argparse
import json
import sys
from pathlib import Path

from typing import Any, Dict, List

from mcp_proxy_adapter.examples.config_factory import (
    create_full_featured,
    create_http_simple,
    create_http_token,
    create_https_simple,
    create_https_token,
    create_mtls_simple,
    create_mtls_with_roles,
    create_mtls_with_proxy,
)


def parse_api_keys(api_keys_str: str) -> Dict[str, str]:
    """Parse API keys from string format 'key1:value1,key2:value2'."""
    if not api_keys_str:
        return {}

    api_keys = {}
    for pair in api_keys_str.split(","):
        if ":" not in pair:
            raise ValueError(f"Invalid API key format: {pair}. Expected 'key:value'")
        key, value = pair.split(":", 1)
        api_keys[key.strip()] = value.strip()

    return api_keys


def parse_roles(roles_str: str) -> Dict[str, List[str]]:
    """Parse roles from string format 'role1:perm1,perm2;role2:perm3,perm4'."""
    if not roles_str:
        return {}

    roles = {}
    for role_def in roles_str.split(";"):
        if ":" not in role_def:
            raise ValueError(
                f"Invalid role format: {role_def}. Expected 'role:perm1,perm2'"
            )
        role, perms = role_def.split(":", 1)
        roles[role.strip()] = [perm.strip() for perm in perms.split(",")]

    return roles


def create_custom_config(args: argparse.Namespace) -> Dict[str, Any]:
    """Create custom configuration from CLI args using config_factory."""
    log_dir = getattr(args, "log_dir", "./logs")
    cert_dir = getattr(args, "cert_dir", "./certs")
    key_dir = getattr(args, "key_dir", "./keys")
    host = getattr(args, "host", "0.0.0.0")
    port = getattr(args, "port", 8000)
    protocol = getattr(args, "protocol", "http")
    use_token = getattr(args, "auth", "none") == "token" or bool(
        getattr(args, "api_keys", None)
    )
    api_keys = parse_api_keys(getattr(args, "api_keys", "") or "")
    roles = parse_roles(getattr(args, "roles", "") or "")

    if protocol == "http":
        if use_token:
            return create_http_token(
                port=port, log_dir=log_dir, host=host, api_keys=api_keys or None
            )
        return create_http_simple(port=port, log_dir=log_dir, host=host)
    if protocol == "https":
        if use_token:
            return create_https_token(
                port=port,
                log_dir=log_dir,
                host=host,
                cert_dir=cert_dir,
                key_dir=key_dir,
                api_keys=api_keys or None,
            )
        return create_https_simple(
            port=port,
            log_dir=log_dir,
            host=host,
            cert_dir=cert_dir,
            key_dir=key_dir,
        )
    if protocol == "mtls":
        if getattr(args, "proxy_url", None):
            return create_mtls_with_proxy(
                port=port,
                log_dir=log_dir,
                host=host,
                cert_dir=cert_dir,
                key_dir=key_dir,
                proxy_url=args.proxy_url,
                server_id=getattr(args, "server_id", "mcp_proxy_adapter"),
            )
        if use_token or roles:
            return create_mtls_with_roles(
                port=port,
                log_dir=log_dir,
                host=host,
                cert_dir=cert_dir,
                key_dir=key_dir,
                roles=roles or None,
            )
        return create_mtls_simple(
            port=port,
            log_dir=log_dir,
            host=host,
            cert_dir=cert_dir,
            key_dir=key_dir,
        )
    raise ValueError(f"Unsupported protocol: {protocol}")


def create_preset_config(preset: str, **kwargs: Any) -> Dict[str, Any]:
    """Create preset configuration using config_factory."""
    preset_map = {
        "http_simple": create_http_simple,
        "http_token": create_http_token,
        "https_simple": create_https_simple,
        "https_token": create_https_token,
        "mtls_simple": create_mtls_simple,
        "mtls_with_roles": create_mtls_with_roles,
        "mtls_with_proxy": create_mtls_with_proxy,
        "full_featured": create_full_featured,
    }
    if preset not in preset_map:
        raise ValueError(
            f"Invalid preset: {preset}. Must be one of: {list(preset_map.keys())}"
        )
    return preset_map[preset](**kwargs)


def list_presets():
    """List available presets."""
    presets = [
        ("http_simple", "Simple HTTP server without authentication"),
        ("http_token", "HTTP server with token authentication"),
        ("https_simple", "Simple HTTPS server without authentication"),
        ("https_token", "HTTPS server with token authentication"),
        ("mtls_simple", "Simple mTLS server without authentication"),
        ("mtls_with_roles", "mTLS server with role-based access control"),
        ("mtls_with_proxy", "mTLS server with proxy registration"),
        ("full_featured", "Full-featured server with all options enabled"),
    ]

    print("📋 Available Configuration Presets:")
    print("=" * 50)
    for preset, description in presets:
        print(f"  {preset:<20} - {description}")


def main():
    """Main CLI function."""
    parser = argparse.ArgumentParser(
        description="MCP Proxy Adapter Configuration Builder CLI",
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="""
Examples:
  # Create HTTP simple configuration
  python config_cli.py --preset http_simple --output configs/http_simple.json
  
  # Create custom HTTPS configuration with token auth
  python config_cli.py --protocol https --auth token --api-keys "admin:admin-key,user:user-key" --output configs/https_token.json
  
  # Create mTLS configuration with proxy registration
  python config_cli.py --protocol mtls --proxy-url "https://proxy.example.com:8080" --server-id "my_server" --output configs/mtls_proxy.json
  
  # List all available presets
  python config_cli.py --list-presets
        """,
    )

    # Main options
    parser.add_argument("--preset", help="Use a preset configuration")
    parser.add_argument(
        "--list-presets", action="store_true", help="List available presets"
    )
    parser.add_argument("--output", "-o", help="Output file path (default: stdout)")

    # Server configuration
    parser.add_argument(
        "--host", default="0.0.0.0", help="Server host (default: 0.0.0.0)"
    )
    parser.add_argument(
        "--port", type=int, default=8000, help="Server port (default: 8000)"
    )
    parser.add_argument("--debug", action="store_true", help="Enable debug mode")
    parser.add_argument(
        "--log-level",
        default="INFO",
        choices=["DEBUG", "INFO", "WARNING", "ERROR"],
        help="Log level (default: INFO)",
    )

    # Logging configuration
    parser.add_argument(
        "--log-dir", default="./logs", help="Log directory (default: ./logs)"
    )
    parser.add_argument(
        "--no-console", action="store_true", help="Disable console output"
    )
    parser.add_argument(
        "--no-file-log", action="store_true", help="Disable file logging"
    )

    # Protocol configuration
    parser.add_argument(
        "--protocol",
        choices=["http", "https", "mtls"],
        default="http",
        help="Protocol (default: http)",
    )
    parser.add_argument(
        "--cert-dir", default="./certs", help="Certificate directory (default: ./certs)"
    )
    parser.add_argument(
        "--key-dir", default="./keys", help="Key directory (default: ./keys)"
    )

    # Authentication configuration
    parser.add_argument(
        "--auth",
        choices=["none", "token", "basic"],
        default="none",
        help="Authentication method (default: none)",
    )
    parser.add_argument(
        "--api-keys", help="API keys in format 'key1:value1,key2:value2'"
    )
    parser.add_argument(
        "--roles", help="Roles in format 'role1:perm1,perm2;role2:perm3,perm4'"
    )

    # Proxy registration
    parser.add_argument("--proxy-url", help="Proxy URL for registration")
    parser.add_argument(
        "--server-id",
        default="mcp_proxy_adapter",
        help="Server ID for proxy registration (default: mcp_proxy_adapter)",
    )

    # Commands configuration
    parser.add_argument(
        "--enabled-commands", help="Comma-separated list of enabled commands"
    )
    parser.add_argument(
        "--disabled-commands", help="Comma-separated list of disabled commands"
    )

    # Preset-specific options
    parser.add_argument("--preset-host", help="Host for preset configurations")
    parser.add_argument(
        "--preset-port", type=int, help="Port for preset configurations"
    )
    parser.add_argument(
        "--preset-log-dir", help="Log directory for preset configurations"
    )
    parser.add_argument(
        "--preset-cert-dir", help="Certificate directory for preset configurations"
    )
    parser.add_argument(
        "--preset-key-dir", help="Key directory for preset configurations"
    )
    parser.add_argument(
        "--preset-proxy-url", help="Proxy URL for preset configurations"
    )
    parser.add_argument(
        "--preset-server-id", help="Server ID for preset configurations"
    )

    args = parser.parse_args()

    try:
        # Handle list presets
        if args.list_presets:
            list_presets()
            return 0

        # Create configuration
        if args.preset:
            # Use preset configuration
            preset_kwargs = {}
            if args.preset_host:
                preset_kwargs["host"] = args.preset_host
            if args.preset_port:
                preset_kwargs["port"] = args.preset_port
            if args.preset_log_dir:
                preset_kwargs["log_dir"] = args.preset_log_dir
            if args.preset_cert_dir:
                preset_kwargs["cert_dir"] = args.preset_cert_dir
            if args.preset_key_dir:
                preset_kwargs["key_dir"] = args.preset_key_dir
            if args.preset_proxy_url:
                preset_kwargs["proxy_url"] = args.preset_proxy_url
            if args.preset_server_id:
                preset_kwargs["server_id"] = args.preset_server_id

            config = create_preset_config(args.preset, **preset_kwargs)
        else:
            # Create custom configuration
            config = create_custom_config(args)

        # Output configuration
        config_json = json.dumps(config, indent=2, ensure_ascii=False)

        if args.output:
            output_path = Path(args.output)
            output_path.parent.mkdir(parents=True, exist_ok=True)
            with open(output_path, "w", encoding="utf-8") as f:
                f.write(config_json)
            print(f"✅ Configuration saved to: {output_path}")
        else:
            print(config_json)

        return 0

    except Exception as e:
        print(f"❌ Error: {e}", file=sys.stderr)
        return 1


if __name__ == "__main__":
    sys.exit(main())
