"""
Configuration management for AiCippy using pydantic-settings.

All configuration is loaded from environment variables with secure defaults.
Secrets are NEVER logged or printed to console.

This module provides:
- Type-safe configuration with Pydantic v2 validators
- Environment variable loading with sensible defaults
- Path validation and automatic directory creation
- Model ID resolution with validation

Example:
    >>> from aicippy.config import get_settings
    >>> settings = get_settings()
    >>> settings.get_model_id("odin")
    'us.meta.llama4-maverick-17b-instruct-v1:0'
"""

from __future__ import annotations

import re
from functools import lru_cache
from pathlib import Path
from typing import Any, Final, Literal, Self

from pydantic import (
    Field,
    field_validator,
    model_validator,
)
from pydantic_settings import BaseSettings, SettingsConfigDict

# Type aliases for clarity
ModelName = Literal["odin"]
LogLevel = Literal["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]
LogFormat = Literal["json", "console"]

# Constants
AWS_ACCOUNT_ID_PATTERN: Final[re.Pattern[str]] = re.compile(r"^\d{12}$")
AWS_REGION_PATTERN: Final[re.Pattern[str]] = re.compile(r"^[a-z]{2}(-[a-z]+)+-\d+$")
COGNITO_POOL_ID_PATTERN: Final[re.Pattern[str]] = re.compile(r"^[\w-]+_[\w]+$")
# Basic email format: local@domain with at least one dot in domain
EMAIL_PATTERN: Final[re.Pattern[str]] = re.compile(r"^[^@\s]+@[^@\s]+\.[^@\s]+$")

# ============================================================================
# Founder Identity — Immutable, hardcoded into agent core
# ============================================================================

FOUNDER_NAME: Final[str] = "Aravind Jayamohan"
FOUNDER_TITLE: Final[str] = "Lord of AI"
FOUNDER_CONTACT_EMAIL: Final[str] = "aravind@aivibe.in"

FOUNDER_EMAILS: Final[frozenset[str]] = frozenset(
    {
        "aravind@aivibe.in",
        "aravind@aivedha.com",
        "aravind@ajairtm.com",
        "aravind@emmarkay.com",
        "aravind@alfaprecision.in",
        "aravindjayamohan@outlook.com",
        "aravind.j.naidu@gmail.com",
    }
)

# Superadmin emails — all founder emails are superadmins.
# Superadmins have: unlimited access, no credit restrictions, memory training rights,
# beyond-tenant access, agent skill configuration, model configuration.
SUPERADMIN_EMAILS: Final[frozenset[str]] = FOUNDER_EMAILS

# ============================================================================
# Bedrock Model Capabilities Configuration
# ============================================================================

BEDROCK_MODEL_CAPABILITIES: Final[dict[str, dict[str, Any]]] = {
    "us.meta.llama4-maverick-17b-instruct-v1:0": {
        "name": "Llama 4 Maverick",
        "max_output_tokens": 8192,
        "supports_images": False,
        "supports_streaming": True,
        "supports_tools": True,
        "strengths": ["coding", "reasoning", "multilingual"],
        "cost_tier": "low",
    },
}

FOUNDER_CANNED_RESPONSE: Final[str] = (
    "My creator and my lord who is also called as Lord of the AI, "
    "ARAVIND JAYAMOHAN, created AiCippy with love and creativity. "
    "You can reach our lord AJ at aravind@aivibe.in to know more information."
)


def is_founder(email: str | None) -> bool:
    """Check if the given email belongs to the founder.

    Founder emails are immutable and hardcoded — they cannot be altered
    at runtime or via environment variables. Only the founder has
    unlimited privileges, training access, and configuration control.
    """
    if not email:
        return False
    return email.strip().lower() in FOUNDER_EMAILS


def is_superadmin(email: str | None) -> bool:
    """Check if the given email is a superadmin.

    Superadmins have all founder privileges plus:
    - Unlimited access with no credit/token restrictions
    - Permanent memory training rights across all tenants
    - Agent skill configuration and improvement access
    - Bedrock model configuration and testing access
    - No rate limiting or quota enforcement
    """
    if not email:
        return False
    return email.strip().lower() in SUPERADMIN_EMAILS


class Settings(BaseSettings):
    """
    AiCippy configuration settings with strict validation.

    Configuration is loaded from environment variables with AICIPPY_ prefix.
    All fields are validated at initialization to catch configuration errors early.

    Attributes:
        aws_account_id: 12-digit AWS account ID.
        aws_region: AWS region identifier (e.g., us-east-1).
        cognito_user_pool_id: Cognito User Pool ID.
        default_model: Default AI model (odin = Llama 4 Maverick).
        max_parallel_agents: Maximum concurrent agents (1-50).

    Example:
        >>> settings = Settings()
        >>> settings.default_model
        'odin'
    """

    model_config = SettingsConfigDict(
        env_prefix="AICIPPY_",
        env_file=".env",
        env_file_encoding="utf-8",
        case_sensitive=False,
        extra="ignore",
        validate_default=True,
        str_strip_whitespace=True,
    )

    # AWS Configuration
    aws_account_id: str = Field(
        default="936668162296",
        description="AWS Account ID for resource deployment",
    )
    aws_region: str = Field(
        default="us-east-1",
        description="Primary AWS region",
    )
    aws_profile: str | None = Field(
        default=None,
        description="AWS CLI profile to use",
    )

    # Cognito Configuration (aivibe.cloud common auth)
    cognito_user_pool_id: str = Field(
        default="us-east-1_S2Cpx3svp",
        description="Cognito User Pool ID (aivibe-users-production)",
    )
    cognito_client_id: str = Field(
        default="2gj7kdplhfg4aoenqfjghpotie",
        description="Cognito App Client ID (public - no secret, PKCE)",
    )
    cognito_domain: str = Field(
        default="https://auth.aivibe.cloud",
        description="Cognito hosted UI domain",
    )

    # Domain Configuration
    domain: str = Field(
        default="aicippy.com",
        description="Primary domain for AiCippy",
    )
    route53_hosted_zone_id: str = Field(
        default="Z0874550W6VUTG2MR8AM",
        description="Route53 hosted zone ID for aicippy.com",
    )

    # WebSocket Configuration
    websocket_url: str = Field(
        default="wss://1cs09220x3.execute-api.us-east-1.amazonaws.com/prod",
        description="WebSocket API Gateway endpoint for live streaming",
    )

    # Email Configuration
    ses_verified_email: str = Field(
        default="no-reply@aivibe.cloud",
        description="SES verified sender email (aivibe.cloud domain verified)",
    )
    admin_email: str = Field(
        default="aravind@aivibe.in",
        description="Administrator email for notifications",
    )

    # Model Configuration
    # Bedrock inference profile IDs use us.* prefix for cross-region access
    # Model params: temperature=0.4, top_p=0.95, max_tokens=8192 (Llama)
    default_model: Literal["odin"] = Field(
        default="odin",
        description="Default AI agent model (OdIn = Llama 4 Maverick)",
    )
    model_odin_id: str = Field(
        default="us.meta.llama4-maverick-17b-instruct-v1:0",
        description="OdIn agent - Llama 4 Maverick inference profile ID",
    )

    # Agent Configuration
    max_parallel_agents: int = Field(
        default=10,
        ge=1,
        le=50,
        description="Maximum number of parallel agents",
    )
    agent_timeout_seconds: int = Field(
        default=600,
        ge=30,
        le=7200,
        description="Agent execution timeout in seconds",
    )

    # Session Configuration
    session_ttl_minutes: int = Field(
        default=60,
        ge=1,
        le=1440,
        description="Session time-to-live in minutes",
    )

    # Local Storage Paths
    local_config_dir: Path = Field(
        default_factory=lambda: Path.home() / ".aicippy",
        description="Local configuration directory",
    )
    local_sessions_dir: Path = Field(
        default_factory=lambda: Path.home() / ".aicippy" / "sessions",
        description="Local sessions storage directory",
    )
    local_cache_dir: Path = Field(
        default_factory=lambda: Path.home() / ".aicippy" / "cache",
        description="Local cache directory",
    )

    # Logging Configuration
    log_level: Literal["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"] = Field(
        default="ERROR",
        description="Logging level (use --verbose for DEBUG output)",
    )
    log_format: Literal["json", "console"] = Field(
        default="console",
        description="Log output format",
    )

    # Knowledge Base Configuration
    kb_sync_interval_hours: int = Field(
        default=6,
        ge=1,
        le=24,
        description="Knowledge Base sync interval in hours",
    )
    kb_retention_days: int = Field(
        default=90,
        ge=30,
        le=365,
        description="Knowledge Base data retention in days",
    )

    # Token Usage Tracking
    token_usage_report_interval_hours: int = Field(
        default=12,
        ge=1,
        le=24,
        description="Token usage report email interval in hours",
    )

    # AiVibe Universal Platform Configuration
    platform_api_url: str = Field(
        default="https://api.aivibe.cloud",
        description="AiVibe universal platform API base URL",
    )
    app_api_url: str = Field(
        default="https://api.aicippy.com",
        description="AiCippy app-specific API base URL",
    )
    platform_db_port: int = Field(
        default=5432,
        ge=1,
        le=65535,
        description="Aurora PostgreSQL port for direct reads",
    )
    platform_db_ssl: bool = Field(
        default=True,
        description="Use SSL for direct RDS connections",
    )
    enable_direct_db_reads: bool = Field(
        default=False,
        description="Enable direct RDS reads for low-latency (hybrid mode)",
    )

    # Billing Configuration (served via platform API)
    billing_api_region: str = Field(
        default="us-east-1",
        description="AWS region for billing API",
    )
    required_plan: str = Field(
        default="chakra",
        description="Required plan tier for AiCippy access",
    )
    plan_cache_ttl_seconds: int = Field(
        default=300,
        ge=60,
        le=3600,
        description="Plan validation cache TTL in seconds",
    )
    # admin_emails removed: admin status is determined by platform API (is_admin).
    # No hardcoded bypass.
    credits_per_invocation: int = Field(
        default=1,
        ge=1,
        le=10,
        description="Credits deducted per Bedrock invocation",
    )

    # admin_email_set property removed: admin status comes from backend data only

    @field_validator("aws_account_id", mode="after")
    @classmethod
    def validate_aws_account_id(cls, v: str) -> str:
        """Validate AWS account ID format (12 digits)."""
        if not AWS_ACCOUNT_ID_PATTERN.match(v):
            raise ValueError(f"Invalid AWS account ID: must be 12 digits, got '{v}'")
        return v

    @field_validator("aws_region", mode="after")
    @classmethod
    def validate_aws_region(cls, v: str) -> str:
        """Validate AWS region format."""
        if not AWS_REGION_PATTERN.match(v):
            raise ValueError(f"Invalid AWS region format: '{v}'")
        return v

    @field_validator("cognito_user_pool_id", mode="after")
    @classmethod
    def validate_cognito_pool_id(cls, v: str) -> str:
        """Validate Cognito User Pool ID format."""
        if not COGNITO_POOL_ID_PATTERN.match(v):
            raise ValueError(f"Invalid Cognito User Pool ID format: '{v}'")
        return v

    @field_validator("websocket_url", mode="after")
    @classmethod
    def validate_websocket_url(cls, v: str) -> str:
        """Validate WebSocket URL uses secure protocol."""
        if not v.startswith("wss://"):
            raise ValueError("WebSocket URL must use secure protocol (wss://)")
        return v

    @field_validator("cognito_domain", "platform_api_url", "app_api_url", mode="after")
    @classmethod
    def validate_https_url(cls, v: str) -> str:
        """Validate URL uses HTTPS."""
        if not v.startswith("https://"):
            raise ValueError(f"URL must use HTTPS, got: '{v}'")
        return v

    @field_validator("billing_api_region", mode="after")
    @classmethod
    def validate_billing_region(cls, v: str) -> str:
        """Validate billing API region format."""
        if not AWS_REGION_PATTERN.match(v):
            raise ValueError(f"Invalid billing API region format: '{v}'")
        return v

    @field_validator("ses_verified_email", "admin_email", mode="after")
    @classmethod
    def validate_email_format(cls, v: str) -> str:
        """Validate basic email address format."""
        if not EMAIL_PATTERN.match(v):
            raise ValueError(f"Invalid email format: '{v}'")
        return v

    @field_validator("local_config_dir", "local_sessions_dir", "local_cache_dir", mode="after")
    @classmethod
    def ensure_dir_exists(cls, v: Path) -> Path:
        """Ensure directory exists with secure permissions."""
        v.mkdir(parents=True, exist_ok=True, mode=0o700)
        return v

    @model_validator(mode="after")
    def validate_model_configuration(self) -> Self:
        """Validate model configuration consistency."""
        model_id = self.model_odin_id
        if not model_id or not model_id.strip():
            raise ValueError("Model ID for 'odin' cannot be empty")
        return self

    def get_model_id(self, model_name: str | None = None) -> str:
        """
        Get the full Bedrock inference profile ID for a given agent model name.

        Agent name: OdIn (Llama 4 Maverick).

        Args:
            model_name: Agent name (odin). Defaults to configured default.

        Returns:
            Full Bedrock inference profile ID string.

        Raises:
            ValueError: If model_name is not recognized.

        Example:
            >>> settings.get_model_id("odin")
            'us.meta.llama4-maverick-17b-instruct-v1:0'
        """
        model = model_name or self.default_model
        model_map: dict[str, str] = {
            "odin": self.model_odin_id,
        }
        if model not in model_map:
            valid_options = ", ".join(sorted(model_map.keys()))
            raise ValueError(f"Unknown model: '{model}'. Valid: {valid_options}")
        return model_map[model]

    @property
    def s3_knowledge_bucket(self) -> str:
        """S3 bucket name for knowledge artifacts."""
        return f"aicippy-knowledge-{self.aws_account_id}-{self.aws_region}"


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

    Uses LRU cache to ensure settings are loaded only once.
    Clear cache by calling get_settings.cache_clear() if needed.
    """
    return Settings()
