"""
Example 07: Django-style Settings (v2.0.0)

This example demonstrates using prism-config with Django applications,
mapping familiar Django settings patterns to typed configuration.

Key features demonstrated:
- Django-compatible configuration structure
- Typed settings with IDE autocomplete
- Environment-specific overrides
- Secret resolution for sensitive settings
- Export to Django settings module format

Run this example:
    export DJANGO_SECRET_KEY=django-insecure-change-me
    export DB_PASSWORD=secret_db_pass
    export EMAIL_HOST_USER=user@example.com
    export EMAIL_HOST_PASSWORD=email_pass
    export SENTRY_DSN=https://example@sentry.io/123

    python examples/07-django/django_example.py
"""

import sys
from pathlib import Path
from typing import Any, Dict, List, Optional

# Ensure UTF-8 output on Windows
if sys.platform == "win32":
    sys.stdout.reconfigure(encoding="utf-8", errors="replace")

from prism.config import (
    BaseConfigSection,
    BaseConfigRoot,
    DatabaseConfig,
    PrismConfig,
    register_emoji,
)


# =============================================================================
# Django Settings Schema (v2.0.0 Custom Schema)
# =============================================================================


class DjangoConfig(BaseConfigSection):
    """Core Django settings."""

    secret_key: str
    debug: bool = False
    allowed_hosts: List[str] = ["localhost"]
    language_code: str = "en-us"
    time_zone: str = "UTC"
    use_i18n: bool = True
    use_tz: bool = True


class StaticConfig(BaseConfigSection):
    """Static files configuration."""

    url: str = "/static/"
    root: str = "/var/www/static/"
    dirs: List[str] = []


class MediaConfig(BaseConfigSection):
    """Media files configuration."""

    url: str = "/media/"
    root: str = "/var/www/media/"


class EmailConfig(BaseConfigSection):
    """Email backend configuration."""

    backend: str = "smtp"
    host: str = "localhost"
    port: int = 25
    use_tls: bool = False
    use_ssl: bool = False
    host_user: Optional[str] = None
    host_password: Optional[str] = None
    default_from: str = "webmaster@localhost"


class CacheConfig(BaseConfigSection):
    """Cache configuration."""

    backend: str = "locmem"
    location: str = ""
    timeout: int = 300
    options: Dict[str, Any] = {}


class SessionConfig(BaseConfigSection):
    """Session configuration."""

    engine: str = "django.contrib.sessions.backends.db"
    cache_alias: str = "default"
    cookie_age: int = 1209600
    cookie_secure: bool = False
    cookie_httponly: bool = True


class LoggingConfig(BaseConfigSection):
    """Logging configuration."""

    version: int = 1
    disable_existing_loggers: bool = False
    root_level: str = "INFO"
    handlers: List[str] = ["console"]
    file_path: Optional[str] = None


class SecurityConfig(BaseConfigSection):
    """Security middleware settings."""

    csrf_cookie_secure: bool = False
    session_cookie_secure: bool = False
    secure_browser_xss_filter: bool = True
    secure_content_type_nosniff: bool = True
    x_frame_options: str = "DENY"
    hsts_seconds: int = 0
    hsts_include_subdomains: bool = False


class SentryConfig(BaseConfigSection):
    """Sentry integration settings."""

    dsn: Optional[str] = None
    environment: str = "development"
    traces_sample_rate: float = 0.0


class CeleryConfig(BaseConfigSection):
    """Celery integration settings."""

    broker_url: str = "redis://localhost:6379/0"
    result_backend: str = "redis://localhost:6379/0"
    task_always_eager: bool = False


class IntegrationsConfig(BaseConfigSection):
    """Third-party integrations."""

    sentry: SentryConfig
    celery: CeleryConfig


class DjangoSettingsConfig(BaseConfigRoot):
    """
    Complete Django application configuration.

    Maps to familiar Django settings patterns while providing
    type safety and secret management.
    """

    django: DjangoConfig
    database: DatabaseConfig
    static: StaticConfig
    media: MediaConfig
    email: EmailConfig
    cache: CacheConfig
    session: SessionConfig
    logging: LoggingConfig
    security: SecurityConfig
    integrations: IntegrationsConfig


# =============================================================================
# Django Settings Generator
# =============================================================================


def generate_django_settings(config: PrismConfig) -> str:
    """
    Generate a Django settings.py compatible output from config.

    This demonstrates how prism-config can be used to generate
    Django settings dynamically.
    """
    lines = [
        '"""',
        "Django settings generated by prism-config.",
        "Do not edit directly - modify config.yaml instead.",
        '"""',
        "",
        "from pathlib import Path",
        "",
        "# Build paths inside the project",
        "BASE_DIR = Path(__file__).resolve().parent.parent",
        "",
        "# SECURITY WARNING: keep the secret key used in production secret!",
        f"SECRET_KEY = {repr(config.django.secret_key)}",
        "",
        f"DEBUG = {config.django.debug}",
        "",
        f"ALLOWED_HOSTS = {config.django.allowed_hosts}",
        "",
        "# Application definition",
        "INSTALLED_APPS = [",
        "    'django.contrib.admin',",
        "    'django.contrib.auth',",
        "    'django.contrib.contenttypes',",
        "    'django.contrib.sessions',",
        "    'django.contrib.messages',",
        "    'django.contrib.staticfiles',",
        "]",
        "",
        "# Database",
        "DATABASES = {",
        "    'default': {",
        "        'ENGINE': 'django.db.backends.postgresql',",
        f"        'NAME': {repr(config.database.name)},",
        f"        'HOST': {repr(config.database.host)},",
        f"        'PORT': {repr(str(config.database.port))},",
        "    }",
        "}",
        "",
        "# Internationalization",
        f"LANGUAGE_CODE = {repr(config.django.language_code)}",
        f"TIME_ZONE = {repr(config.django.time_zone)}",
        f"USE_I18N = {config.django.use_i18n}",
        f"USE_TZ = {config.django.use_tz}",
        "",
        "# Static files",
        f"STATIC_URL = {repr(config.static.url)}",
        f"STATIC_ROOT = {repr(config.static.root)}",
        "",
        "# Media files",
        f"MEDIA_URL = {repr(config.media.url)}",
        f"MEDIA_ROOT = {repr(config.media.root)}",
        "",
        "# Email",
        "EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'",
        f"EMAIL_HOST = {repr(config.email.host)}",
        f"EMAIL_PORT = {config.email.port}",
        f"EMAIL_USE_TLS = {config.email.use_tls}",
        f"DEFAULT_FROM_EMAIL = {repr(config.email.default_from)}",
        "",
        "# Security",
        f"CSRF_COOKIE_SECURE = {config.security.csrf_cookie_secure}",
        f"SESSION_COOKIE_SECURE = {config.security.session_cookie_secure}",
        f"X_FRAME_OPTIONS = {repr(config.security.x_frame_options)}",
        "",
        "# Cache",
        f"CACHE_TIMEOUT = {config.cache.timeout}",
    ]
    return "\n".join(lines)


# =============================================================================
# Main Example
# =============================================================================


def main():
    """Demonstrate Django-style configuration with prism-config."""

    print("=" * 60)
    print("Django-style Settings Example (prism-config v2.0.0)")
    print("=" * 60)
    print()

    # -------------------------------------------------------------------------
    # Step 1: Register Django-specific emojis
    # -------------------------------------------------------------------------
    print("Step 1: Registering Django-specific emojis...")
    register_emoji("django", "🦄")  # Django's pony mascot
    register_emoji("static", "📦")
    register_emoji("media", "🖼️")
    register_emoji("email", "📧")
    register_emoji("session", "🎟️")
    register_emoji("integrations", "🔗")
    print("  Registered custom emojis for Django sections")
    print()

    # -------------------------------------------------------------------------
    # Step 2: Load configuration with Django schema
    # -------------------------------------------------------------------------
    print("Step 2: Loading configuration with Django schema...")
    config_file = Path(__file__).parent / "config.yaml"

    config = PrismConfig.from_file(
        config_file,
        schema=DjangoSettingsConfig,
        resolve_secrets=True,
    )

    print(f"  Loaded from: {config_file}")
    print()

    # -------------------------------------------------------------------------
    # Step 3: Access Django settings
    # -------------------------------------------------------------------------
    print("Step 3: Accessing Django settings...")
    print()

    print("  🦄 Core Django Settings:")
    print(f"     DEBUG: {config.django.debug}")
    print(f"     ALLOWED_HOSTS: {config.django.allowed_hosts}")
    print(f"     TIME_ZONE: {config.django.time_zone}")
    print()

    print("  💾 Database Settings:")
    print(f"     HOST: {config.database.host}")
    print(f"     NAME: {config.database.name}")
    print(f"     PORT: {config.database.port}")
    print()

    print("  📧 Email Settings:")
    print(f"     HOST: {config.email.host}")
    print(f"     PORT: {config.email.port}")
    print(f"     USE_TLS: {config.email.use_tls}")
    print()

    print("  🔒 Security Settings:")
    print(f"     CSRF_COOKIE_SECURE: {config.security.csrf_cookie_secure}")
    print(f"     X_FRAME_OPTIONS: {config.security.x_frame_options}")
    print(f"     HSTS_SECONDS: {config.security.hsts_seconds}")
    print()

    print("  🔗 Integrations:")
    print(f"     Sentry Environment: {config.integrations.sentry.environment}")
    print(f"     Celery Broker: {config.integrations.celery.broker_url}")
    print()

    # -------------------------------------------------------------------------
    # Step 4: Display configuration
    # -------------------------------------------------------------------------
    print("Step 4: Beautiful display with Django emojis...")
    print()
    config.display()
    print()

    # -------------------------------------------------------------------------
    # Step 5: Generate Django settings.py
    # -------------------------------------------------------------------------
    print("Step 5: Generate Django settings.py (excerpt):")
    print("-" * 60)
    settings_code = generate_django_settings(config)
    # Show first 40 lines
    lines = settings_code.split("\n")[:40]
    print("\n".join(lines))
    print("... (truncated)")
    print("-" * 60)
    print()

    # -------------------------------------------------------------------------
    # Step 6: Usage in Django
    # -------------------------------------------------------------------------
    print("Step 6: Usage in Django settings.py:")
    print()
    print("""
    # settings.py - Option 1: Direct import
    from prism.config import PrismConfig

    config = PrismConfig.from_file(
        "config.yaml",
        schema=DjangoSettingsConfig,
        resolve_secrets=True
    )

    SECRET_KEY = config.django.secret_key
    DEBUG = config.django.debug
    ALLOWED_HOSTS = config.django.allowed_hosts

    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.postgresql',
            'NAME': config.database.name,
            'HOST': config.database.host,
            'PORT': str(config.database.port),
            'PASSWORD': config.database.password,
        }
    }

    # Option 2: Use environment-specific configs
    import os
    env = os.getenv('DJANGO_ENV', 'development')
    config = PrismConfig.from_file(f"config.{env}.yaml")
    """)

    print("=" * 60)
    print("Example complete!")
    print("=" * 60)


if __name__ == "__main__":
    main()
