"""
Configuration management for StarPunk
Loads settings from environment variables and .env file
"""

import os
from pathlib import Path
from dotenv import load_dotenv


def load_config(app, config_override=None):
    """
    Load configuration into Flask app

    Args:
        app: Flask application instance
        config_override: Optional dict to override config values
    """
    # Load .env file
    load_dotenv()

    # Site configuration
    # IndieWeb/OAuth specs require trailing slash for root URLs used as client_id
    # See: https://indielogin.com/ OAuth client requirements
    site_url = os.getenv("SITE_URL", "http://localhost:5000")
    app.config["SITE_URL"] = site_url if site_url.endswith('/') else site_url + '/'
    app.config["SITE_NAME"] = os.getenv("SITE_NAME", "StarPunk")
    app.config["SITE_AUTHOR"] = os.getenv("SITE_AUTHOR", "Unknown")
    app.config["SITE_DESCRIPTION"] = os.getenv(
        "SITE_DESCRIPTION", "A minimal IndieWeb CMS"
    )

    # Authentication
    app.config["ADMIN_ME"] = os.getenv("ADMIN_ME")
    app.config["SESSION_SECRET"] = os.getenv("SESSION_SECRET")
    app.config["SESSION_LIFETIME"] = int(os.getenv("SESSION_LIFETIME", "30"))
    app.config["INDIELOGIN_URL"] = os.getenv("INDIELOGIN_URL", "https://indielogin.com")

    # DEPRECATED: TOKEN_ENDPOINT no longer used (v1.0.0-rc.5+)
    # Endpoints are now discovered from ADMIN_ME profile (ADR-031)
    if 'TOKEN_ENDPOINT' in os.environ:
        app.logger.warning(
            "TOKEN_ENDPOINT is deprecated and will be ignored. "
            "Remove it from your configuration. "
            "Endpoints are now discovered automatically from your ADMIN_ME profile. "
            "See docs/migration/fix-hardcoded-endpoints.md for details."
        )

    # Validate required configuration
    if not app.config["SESSION_SECRET"]:
        raise ValueError(
            "SESSION_SECRET must be set in .env file. "
            'Generate with: python3 -c "import secrets; print(secrets.token_hex(32))"'
        )

    # Flask secret key (uses SESSION_SECRET by default)
    # Note: We check for truthy value to handle empty string in .env
    flask_secret = os.getenv("FLASK_SECRET_KEY")
    app.config["SECRET_KEY"] = flask_secret if flask_secret else app.config["SESSION_SECRET"]

    # Data paths
    app.config["DATA_PATH"] = Path(os.getenv("DATA_PATH", "./data"))
    app.config["NOTES_PATH"] = Path(os.getenv("NOTES_PATH", "./data/notes"))
    app.config["DATABASE_PATH"] = Path(os.getenv("DATABASE_PATH", "./data/starpunk.db"))

    # Flask environment
    app.config["ENV"] = os.getenv("FLASK_ENV", "development")
    app.config["DEBUG"] = os.getenv("FLASK_DEBUG", "1") == "1"

    # Logging
    app.config["LOG_LEVEL"] = os.getenv("LOG_LEVEL", "INFO")

    # Development mode configuration
    app.config["DEV_MODE"] = os.getenv("DEV_MODE", "false").lower() == "true"
    app.config["DEV_ADMIN_ME"] = os.getenv("DEV_ADMIN_ME", "")

    # Application version (use __version__ from package)
    from starpunk import __version__
    app.config["VERSION"] = os.getenv("VERSION", __version__)

    # RSS feed configuration
    app.config["FEED_MAX_ITEMS"] = int(os.getenv("FEED_MAX_ITEMS", "50"))
    app.config["FEED_CACHE_SECONDS"] = int(os.getenv("FEED_CACHE_SECONDS", "300"))

    # Feed caching (v1.1.2 Phase 3)
    app.config["FEED_CACHE_ENABLED"] = os.getenv("FEED_CACHE_ENABLED", "true").lower() == "true"
    app.config["FEED_CACHE_MAX_SIZE"] = int(os.getenv("FEED_CACHE_MAX_SIZE", "50"))

    # Upload limits (v1.4.2)
    # Flask MAX_CONTENT_LENGTH limits request body size (matches media.py MAX_FILE_SIZE)
    app.config["MAX_CONTENT_LENGTH"] = 50 * 1024 * 1024  # 50MB

    # Metrics configuration (v1.1.2 Phase 1)
    app.config["METRICS_ENABLED"] = os.getenv("METRICS_ENABLED", "true").lower() == "true"
    app.config["METRICS_SLOW_QUERY_THRESHOLD"] = float(os.getenv("METRICS_SLOW_QUERY_THRESHOLD", "1.0"))
    app.config["METRICS_SAMPLING_RATE"] = float(os.getenv("METRICS_SAMPLING_RATE", "1.0"))
    app.config["METRICS_BUFFER_SIZE"] = int(os.getenv("METRICS_BUFFER_SIZE", "1000"))
    app.config["METRICS_MEMORY_INTERVAL"] = int(os.getenv("METRICS_MEMORY_INTERVAL", "30"))

    # Debug file configuration (v1.5.0 Phase 2)
    app.config["DEBUG_SAVE_FAILED_UPLOADS"] = os.getenv("DEBUG_SAVE_FAILED_UPLOADS", "false").lower() == "true"
    app.config["DEBUG_FILE_MAX_AGE_DAYS"] = int(os.getenv("DEBUG_FILE_MAX_AGE_DAYS", "7"))
    app.config["DEBUG_FILE_MAX_SIZE_MB"] = int(os.getenv("DEBUG_FILE_MAX_SIZE_MB", "100"))

    # Apply overrides if provided
    if config_override:
        app.config.update(config_override)

    # Normalize SITE_URL trailing slash (in case override provided URL without slash)
    if "SITE_URL" in app.config:
        site_url = app.config["SITE_URL"]
        app.config["SITE_URL"] = site_url if site_url.endswith('/') else site_url + '/'

    # Convert path strings to Path objects (in case overrides provided strings)
    if isinstance(app.config["DATA_PATH"], str):
        app.config["DATA_PATH"] = Path(app.config["DATA_PATH"])
    if isinstance(app.config["NOTES_PATH"], str):
        app.config["NOTES_PATH"] = Path(app.config["NOTES_PATH"])
    if isinstance(app.config["DATABASE_PATH"], str):
        app.config["DATABASE_PATH"] = Path(app.config["DATABASE_PATH"])

    # Validate configuration
    validate_config(app)

    # Ensure data directories exist
    app.config["DATA_PATH"].mkdir(parents=True, exist_ok=True)
    app.config["NOTES_PATH"].mkdir(parents=True, exist_ok=True)


def validate_config(app):
    """
    Validate application configuration on startup

    Per ADR-052 and developer Q&A Q14:
    - Validates at startup (fail fast)
    - Checks both presence and type of required values
    - Provides clear error messages
    - Exits with non-zero status on failure

    Ensures required configuration is present based on mode (dev/production)
    and warns prominently if development mode is enabled.

    Args:
        app: Flask application instance

    Raises:
        ValueError: If required configuration is missing or invalid
    """
    errors = []

    # Validate required string fields
    required_strings = {
        'SITE_URL': app.config.get('SITE_URL'),
        'SITE_NAME': app.config.get('SITE_NAME'),
        'SITE_AUTHOR': app.config.get('SITE_AUTHOR'),
        'SESSION_SECRET': app.config.get('SESSION_SECRET'),
        'SECRET_KEY': app.config.get('SECRET_KEY'),
    }

    for field, value in required_strings.items():
        if not value:
            errors.append(f"{field} is required but not set")
        elif not isinstance(value, str):
            errors.append(f"{field} must be a string, got {type(value).__name__}")

    # Validate required integer fields
    required_ints = {
        'SESSION_LIFETIME': app.config.get('SESSION_LIFETIME'),
        'FEED_MAX_ITEMS': app.config.get('FEED_MAX_ITEMS'),
        'FEED_CACHE_SECONDS': app.config.get('FEED_CACHE_SECONDS'),
    }

    for field, value in required_ints.items():
        if value is None:
            errors.append(f"{field} is required but not set")
        elif not isinstance(value, int):
            errors.append(f"{field} must be an integer, got {type(value).__name__}")
        elif value < 0:
            errors.append(f"{field} must be non-negative, got {value}")

    # Validate required Path fields
    required_paths = {
        'DATA_PATH': app.config.get('DATA_PATH'),
        'NOTES_PATH': app.config.get('NOTES_PATH'),
        'DATABASE_PATH': app.config.get('DATABASE_PATH'),
    }

    for field, value in required_paths.items():
        if not value:
            errors.append(f"{field} is required but not set")
        elif not isinstance(value, Path):
            errors.append(f"{field} must be a Path object, got {type(value).__name__}")

    # Validate LOG_LEVEL
    log_level = app.config.get('LOG_LEVEL', 'INFO').upper()
    valid_log_levels = ['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL']
    if log_level not in valid_log_levels:
        errors.append(f"LOG_LEVEL must be one of {valid_log_levels}, got '{log_level}'")

    # Mode-specific validation
    dev_mode = app.config.get("DEV_MODE", False)

    if dev_mode:
        # Prominently warn about development mode
        app.logger.warning(
            "=" * 60 + "\n"
            "WARNING: Development authentication enabled!\n"
            "This should NEVER be used in production.\n"
            "Set DEV_MODE=false for production deployments.\n" + "=" * 60
        )

        # Require DEV_ADMIN_ME in dev mode
        if not app.config.get("DEV_ADMIN_ME"):
            errors.append(
                "DEV_MODE=true requires DEV_ADMIN_ME to be set. "
                "Set DEV_ADMIN_ME=https://your-dev-identity.example.com in .env"
            )
    else:
        # Production mode: ADMIN_ME is required
        if not app.config.get("ADMIN_ME"):
            errors.append(
                "Production mode requires ADMIN_ME to be set. "
                "Set ADMIN_ME=https://your-site.com in .env"
            )

    # If there are validation errors, fail fast with clear message
    if errors:
        error_msg = "\n".join([
            "=" * 70,
            "CONFIGURATION VALIDATION FAILED",
            "=" * 70,
            "The following configuration errors were found:",
            "",
            *[f"  - {error}" for error in errors],
            "",
            "Please fix these errors in your .env file and restart.",
            "=" * 70
        ])
        raise ValueError(error_msg)
