"""
Configuration management for Miku Discord Bot.
Uses Pydantic for type-safe configuration loading from:
- .env (secrets only)
- config.yaml (all other configuration)
"""

from pathlib import Path
from typing import Optional
from pydantic import BaseModel, Field
from pydantic_settings import BaseSettings, SettingsConfigDict

# ============================================
# Pydantic Models for Configuration
# ============================================


class ServicesConfig(BaseModel):
    """External service endpoint configuration"""
    url: str = "http://llama-swap:8080"
    amd_url: str = "http://llama-swap-amd:8080"


class CheshireCatConfig(BaseModel):
    """Cheshire Cat AI memory system configuration"""
    url: str = "http://cheshire-cat:80"
    timeout_seconds: int = Field(default=120, ge=1, le=600)
    enabled: bool = True


class FaceDetectorConfig(BaseModel):
    """Face detection service configuration"""
    startup_timeout_seconds: int = Field(default=60, ge=10, le=300)


class ModelsConfig(BaseModel):
    """AI model configuration"""
    text: str = "llama3.1"
    vision: str = "vision"
    evil: str = "darkidol"
    japanese: str = "swallow"


class DiscordConfig(BaseModel):
    """Discord bot configuration"""
    language_mode: str = Field(default="english", pattern="^(english|japanese)$")
    api_port: int = Field(default=3939, ge=1024, le=65535)


class AutonomousConfig(BaseModel):
    """Autonomous system configuration"""
    debug_mode: bool = False


class VoiceConfig(BaseModel):
    """Voice chat configuration"""
    debug_mode: bool = False


class MemoryConfig(BaseModel):
    """Memory and logging configuration"""
    log_dir: str = "/app/memory/logs"
    conversation_history_length: int = Field(default=5, ge=1, le=50)


class ServerConfig(BaseModel):
    """Server settings"""
    host: str = "0.0.0.0"
    log_level: str = Field(default="critical", pattern="^(debug|info|warning|error|critical)$")


class GPUConfig(BaseModel):
    """GPU configuration"""
    prefer_amd: bool = False
    amd_models_enabled: bool = True


class AppConfig(BaseModel):
    """Main application configuration"""
    services: ServicesConfig = Field(default_factory=ServicesConfig)
    cheshire_cat: CheshireCatConfig = Field(default_factory=CheshireCatConfig)
    face_detector: FaceDetectorConfig = Field(default_factory=FaceDetectorConfig)
    models: ModelsConfig = Field(default_factory=ModelsConfig)
    discord: DiscordConfig = Field(default_factory=DiscordConfig)
    autonomous: AutonomousConfig = Field(default_factory=AutonomousConfig)
    voice: VoiceConfig = Field(default_factory=VoiceConfig)
    memory: MemoryConfig = Field(default_factory=MemoryConfig)
    server: ServerConfig = Field(default_factory=ServerConfig)
    gpu: GPUConfig = Field(default_factory=GPUConfig)


class Secrets(BaseSettings):
    """
    Secrets loaded from environment variables (.env file)
    These are sensitive values that should never be committed to git
    """
    model_config = SettingsConfigDict(
        env_file=".env",
        env_file_encoding="utf-8",
        env_prefix="",  # No prefix for env vars
        extra="ignore"  # Ignore extra env vars
    )

    # Discord
    discord_bot_token: str = Field(..., description="Discord bot token")

    # API Keys
    cheshire_cat_api_key: str = Field(default="", description="Cheshire Cat API key (empty if no auth)")

    # Error Reporting
    error_webhook_url: Optional[str] = Field(default=None, description="Discord webhook for error notifications")

    # Owner
    owner_user_id: int = Field(default=209381657369772032, description="Bot owner Discord user ID")


# ============================================
# Configuration Loader
# ============================================


def load_config(config_path: str = None) -> AppConfig:
    """
    Load configuration from YAML file.
    
    Args:
        config_path: Path to config.yaml (defaults to ../config.yaml from bot directory)
    
    Returns:
        AppConfig instance
    """
    import yaml

    if config_path is None:
        # Default: try Docker path first, then fall back to relative path
        # In Docker, config.yaml is mounted at /app/config.yaml
        docker_config = Path("/app/config.yaml")
        if docker_config.exists():
            config_path = docker_config
        else:
            # Not in Docker, go up one level from bot/ directory
            config_path = Path(__file__).parent.parent / "config.yaml"

    config_file = Path(config_path)

    if not config_file.exists():
        # Fall back to default config if file doesn't exist
        print(f"⚠️  Config file not found: {config_file}")
        print("Using default configuration")
        return AppConfig()

    with open(config_file, "r") as f:
        config_data = yaml.safe_load(f) or {}

    return AppConfig(**config_data)


def load_secrets() -> Secrets:
    """
    Load secrets from environment variables (.env file).
    
    Returns:
        Secrets instance
    """
    return Secrets()


# ============================================
# Unified Configuration Instance
# ============================================

# Load configuration at module import time
CONFIG = load_config()
SECRETS = load_secrets()

# ============================================
# Re-exports for modules that import from config
# ============================================
# error_handler.py imports ERROR_WEBHOOK_URL from here
ERROR_WEBHOOK_URL = SECRETS.error_webhook_url

# ============================================
# Validation & Health Check
# ============================================


def validate_config() -> tuple[bool, list[str]]:
    """
    Validate that all required configuration is present.
    
    Returns:
        Tuple of (is_valid, list_of_errors)
    """
    errors = []

    # Check secrets
    if not SECRETS.discord_bot_token or SECRETS.discord_bot_token == "your_discord_bot_token_here":
        errors.append("DISCORD_BOT_TOKEN not set or using placeholder value")

    # Validate Cheshire Cat config
    if CONFIG.cheshire_cat.enabled and not CONFIG.cheshire_cat.url:
        errors.append("Cheshire Cat enabled but URL not configured")

    return len(errors) == 0, errors


def print_config_summary():
    """Print a summary of current configuration (without secrets)"""
    print("\n" + "="*60)
    print("🎵 Miku Bot Configuration Summary")
    print("="*60)
    print(f"\n📊 Configuration loaded from: config.yaml")
    print(f"🔐 Secrets loaded from: .env")
    print(f"\n🤖 Models:")
    print(f"   - Text: {CONFIG.models.text}")
    print(f"   - Vision: {CONFIG.models.vision}")
    print(f"   - Evil: {CONFIG.models.evil}")
    print(f"   - Japanese: {CONFIG.models.japanese}")
    print(f"\n🔗 Services:")
    print(f"   - Llama: {CONFIG.services.url}")
    print(f"   - Llama AMD: {CONFIG.services.amd_url}")
    print(f"   - Cheshire Cat: {CONFIG.cheshire_cat.url} (enabled: {CONFIG.cheshire_cat.enabled})")
    print(f"\n⚙️  Settings:")
    print(f"   - Language Mode: {CONFIG.discord.language_mode}")
    print(f"   - Autonomous Debug: {CONFIG.autonomous.debug_mode}")
    print(f"   - Voice Debug: {CONFIG.voice.debug_mode}")
    print(f"   - Prefer AMD GPU: {CONFIG.gpu.prefer_amd}")
    print(f"\n📝 Secrets: {'✅ Loaded' if SECRETS.discord_bot_token else '❌ Missing'}")
    print("\n" + "="*60 + "\n")


# Auto-validate on import
is_valid, validation_errors = validate_config()
if not is_valid:
    print("❌ Configuration Validation Failed:")
    for error in validation_errors:
        print(f"   - {error}")
    print("\nPlease check your .env file and try again.")
    # Note: We don't exit here because the bot might be started in a different context
    # The calling code should check validate_config() if needed
