"""
Configuration centralisée pour PriceWatch Phase 2.

Gère la configuration de la base de données, Redis, et l'application globale.
Utilise Pydantic Settings pour validation et chargement depuis variables d'environnement.

Justification technique:
- Pattern 12-factor app: configuration via env vars
- Pydantic validation garantit config valide au démarrage
- Valeurs par défaut pour développement local
- Support .env file pour faciliter le setup
"""

from typing import Optional

from pydantic import Field
from pydantic_settings import BaseSettings, SettingsConfigDict

from pricewatch.app.core.logging import get_logger

logger = get_logger("core.config")


class DatabaseConfig(BaseSettings):
    """Configuration PostgreSQL."""

    host: str = Field(default="localhost", description="PostgreSQL host")
    port: int = Field(default=5432, description="PostgreSQL port")
    database: str = Field(default="pricewatch", description="Database name")
    user: str = Field(default="pricewatch", description="Database user")
    password: str = Field(default="pricewatch", description="Database password")

    model_config = SettingsConfigDict(
        env_prefix="PW_DB_",  # PW_DB_HOST, PW_DB_PORT, etc.
        env_file=".env",
        env_file_encoding="utf-8",
        extra="ignore",
    )

    @property
    def url(self) -> str:
        """
        SQLAlchemy connection URL.

        Format: postgresql://user:password@host:port/database
        """
        return f"postgresql://{self.user}:{self.password}@{self.host}:{self.port}/{self.database}"

    @property
    def url_async(self) -> str:
        """
        Async SQLAlchemy connection URL (pour usage futur avec asyncpg).

        Format: postgresql+asyncpg://user:password@host:port/database
        """
        return f"postgresql+asyncpg://{self.user}:{self.password}@{self.host}:{self.port}/{self.database}"


class RedisConfig(BaseSettings):
    """Configuration Redis pour RQ worker."""

    host: str = Field(default="localhost", description="Redis host")
    port: int = Field(default=6379, description="Redis port")
    db: int = Field(default=0, description="Redis database number (0-15)")
    password: Optional[str] = Field(default=None, description="Redis password (optional)")

    model_config = SettingsConfigDict(
        env_prefix="PW_REDIS_",  # PW_REDIS_HOST, PW_REDIS_PORT, etc.
        env_file=".env",
        env_file_encoding="utf-8",
        extra="ignore",
    )

    @property
    def url(self) -> str:
        """
        Redis connection URL pour RQ.

        Format: redis://[password@]host:port/db
        """
        auth = f":{self.password}@" if self.password else ""
        return f"redis://{auth}{self.host}:{self.port}/{self.db}"


class AppConfig(BaseSettings):
    """Configuration globale de l'application."""

    # Mode debug
    debug: bool = Field(
        default=False, description="Enable debug mode (verbose logging, SQL echo)"
    )

    # Worker configuration
    worker_timeout: int = Field(
        default=300, description="Worker job timeout in seconds (5 minutes)"
    )

    worker_concurrency: int = Field(
        default=2, description="Number of concurrent worker processes"
    )

    # Feature flags
    enable_db: bool = Field(
        default=True, description="Enable database persistence (can disable for testing)"
    )

    enable_worker: bool = Field(
        default=True, description="Enable background worker functionality"
    )

    # API auth
    api_token: Optional[str] = Field(
        default=None, description="API token simple (Bearer)"
    )

    # Scraping defaults
    default_playwright_timeout: int = Field(
        default=60000, description="Default Playwright timeout in milliseconds"
    )

    default_use_playwright: bool = Field(
        default=True, description="Use Playwright fallback by default"
    )

    model_config = SettingsConfigDict(
        env_prefix="PW_",  # PW_DEBUG, PW_WORKER_TIMEOUT, etc.
        env_file=".env",
        env_file_encoding="utf-8",
        extra="ignore",
    )

    # Nested configs (instances, not classes)
    db: DatabaseConfig = Field(default_factory=DatabaseConfig)
    redis: RedisConfig = Field(default_factory=RedisConfig)

    def log_config(self) -> None:
        """Log la configuration active (sans password)."""
        logger.info("=== Configuration PriceWatch ===")
        logger.info(f"Debug mode: {self.debug}")
        logger.info(f"Database: {self.db.host}:{self.db.port}/{self.db.database}")
        logger.info(f"Redis: {self.redis.host}:{self.redis.port}/{self.redis.db}")
        logger.info(f"DB enabled: {self.enable_db}")
        logger.info(f"Worker enabled: {self.enable_worker}")
        logger.info(f"Worker timeout: {self.worker_timeout}s")
        logger.info(f"Worker concurrency: {self.worker_concurrency}")
        logger.info(f"API token configured: {bool(self.api_token)}")
        logger.info("================================")


# Singleton global config instance
_config: Optional[AppConfig] = None


def get_config() -> AppConfig:
    """
    Récupère l'instance globale de configuration (singleton).

    Returns:
        Instance AppConfig

    Justification:
    - Évite de recharger la config à chaque appel
    - Centralise la configuration pour toute l'application
    - Permet d'override pour les tests
    """
    global _config

    if _config is None:
        _config = AppConfig()
        if _config.debug:
            _config.log_config()

    return _config


def set_config(config: AppConfig) -> None:
    """
    Override la configuration globale (principalement pour tests).

    Args:
        config: Instance AppConfig à utiliser
    """
    global _config
    _config = config
    logger.debug("Configuration overridden")


def reset_config() -> None:
    """Reset la configuration globale (pour tests)."""
    global _config
    _config = None
    logger.debug("Configuration reset")
