"""
Server configuration using pydantic_settings for clean environment and argument handling.
"""

import logging
import os
import sys
from enum import Enum
from pathlib import Path
from typing import Literal

from pydantic import AliasChoices, Field, field_validator
from pydantic_settings import BaseSettings, SettingsConfigDict

logger = logging.getLogger(__name__)


def _is_test_environment() -> bool:
    """Detect if we're running in a test environment where CLI parsing should be disabled."""
    # Check for pytest-related environment variables
    if "PYTEST_CURRENT_TEST" in os.environ:
        return True

    # Check if pytest is in the call stack
    for frame_info in sys._current_frames().values():
        frame = frame_info
        while frame:
            if "pytest" in frame.f_code.co_filename:
                return True
            frame = frame.f_back

    # Check if pytest modules are imported
    pytest_modules = ["pytest", "_pytest", "pluggy"]
    return any(module_name in sys.modules for module_name in pytest_modules)


class ServerMode(str, Enum):
    """Server operation modes with clear authentication and transport behavior."""

    STDIO = "stdio"  # stdio transport, no auth (default session only)
    HTTP_NO_AUTH = "http-no-auth"  # http transport, auth disabled (development)
    HTTP_AUTH = "http-auth"  # http transport, auth required (production)


class ServerConfig(BaseSettings):
    """
    Server configuration with automatic environment variable and argument parsing.

    Supports three clear server modes:
    - stdio: Development with Cursor IDE (no auth, default session only)
    - http-no-auth: Development HTTP server (auth disabled)
    - http-auth: Production HTTP server (auth required)
    """

    model_config = SettingsConfigDict(
        env_file=".env",
        env_file_encoding="utf-8",
        case_sensitive=False,
        extra="ignore",
        # Disable CLI parsing in test environments to avoid conflicts with pytest
        cli_parse_args=not _is_test_environment(),
        cli_kebab_case=True,
        cli_exit_on_error=not _is_test_environment(),  # Don't exit on error in tests
        cli_enforce_required=False,
    )

    # Server mode - determines transport and auth behavior
    server_mode: ServerMode = Field(
        default=ServerMode.STDIO,
        validation_alias=AliasChoices("mode", "server_mode"),
        description="Server operation mode: stdio (local dev), http-no-auth (dev server), http-auth (production)",
    )

    # Network configuration
    host: str = Field(
        default="127.0.0.1", description="Host to bind to (use 0.0.0.0 for production)"
    )

    port: int = Field(default=8000, ge=1, le=65535, description="Port to bind to")

    # Session configuration
    session_dir: str = Field(
        default="",
        description="Custom session directory (defaults to ~/.config/fast-mcp-telegram/)",
    )

    session_name: str = Field(
        default="telegram",
        description="Session file name (without .session extension) for stdio mode or custom sessions",
    )

    # Telegram API configuration
    api_id: str = Field(
        default="",
        description="Telegram API ID (get from https://my.telegram.org/apps)",
    )

    api_hash: str = Field(
        default="",
        description="Telegram API Hash (get from https://my.telegram.org/apps)",
    )

    phone_number: str = Field(
        default="",
        description="Phone number for Telegram authentication (include country code)",
    )

    # Web setup configuration
    domain: str = Field(
        default="your-domain.com",
        description="Domain for web setup and config generation",
    )

    # Session management
    max_active_sessions: int = Field(
        default=10, ge=1, description="Maximum number of active sessions in LRU cache"
    )

    setup_session_ttl_seconds: int = Field(
        default=900, ge=60, description="TTL for temporary setup sessions (seconds)"
    )

    entity_cache_limit: int = Field(
        default=1000,
        ge=1,
        description="Maximum number of entities to cache per Telegram client",
    )

    # File download security
    allow_http_urls: bool = Field(
        default=False, description="Allow HTTP URLs (insecure, only for development)"
    )
    max_file_size_mb: int = Field(
        default=50, description="Maximum file size for downloads (MB)"
    )
    block_private_ips: bool = Field(
        default=True, description="Block access to private IP ranges"
    )

    # Logging configuration
    log_level: str = Field(
        default="DEBUG", description="Logging level (DEBUG, INFO, WARNING, ERROR)"
    )

    # Backward compatibility: DISABLE_AUTH environment variable
    disable_auth_env: str | None = Field(
        default=None,
        validation_alias="DISABLE_AUTH",
        description="DISABLE_AUTH environment variable value",
    )

    @field_validator("host")
    @classmethod
    def validate_host(cls, v: str, info) -> str:
        """Set smart defaults for host based on server mode."""
        if not v or v == "127.0.0.1":
            # Get server_mode from values if available
            mode = info.data.get("server_mode", ServerMode.STDIO)
            if mode in (ServerMode.HTTP_AUTH, ServerMode.HTTP_NO_AUTH):
                return "0.0.0.0"  # Production HTTP should bind to all interfaces
        return v

    @property
    def transport(self) -> Literal["stdio", "http"]:
        """Transport type based on server mode."""
        if self.server_mode == ServerMode.STDIO:
            return "stdio"
        return "http"

    @property
    def disable_auth(self) -> bool:
        """Whether authentication is disabled."""
        # Check for DISABLE_AUTH environment variable first (backward compatibility)
        if self.disable_auth_env is not None and self.disable_auth_env.strip():
            # Parse string values to boolean
            env_value = self.disable_auth_env.lower().strip()
            if env_value in ("true", "1", "yes", "on"):
                return True
            if env_value in ("false", "0", "no", "off"):
                return False
            # Invalid values are ignored, fall through to server mode logic

        # Otherwise use server mode logic
        return self.server_mode in (ServerMode.STDIO, ServerMode.HTTP_NO_AUTH)

    @property
    def require_auth(self) -> bool:
        """Whether authentication is required (no fallback)."""
        return self.server_mode == ServerMode.HTTP_AUTH

    @property
    def session_directory(self) -> Path:
        """Get session directory with smart defaults."""
        if self.session_dir:
            return Path(self.session_dir)

        # Use standard user config directory
        config_dir = Path.home() / ".config" / "fast-mcp-telegram"
        config_dir.mkdir(parents=True, exist_ok=True)
        return config_dir

    @property
    def session_path(self) -> Path:
        """Get full session file path (without .session extension - Telethon adds it)."""
        return self.session_directory / self.session_name

    def validate_config(self) -> None:
        """Validate configuration and log important information."""
        # Prevent repeated logging by checking if already logged
        if hasattr(self, "_config_logged"):
            return

        logger.info(f"🚀 Server mode: {self.server_mode.value}")
        logger.info(f"🌐 Transport: {self.transport}")

        if self.transport == "http":
            logger.info(f"🔗 Binding to {self.host}:{self.port}")

        if self.server_mode == ServerMode.STDIO:
            logger.info("🔓 Authentication DISABLED - Default session only")
        elif self.server_mode == ServerMode.HTTP_NO_AUTH:
            logger.info("🔓 Authentication DISABLED for development mode")
        elif self.require_auth:
            logger.info("🔐 Authentication REQUIRED - Bearer token mandatory")

        logger.info(f"📁 Session directory: {self.session_directory}")

        # Mark as logged to prevent repeated messages
        self._config_logged = True

        # Validation warnings
        if self.transport == "stdio" and self.host != "127.0.0.1":
            logger.warning("⚠️ stdio transport ignores host setting")

        if self.server_mode == ServerMode.HTTP_AUTH and not self.api_id:
            logger.warning(
                "⚠️ Production mode without API credentials - ensure they're available for setup"
            )

    @classmethod
    def from_args_and_env(cls) -> "ServerConfig":
        """Create configuration from command line arguments and environment variables.

        With native CLI parsing, this simply creates the config instance.
        pydantic-settings automatically handles CLI args, env vars, and .env files.
        """
        config = cls()
        config.validate_config()
        return config


# Global configuration instance
_config: ServerConfig | None = None


def get_config() -> ServerConfig:
    """Get the global server configuration instance."""
    global _config
    if _config is None:
        _config = ServerConfig.from_args_and_env()
    return _config


def set_config(config: ServerConfig) -> None:
    """Set the global server configuration instance (for testing)."""
    global _config
    _config = config
