"""Application configuration using Pydantic Settings."""

import logging
import os
from pathlib import Path

from pydantic import Field
from pydantic_settings import BaseSettings, SettingsConfigDict
from typing_extensions import List, Optional

from config.enhanced_logging import setup_logger

logger = setup_logger()
from urllib.parse import urlparse

# Lazy import for compatibility shim to avoid circular imports
_COMPATIBILITY_AVAILABLE = None  # Will be checked lazily


class Settings(BaseSettings):
    """Application configuration using Pydantic Settings"""

    # OAuth Configuration (either use JSON file OR individual credentials)
    google_client_secrets_file: str = ""  # Path to client_secret.json file
    google_client_id: str = ""
    google_client_secret: str = ""
    oauth_redirect_uri: str = "http://localhost:8002/oauth2callback"

    # Server Configuration
    server_port: int = 8002
    server_host: str = "localhost"
    server_name: str = "Google Drive Upload Server"

    # HTTPS/SSL Configuration
    # Default to False for Docker compatibility - explicitly enable via .env when needed
    enable_https: bool = False
    ssl_cert_file: str = ""  # Path to SSL certificate (e.g., "./localhost+2.pem")
    ssl_key_file: str = ""  # Path to SSL private key (e.g., "./localhost+2-key.pem")
    ssl_ca_file: str = ""  # Optional CA file for client certificate verification

    # Storage Configuration
    credentials_dir: str = str(Path(__file__).parent.parent / "credentials")
    credential_storage_mode: str = "FILE_ENCRYPTED"
    chat_service_account_file: str = ""

    @property
    def is_cloud_deployment(self) -> bool:
        """Detect if running in FastMCP Cloud."""
        return os.getenv("FASTMCP_CLOUD", "false").lower() in ("true", "1", "yes", "on")

    # Qdrant Configuration
    qdrant_url: str = "http://localhost:6333"
    qdrant_key: str = "NONE"
    qdrant_host: Optional[str] = None  # Will be set from qdrant_url
    qdrant_port: Optional[int] = None  # Will be set from qdrant_url
    qdrant_api_key: Optional[str] = None  # Will be set from qdrant_key
    qdrant_prefer_grpc: bool = (
        True  # Use gRPC to avoid SSL certificate issues with cloud Qdrant
    )

    # Primary Qdrant collection for MCP tool responses / analytics
    tool_collection: str = Field(
        default="mcp_tool_responses",
        description="Primary Qdrant collection for MCP tool responses and analytics",
        json_schema_extra={"env": "TOOL_COLLECTION"},
    )

    # Qdrant Docker Auto-Launch Configuration
    # When enabled, automatically launches Qdrant via Docker if not reachable
    qdrant_auto_launch: bool = Field(
        default=True,
        description="Automatically launch Qdrant via Docker if not reachable (local URLs only)",
        json_schema_extra={"env": "QDRANT_AUTO_LAUNCH"},
    )
    qdrant_docker_image: str = Field(
        default="qdrant/qdrant:latest",
        description="Docker image for Qdrant container",
        json_schema_extra={"env": "QDRANT_DOCKER_IMAGE"},
    )
    qdrant_docker_container_name: str = Field(
        default="mcp-qdrant",
        description="Name for the Qdrant Docker container",
        json_schema_extra={"env": "QDRANT_DOCKER_CONTAINER_NAME"},
    )
    qdrant_docker_grpc_port: int = Field(
        default=6334,
        description="gRPC port to expose for Qdrant container",
        json_schema_extra={"env": "QDRANT_DOCKER_GRPC_PORT"},
    )
    qdrant_docker_data_dir: str = Field(
        default="",
        description="Persistent data directory for Qdrant. If empty, uses credentials_dir/qdrant_data",
        json_schema_extra={"env": "QDRANT_DOCKER_DATA_DIR"},
    )
    qdrant_docker_startup_timeout: int = Field(
        default=30,
        description="Seconds to wait for Qdrant container to become ready",
        json_schema_extra={"env": "QDRANT_DOCKER_STARTUP_TIMEOUT"},
    )
    qdrant_docker_stop_on_exit: bool = Field(
        default=False,
        description="Stop Qdrant container when MCP server exits (only if we started it)",
        json_schema_extra={"env": "QDRANT_DOCKER_STOP_ON_EXIT"},
    )

    # Logging
    log_level: str = "INFO"

    # Security
    session_timeout_minutes: int = 60

    # Gmail Allow List Configuration
    gmail_allow_list: str = ""  # Comma-separated list of email addresses

    # Gmail Elicitation Configuration (for MCP client compatibility)
    gmail_enable_elicitation: bool = True  # Enable elicitation for untrusted recipients
    gmail_elicitation_fallback: str = (
        "block"  # What to do if elicitation fails: "block", "allow", "draft"
    )

    # Qdrant Tool Response Collection Cache Configuration
    mcp_tool_responses_collection_cache_days: int = 5  # Default to 14 days retention

    # Sampling Tools Configuration
    sampling_tools: bool = False  # Enable sampling middleware tools (default: False)

    # Minimal Tools Startup Configuration
    # When enabled, server starts with only essential tools (protected infra tools)
    # Clients can enable tools as needed, and their state persists across reconnects
    minimal_tools_startup: bool = Field(
        default=False,
        description="Start server with minimal tools enabled. New sessions get bare minimum, reconnecting sessions restore their previous tool state.",
        json_schema_extra={"env": "MINIMAL_TOOLS_STARTUP"},
    )

    # Session tool state persistence file location
    session_tool_state_file: str = Field(
        default="",
        description="Path to JSON file for persisting session tool states across server restarts. If empty, uses credentials_dir/session_tool_states.json",
        json_schema_extra={"env": "SESSION_TOOL_STATE_FILE"},
    )

    # Default enabled services for minimal startup mode
    # Comma-separated list of service names from ScopeRegistry (e.g., "drive,gmail,calendar")
    # When minimal_tools_startup is enabled, tools for these services will be enabled by default
    # If empty, only protected infrastructure tools are enabled
    minimal_startup_services: str = Field(
        default="",
        description="Comma-separated list of services to enable by default in minimal startup mode (e.g., 'drive,gmail'). Empty = only protected tools.",
        json_schema_extra={"env": "MINIMAL_STARTUP_SERVICES"},
    )

    # ColBERT Embedding Configuration (Development/Testing)
    colbert_embedding_dev: bool = Field(
        default=False,
        description="Enable ColBERT multi-vector embeddings initialization on startup for development/testing",
        json_schema_extra={"env": "COLBERT_EMBEDDING_DEV"},
    )

    # Google Chat Card Collection Configuration
    # v7 collection has three named vectors:
    #   - components: Identity (Name + Type + Path + Docstring)
    #   - inputs: Values (defaults, enums, instance_params)
    #   - relationships: Graph (parent-child connections)
    card_collection: str = Field(
        default="mcp_gchat_cards_v7",
        description="Qdrant collection for Google Chat card components, templates, and feedback patterns",
        json_schema_extra={"env": "CARD_COLLECTION"},
    )

    # Component Relationship Collection Configuration
    relationship_collection: str = Field(
        default="mcp_component_relationships",
        description="Qdrant collection for card component relationships (parent→child paths)",
        json_schema_extra={"env": "RELATIONSHIP_COLLECTION"},
    )

    # Google Chat Default Webhook URL
    # When set, this becomes the default webhook for all card tools (send_dynamic_card, etc.)
    # Useful for development/testing when you always want to send to the same space
    mcp_chat_webhook: str = Field(
        default="",
        description="Default Google Chat webhook URL for card tools. When set, card tools use this as the default webhook_url parameter.",
        json_schema_extra={"env": "MCP_CHAT_WEBHOOK"},
    )

    # Phase 1 OAuth Migration Feature Flags
    enable_unified_auth: bool = True
    legacy_compat_mode: bool = True
    credential_migration: bool = True
    service_caching: bool = True
    enhanced_logging: bool = True

    # Security Configuration
    auth_security_level: str = Field(
        default="standard",
        description="Authentication security level: 'standard', 'high', or 'custom'",
        json_schema_extra={"env": "AUTH_SECURITY_LEVEL"},
    )

    # Template Configuration
    jinja_template_strict_mode: bool = Field(
        default=True,
        description="When enabled, template processing errors will cause tool execution to fail instead of just logging the error",
        json_schema_extra={"env": "JINJA_TEMPLATE_STRICT_MODE"},
    )

    # FastMCP 2.12.0 GoogleProvider Configuration
    fastmcp_server_auth: str = ""
    fastmcp_server_auth_google_client_id: str = ""
    fastmcp_server_auth_google_client_secret: str = ""
    fastmcp_server_auth_google_base_url: str = ""

    # Legacy OAuth scopes - maintained for backward compatibility
    # These are now managed through the centralized scope registry
    _fallback_drive_scopes: list[str] = [
        # Base OAuth scopes for user identification
        "https://www.googleapis.com/auth/userinfo.email",
        "https://www.googleapis.com/auth/userinfo.profile",
        "openid",
        # Google Drive scopes
        "https://www.googleapis.com/auth/drive",
        "https://www.googleapis.com/auth/drive.readonly",
        "https://www.googleapis.com/auth/drive.file",
        # Google Docs scopes
        "https://www.googleapis.com/auth/documents.readonly",
        "https://www.googleapis.com/auth/documents",
        # Gmail API scopes
        "https://www.googleapis.com/auth/gmail.readonly",
        "https://www.googleapis.com/auth/gmail.send",
        "https://www.googleapis.com/auth/gmail.compose",
        "https://www.googleapis.com/auth/gmail.modify",
        "https://www.googleapis.com/auth/gmail.labels",
        # Gmail Settings scopes (CRITICAL for filters/forwarding)
        "https://www.googleapis.com/auth/gmail.settings.basic",
        "https://www.googleapis.com/auth/gmail.settings.sharing",
        # Google Chat API scopes
        "https://www.googleapis.com/auth/chat.messages.readonly",
        "https://www.googleapis.com/auth/chat.messages",
        "https://www.googleapis.com/auth/chat.spaces",
        # Google Sheets API scopes
        "https://www.googleapis.com/auth/spreadsheets.readonly",
        "https://www.googleapis.com/auth/spreadsheets",
        # Google Forms API scopes
        "https://www.googleapis.com/auth/forms.body",
        "https://www.googleapis.com/auth/forms.body.readonly",
        "https://www.googleapis.com/auth/forms.responses.readonly",
        # Google Slides API scopes
        "https://www.googleapis.com/auth/presentations",
        "https://www.googleapis.com/auth/presentations.readonly",
        # Calendar scopes
        "https://www.googleapis.com/auth/calendar.readonly",
        "https://www.googleapis.com/auth/calendar.events",
        "https://www.googleapis.com/auth/calendar",
        # Google Photos Library API scopes
        "https://www.googleapis.com/auth/photoslibrary.readonly",
        "https://www.googleapis.com/auth/photoslibrary.appendonly",
        "https://www.googleapis.com/auth/photoslibrary",
        "https://www.googleapis.com/auth/photoslibrary.sharing",
        "https://www.googleapis.com/auth/photoslibrary.readonly.appcreateddata",
        "https://www.googleapis.com/auth/photoslibrary.edit.appcreateddata",
        # Cloud Platform scopes (for broader Google services)
        "https://www.googleapis.com/auth/cloud-platform",
        "https://www.googleapis.com/auth/cloudfunctions",
        "https://www.googleapis.com/auth/pubsub",
        "https://www.googleapis.com/auth/iam",
    ]

    @property
    def drive_scopes(self) -> list[str]:
        """
        Get OAuth scopes for Google services.

        This property uses the centralized scope registry as the single source of truth,
        ensuring consistency across the application and avoiding problematic scopes.

        Returns:
            List of OAuth scope URLs from oauth_comprehensive group
        """
        try:
            # Use the scope registry directly as single source of truth
            from auth.scope_registry import ScopeRegistry

            scopes = ScopeRegistry.resolve_scope_group("oauth_comprehensive")
            logging.debug(
                f"SCOPE_DEBUG: Retrieved {len(scopes)} scopes from oauth_comprehensive group"
            )

            # Verify no problematic scopes are included
            problematic_patterns = [
                "photoslibrary.sharing",
                "cloud-platform",
                "cloudfunctions",
                "pubsub",
                "iam",
            ]
            problematic_scopes = [
                scope
                for scope in scopes
                if any(bad in scope for bad in problematic_patterns)
            ]

            if problematic_scopes:
                logging.error(
                    f"SCOPE_DEBUG: Found {len(problematic_scopes)} problematic scopes in oauth_comprehensive"
                )
                for scope in problematic_scopes:
                    logging.error(f"SCOPE_DEBUG: Problematic scope: {scope}")
            else:
                logging.debug(
                    "SCOPE_DEBUG: No problematic scopes found - using clean oauth_comprehensive group"
                )

            # Check if Gmail settings scopes are included
            gmail_settings_basic = (
                "https://www.googleapis.com/auth/gmail.settings.basic"
            )
            gmail_settings_sharing = (
                "https://www.googleapis.com/auth/gmail.settings.sharing"
            )
            has_settings_basic = gmail_settings_basic in scopes
            has_settings_sharing = gmail_settings_sharing in scopes
            logging.debug(
                f"SCOPE_DEBUG: Gmail settings.basic included: {has_settings_basic}"
            )
            logging.debug(
                f"SCOPE_DEBUG: Gmail settings.sharing included: {has_settings_sharing}"
            )

            return scopes

        except Exception as e:
            logging.error(
                f"SCOPE_DEBUG: Error getting scopes from registry, using minimal fallback: {e}"
            )
            # Use a minimal fallback that excludes problematic scopes
            minimal_scopes = [
                "https://www.googleapis.com/auth/userinfo.email",
                "https://www.googleapis.com/auth/userinfo.profile",
                "openid",
                "https://www.googleapis.com/auth/drive",
                "https://www.googleapis.com/auth/gmail.readonly",
                "https://www.googleapis.com/auth/gmail.send",
                "https://www.googleapis.com/auth/calendar",
                "https://www.googleapis.com/auth/documents",
                "https://www.googleapis.com/auth/spreadsheets",
                "https://www.googleapis.com/auth/presentations",
            ]
            logging.warning(
                f"SCOPE_DEBUG: Using minimal fallback with {len(minimal_scopes)} scopes"
            )
            return minimal_scopes
            return self._fallback_drive_scopes

    model_config = SettingsConfigDict(
        env_file=str(Path(__file__).parent.parent / ".env"),
        env_file_encoding="utf-8",
        case_sensitive=False,
        extra="ignore",  # Ignore extra fields like TEST_EMAIL_ADDRESS
    )

    def __init__(self, **kwargs):
        super().__init__(**kwargs)

        # DEBUG: Log environment variable loading
        import os

        env_qdrant_url = os.getenv("QDRANT_URL")
        env_qdrant_key = os.getenv("QDRANT_KEY")
        logging.debug(
            f"🔧 SETTINGS DEBUG - Environment variables: QDRANT_URL='{env_qdrant_url}', QDRANT_KEY={'***' if env_qdrant_key else 'None'}"
        )
        logging.debug(
            f"🔧 SETTINGS DEBUG - Settings fields: qdrant_url='{self.qdrant_url}', qdrant_key={'***' if self.qdrant_key and self.qdrant_key != 'NONE' else 'None'}"
        )

        # DEBUG: Log FastMCP GoogleProvider environment variable loading
        env_fastmcp_auth = os.getenv("FASTMCP_SERVER_AUTH")
        env_fastmcp_client_id = os.getenv("FASTMCP_SERVER_AUTH_GOOGLE_CLIENT_ID")
        env_fastmcp_client_secret = os.getenv(
            "FASTMCP_SERVER_AUTH_GOOGLE_CLIENT_SECRET"
        )
        env_fastmcp_base_url = os.getenv("FASTMCP_SERVER_AUTH_GOOGLE_BASE_URL")
        logging.debug("🔧 FASTMCP DEBUG - Environment variables:")
        logging.debug(f"🔧   FASTMCP_SERVER_AUTH='{env_fastmcp_auth}'")
        logging.debug(
            f"🔧   FASTMCP_SERVER_AUTH_GOOGLE_CLIENT_ID={'***' if env_fastmcp_client_id else 'None'}"
        )
        logging.debug(
            f"🔧   FASTMCP_SERVER_AUTH_GOOGLE_CLIENT_SECRET={'***' if env_fastmcp_client_secret else 'None'}"
        )
        logging.debug(
            f"🔧   FASTMCP_SERVER_AUTH_GOOGLE_BASE_URL='{env_fastmcp_base_url}'"
        )
        logging.debug("🔧 FASTMCP DEBUG - Settings fields:")
        logging.debug(f"🔧   fastmcp_server_auth='{self.fastmcp_server_auth}'")
        logging.debug(
            f"🔧   fastmcp_server_auth_google_client_id={'***' if self.fastmcp_server_auth_google_client_id else 'None'}"
        )
        logging.debug(
            f"🔧   fastmcp_server_auth_google_client_secret={'***' if self.fastmcp_server_auth_google_client_secret else 'None'}"
        )
        logging.debug(
            f"🔧   fastmcp_server_auth_google_base_url='{self.fastmcp_server_auth_google_base_url}'"
        )

        # Cloud-aware configuration
        if self.is_cloud_deployment:
            # Use cloud-optimized settings
            self.credentials_dir = os.getenv("CREDENTIALS_DIR", "/tmp/credentials")
            if (
                not self.credential_storage_mode
                or self.credential_storage_mode == "FILE_ENCRYPTED"
            ):
                self.credential_storage_mode = os.getenv(
                    "CREDENTIAL_STORAGE_MODE", "MEMORY_WITH_BACKUP"
                )
            logging.debug(
                f"☁️ Cloud deployment detected - using credentials_dir='{self.credentials_dir}', storage_mode='{self.credential_storage_mode}'"
            )
        else:
            # Use environment variable override if provided, otherwise keep current value
            self.credentials_dir = os.getenv("CREDENTIALS_DIR", self.credentials_dir)
            self.credential_storage_mode = os.getenv(
                "CREDENTIAL_STORAGE_MODE", self.credential_storage_mode
            )

        # Ensure credentials directory exists
        Path(self.credentials_dir).mkdir(parents=True, exist_ok=True)

        # Parse Qdrant URL to get host and port
        parsed_url = urlparse(self.qdrant_url)
        self.qdrant_host = parsed_url.hostname or "localhost"
        self.qdrant_port = parsed_url.port or 6333
        # If QDRANT_KEY is "NONE" or empty, treat as no authentication
        self.qdrant_api_key = (
            None if self.qdrant_key in ["NONE", "", None] else self.qdrant_key
        )

        # DEBUG: Log final parsed values
        logging.debug(
            f"🔧 SETTINGS DEBUG - Parsed values: host='{self.qdrant_host}', port={self.qdrant_port}, api_key={'***' if self.qdrant_api_key else 'None'}"
        )

    @property
    def session_tool_state_path(self) -> Path:
        """Get the path for session tool state persistence file."""
        if self.session_tool_state_file:
            return Path(self.session_tool_state_file)
        return Path(self.credentials_dir) / "session_tool_states.json"

    def get_minimal_startup_services(self) -> List[str]:
        """
        Parse and return the list of services enabled by default in minimal startup mode.

        Returns:
            List[str]: List of service names (e.g., ['drive', 'gmail']).
                       Returns empty list if not configured.
        """
        if (
            not self.minimal_startup_services
            or self.minimal_startup_services.strip() == ""
        ):
            return []

        # Parse comma-separated list, strip whitespace, filter empty strings
        services = [
            service.strip().lower()
            for service in self.minimal_startup_services.split(",")
            if service.strip()
        ]

        # Validate against ScopeRegistry services
        try:
            from auth.scope_registry import ScopeRegistry

            valid_services = ScopeRegistry.get_all_services()
            validated = [s for s in services if s in valid_services]

            invalid = [s for s in services if s not in valid_services]
            if invalid:
                logging.warning(
                    f"Invalid services in MINIMAL_STARTUP_SERVICES: {invalid}. "
                    f"Valid services: {valid_services}"
                )

            return validated
        except ImportError:
            # ScopeRegistry not available - return as-is
            return services

    def get_gmail_allow_list(self) -> List[str]:
        """
        Parse and return the Gmail allow list from the configuration.

        Returns:
            List[str]: List of email addresses in the allow list.
                       Returns empty list if not configured or empty.
        """
        if not self.gmail_allow_list or self.gmail_allow_list.strip() == "":
            return []

        # Parse comma-separated list, strip whitespace, filter empty strings
        emails = [
            email.strip().lower()
            for email in self.gmail_allow_list.split(",")
            if email.strip()
        ]

        # Log the parsed allow list for debugging (without exposing full emails)
        if emails:
            masked_emails = [
                f"{email[:3]}...{email[-10:]}" if len(email) > 13 else email
                for email in emails
            ]
            logging.debug(
                f"Gmail allow list contains {len(emails)} email(s): {masked_emails}"
            )

        return emails

    def is_oauth_configured(self) -> bool:
        """Check if OAuth credentials are properly configured."""
        # Check if JSON file is provided and exists
        if self.google_client_secrets_file:
            return Path(self.google_client_secrets_file).exists()

        # Fallback to individual credentials
        return bool(self.google_client_id and self.google_client_secret)

    def validate_oauth_config(self) -> None:
        """Validate that OAuth configuration is complete."""
        if not self.is_oauth_configured():
            if self.google_client_secrets_file:
                raise ValueError(
                    f"OAuth client secrets file not found: {self.google_client_secrets_file}. "
                    "Please check the path to your Google OAuth JSON file."
                )
            else:
                raise ValueError(
                    "OAuth configuration is incomplete. Please either:\n"
                    "1. Set GOOGLE_CLIENT_SECRETS_FILE environment variable to point to your OAuth JSON file, OR\n"
                    "2. Set GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET environment variables"
                )

    def get_oauth_client_config(self) -> dict:
        """Get OAuth client configuration from JSON file or environment variables."""
        if self.google_client_secrets_file:
            secrets_path = Path(self.google_client_secrets_file)
            if not secrets_path.exists():
                # Log the full path for debugging
                logging.error(
                    f"OAuth client secrets file not found at: {secrets_path.absolute()}"
                )
                raise FileNotFoundError(
                    f"OAuth client secrets file not found: {self.google_client_secrets_file}"
                )

            import json

            try:
                with open(secrets_path, "r") as f:
                    config = json.load(f)
            except json.JSONDecodeError as e:
                raise ValueError(f"Invalid JSON in OAuth client secrets file: {e}")
            except Exception as e:
                raise ValueError(f"Error reading OAuth client secrets file: {e}")

            # Extract from Google OAuth JSON format
            if "web" in config:
                web_config = config["web"]
                return {
                    "client_id": web_config.get("client_id"),
                    "client_secret": web_config.get("client_secret"),
                    "auth_uri": web_config.get(
                        "auth_uri", "https://accounts.google.com/o/oauth2/auth"
                    ),
                    "token_uri": web_config.get(
                        "token_uri", "https://oauth2.googleapis.com/token"
                    ),
                    "redirect_uris": web_config.get(
                        "redirect_uris", [self.dynamic_oauth_redirect_uri]
                    ),
                }
            elif "installed" in config:
                installed_config = config["installed"]
                return {
                    "client_id": installed_config.get("client_id"),
                    "client_secret": installed_config.get("client_secret"),
                    "auth_uri": installed_config.get(
                        "auth_uri", "https://accounts.google.com/o/oauth2/auth"
                    ),
                    "token_uri": installed_config.get(
                        "token_uri", "https://oauth2.googleapis.com/token"
                    ),
                    "redirect_uris": installed_config.get(
                        "redirect_uris", [self.dynamic_oauth_redirect_uri]
                    ),
                }
            else:
                raise ValueError(
                    "OAuth client secrets JSON must contain either 'web' or 'installed' configuration"
                )

        # Fallback to environment variables
        if not self.google_client_id or not self.google_client_secret:
            raise ValueError(
                "OAuth configuration incomplete: Please set either GOOGLE_CLIENT_SECRETS_FILE or both GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET"
            )

        return {
            "client_id": self.google_client_id,
            "client_secret": self.google_client_secret,
            "auth_uri": "https://accounts.google.com/o/oauth2/auth",
            "token_uri": "https://oauth2.googleapis.com/token",
            "redirect_uris": [self.dynamic_oauth_redirect_uri],
        }

    def get_credentials_path(self, user_email: str) -> Path:
        """Get the path to store credentials for a specific user."""
        creds_dir = Path(self.credentials_dir)
        creds_dir.mkdir(exist_ok=True)
        return creds_dir / f"{user_email}_credentials.json"

    @property
    def protocol(self) -> str:
        """Get the protocol (http or https) based on SSL configuration."""
        return "https" if self.enable_https else "http"

    @property
    def base_url(self) -> str:
        """Get the base URL for the server."""
        # For OAuth flows, always use localhost if OAUTH_REDIRECT_URI points to localhost
        # This is needed because FastMCP Cloud only hosts the MCP endpoint, not OAuth endpoints
        env_oauth_uri = os.getenv("OAUTH_REDIRECT_URI", self.oauth_redirect_uri)
        if env_oauth_uri and "localhost" in env_oauth_uri:
            # In cloud deployment, use HTTPS for client-facing URLs even if enable_https=false
            # (CloudFlare handles HTTPS, but clients need HTTPS URLs)
            protocol = "https" if self.is_cloud_deployment else self.protocol
            # Extract port from OAuth redirect URI for consistency
            if ":8002" in env_oauth_uri:
                return f"{protocol}://localhost:8002"
            elif ":8000" in env_oauth_uri:
                return f"{protocol}://localhost:8000"
            else:
                return f"{protocol}://localhost:{self.server_port}"

        # Check if we have an explicit BASE_URL environment variable for cloud MCP endpoint
        explicit_base_url = os.getenv("BASE_URL")
        if explicit_base_url:
            return explicit_base_url

        # In cloud deployment, use HTTPS for client-facing URLs even if enable_https=false
        protocol = "https" if self.is_cloud_deployment else self.protocol
        return f"{protocol}://{self.server_host}:{self.server_port}"

    @property
    def dynamic_oauth_redirect_uri(self) -> str:
        """Get the OAuth redirect URI that dynamically switches between HTTP and HTTPS."""
        # Always use explicit OAUTH_REDIRECT_URI if it's been set via environment variable
        env_oauth_uri = os.getenv("OAUTH_REDIRECT_URI")
        if env_oauth_uri:
            # CRITICAL FIX: Automatically adjust protocol to match server configuration
            if self.enable_https and env_oauth_uri.startswith("http://localhost"):
                # Convert HTTP to HTTPS for localhost when HTTPS is enabled
                https_uri = env_oauth_uri.replace(
                    "http://localhost", "https://localhost"
                )
                logging.debug(
                    f"🔧 PROTOCOL FIX: Converted OAuth redirect URI from HTTP to HTTPS: {env_oauth_uri} → {https_uri}"
                )
                return https_uri
            elif not self.enable_https and env_oauth_uri.startswith(
                "https://localhost"
            ):
                # Convert HTTPS to HTTP for localhost when HTTPS is disabled
                http_uri = env_oauth_uri.replace(
                    "https://localhost", "http://localhost"
                )
                logging.debug(
                    f"🔧 PROTOCOL FIX: Converted OAuth redirect URI from HTTPS to HTTP: {env_oauth_uri} → {http_uri}"
                )
                return http_uri
            else:
                # Use as-is for non-localhost or already correct protocol
                return env_oauth_uri
        # Otherwise, use the configured value or construct from base_url
        if self.oauth_redirect_uri:
            return self.oauth_redirect_uri
        return f"{self.base_url}/oauth2callback"

    def get_uvicorn_ssl_config(self) -> Optional[dict]:
        """Get uvicorn SSL configuration for FastMCP if HTTPS is enabled."""
        if self.is_cloud_deployment:
            # FastMCP Cloud handles SSL automatically
            logging.debug("☁️ Cloud deployment detected - SSL handled by FastMCP Cloud")
            return None

        if not self.enable_https:
            return None

        # Return uvicorn-compatible SSL configuration for local deployment
        uvicorn_config = {
            "ssl_keyfile": self.ssl_key_file,
            "ssl_certfile": self.ssl_cert_file,
        }

        if self.ssl_ca_file:
            uvicorn_config["ssl_ca_certs"] = self.ssl_ca_file

        return uvicorn_config

    def validate_ssl_config(self) -> None:
        """Validate that SSL certificate files exist if HTTPS is enabled."""
        if not self.enable_https:
            return

        cert_path = Path(self.ssl_cert_file)
        key_path = Path(self.ssl_key_file)

        if not cert_path.exists():
            raise ValueError(f"SSL certificate file not found: {self.ssl_cert_file}")

        if not key_path.exists():
            raise ValueError(f"SSL private key file not found: {self.ssl_key_file}")

        if self.ssl_ca_file:
            ca_path = Path(self.ssl_ca_file)
            if not ca_path.exists():
                raise ValueError(f"SSL CA file not found: {self.ssl_ca_file}")


# Global settings instance
settings = Settings()
