"""Configuration management for MoEngage MCP Server.

Uses environment variables for all sensitive configuration.
Supports multiple MoEngage data centers (DC01-DC06).
"""

from enum import Enum
from functools import lru_cache

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


class DataCenter(str, Enum):
    """MoEngage Data Center identifiers."""

    DC01 = "01"
    DC02 = "02"
    DC03 = "03"
    DC04 = "04"
    DC05 = "05"
    DC06 = "06"

    @property
    def api_base_url(self) -> str:
        """Get the API base URL for this data center."""
        return f"https://api-{self.value}.moengage.com"


class Settings(BaseSettings):
    """Application settings loaded from environment variables.

    Environment Variables:
        MOENGAGE_WORKSPACE_ID: Your MoEngage Workspace ID (required)
        MOENGAGE_CAMPAIGN_REPORTS_API_KEY: Your MoEngage API Key for campaign reports (required)
        MOENGAGE_DATA_CENTER: Data center identifier (01-06), defaults to 01
        MOENGAGE_TIMEOUT: API request timeout in seconds, defaults to 30
        MOENGAGE_MAX_RETRIES: Maximum retry attempts for failed requests, defaults to 3
        MCP_SERVER_NAME: Name of the MCP server, defaults to "moengage-stats"
        MCP_SERVER_HOST: Host to bind the server to, defaults to 127.0.0.1
        MCP_SERVER_PORT: Port to bind the server to, defaults to 8000
        LOG_LEVEL: Logging level (DEBUG, INFO, WARNING, ERROR), defaults to INFO
    """

    model_config = SettingsConfigDict(
        env_prefix="MOENGAGE_",
        env_file=".env",
        env_file_encoding="utf-8",
        case_sensitive=False,
        extra="ignore",
    )

    # MoEngage API Configuration
    workspace_id: str = Field(
        ...,
        description="MoEngage Workspace ID (formerly App ID)",
        min_length=1,
    )
    campaign_reports_api_key: str = Field(
        ...,
        description="MoEngage API Key for campaign reports",
        min_length=1,
    )
    data_center: DataCenter = Field(
        default=DataCenter.DC01,
        description="MoEngage Data Center (01-06)",
    )
    timeout: int = Field(
        default=30,
        ge=5,
        le=120,
        description="API request timeout in seconds",
    )
    max_retries: int = Field(
        default=3,
        ge=0,
        le=10,
        description="Maximum retry attempts for failed requests",
    )

    # Server Configuration (without MOENGAGE_ prefix)
    server_name: str = Field(
        default="moengage-stats",
        alias="MCP_SERVER_NAME",
        description="Name of the MCP server",
    )
    server_host: str = Field(
        default="127.0.0.1",
        alias="MCP_SERVER_HOST",
        description="Host to bind the server to",
    )
    server_port: int = Field(
        default=8000,
        alias="MCP_SERVER_PORT",
        ge=1,
        le=65535,
        description="Port to bind the server to",
    )
    log_level: str = Field(
        default="INFO",
        alias="LOG_LEVEL",
        description="Logging level",
    )

    @field_validator("data_center", mode="before")
    @classmethod
    def validate_data_center(cls, v: str | DataCenter) -> DataCenter:
        """Validate and convert data center value."""
        if isinstance(v, DataCenter):
            return v
        # Handle both "01" and "DC01" formats
        v_str = str(v).upper().replace("DC", "")
        try:
            return DataCenter(v_str.zfill(2))
        except ValueError as e:
            raise ValueError(
                f"Invalid data center: {v}. Must be one of: 01, 02, 03, 04, 05, 06"
            ) from e

    @property
    def api_base_url(self) -> str:
        """Get the API base URL for the configured data center."""
        return self.data_center.api_base_url

    @property
    def stats_api_url(self) -> str:
        """Get the Stats API endpoint URL."""
        return f"{self.api_base_url}/core-services/v1/campaign-stats"

    @staticmethod
    def mask_secret(value: str, visible_chars: int = 4) -> str:
        """Mask a secret value for safe logging.

        Args:
            value: The secret value to mask.
            visible_chars: Number of characters to show at start and end.

        Returns:
            Masked string like "abcd...wxyz" or "[MASKED]" if too short.
        """
        if len(value) <= visible_chars * 2:
            return "[MASKED]"
        return f"{value[:visible_chars]}...{value[-visible_chars:]}"

    @property
    def masked_api_key(self) -> str:
        """Get masked API key for safe logging."""
        return self.mask_secret(self.campaign_reports_api_key)

    @property
    def masked_workspace_id(self) -> str:
        """Get masked workspace ID for safe logging."""
        return self.mask_secret(self.workspace_id)

    def __repr__(self) -> str:
        """Return safe string representation without exposing secrets."""
        return (
            f"Settings(workspace_id='{self.masked_workspace_id}', "
            f"data_center={self.data_center.name}, "
            f"api_key='[MASKED]')"
        )

    def __str__(self) -> str:
        """Return safe string representation without exposing secrets."""
        return self.__repr__()


@lru_cache
def get_settings() -> Settings:
    """Get cached settings instance.

    Returns:
        Settings: Application settings loaded from environment.

    Raises:
        ValidationError: If required environment variables are missing.
    """
    return Settings()


def settings_from_headers(headers: dict[str, str]) -> Settings | None:
    """Create Settings from request headers for multi-tenant mode.

    Headers:
        X-MoEngage-Workspace-ID: MoEngage Workspace ID
        X-MoEngage-Campaign-Reports-API-Key: MoEngage API Key for campaign reports
        X-MoEngage-Data-Center: Data center (01-06), optional

    Args:
        headers: Request headers dictionary

    Returns:
        Settings if credentials found in headers, None otherwise
    """
    workspace_id = headers.get("x-moengage-workspace-id") or headers.get("X-MoEngage-Workspace-ID")
    campaign_reports_api_key = (
        headers.get("x-moengage-campaign-reports-api-key")
        or headers.get("X-MoEngage-Campaign-Reports-API-Key")
    )

    if not workspace_id or not campaign_reports_api_key:
        return None

    data_center = (
        headers.get("x-moengage-data-center")
        or headers.get("X-MoEngage-Data-Center")
        or "01"
    )

    return Settings(
        workspace_id=workspace_id,
        campaign_reports_api_key=campaign_reports_api_key,
        data_center=data_center,
    )


class MultiTenantConfig:
    """Configuration for multi-tenant deployment mode.

    In multi-tenant mode:
    - Credentials come from request headers, not environment
    - Each request can use different MoEngage accounts
    - Server doesn't store any credentials
    """

    HEADER_WORKSPACE_ID = "X-MoEngage-Workspace-ID"
    HEADER_CAMPAIGN_REPORTS_API_KEY = "X-MoEngage-Campaign-Reports-API-Key"
    HEADER_DATA_CENTER = "X-MoEngage-Data-Center"

    @staticmethod
    def get_required_headers() -> list[str]:
        """Get list of required headers for multi-tenant mode."""
        return [
            MultiTenantConfig.HEADER_WORKSPACE_ID,
            MultiTenantConfig.HEADER_CAMPAIGN_REPORTS_API_KEY,
        ]

    @staticmethod
    def get_optional_headers() -> list[str]:
        """Get list of optional headers for multi-tenant mode."""
        return [
            MultiTenantConfig.HEADER_DATA_CENTER,
        ]
