#!/usr/bin/env python
"""
Sentry Error Reporting Setup
Configures Sentry for error tracking and monitoring.
"""

import os
import logging
from typing import Dict, Any, Optional

logger = logging.getLogger(__name__)

# Sentry integration (import only if available)
try:
    import sentry_sdk
    from sentry_sdk.integrations.logging import LoggingIntegration
    SENTRY_AVAILABLE = True
except ImportError:
    SENTRY_AVAILABLE = False
    logger.warning("Sentry SDK not installed. Error reporting disabled.")


def init_sentry(dsn: Optional[str] = None, environment: str = 'production', release: Optional[str] = None):
    """
    Initialize Sentry error tracking.

    Args:
        dsn: Sentry DSN (Data Source Name). If None, reads from SENTRY_DSN env var
        environment: Environment name (development, staging, production)
        release: Release version string
    """
    if not SENTRY_AVAILABLE:
        logger.warning("Sentry not initialized - SDK not available")
        return

    dsn = dsn or os.getenv('SENTRY_DSN')
    if not dsn:
        logger.warning("Sentry DSN not provided. Error reporting disabled.")
        return

    # Configure logging integration
    sentry_logging = LoggingIntegration(
        level=logging.INFO,        # Capture info and above as breadcrumbs
        event_level=logging.ERROR  # Send errors as events
    )

    sentry_sdk.init(
        dsn=dsn,
        environment=environment,
        release=release,
        integrations=[sentry_logging],
        traces_sample_rate=0.1,  # 10% of transactions for performance monitoring
        profiles_sample_rate=0.1,  # 10% of transactions for profiling
        send_default_pii=False,  # Don't send personally identifiable information
        before_send=before_send_filter
    )

    logger.info(f"Sentry initialized for environment: {environment}")


def before_send_filter(event, hint):
    """
    Filter/modify events before sending to Sentry.

    Args:
        event: Sentry event dictionary
        hint: Additional context

    Returns:
        Modified event or None to drop the event
    """
    # Filter out specific exceptions if needed
    if 'exc_info' in hint:
        exc_type, exc_value, tb = hint['exc_info']
        # Example: Don't report KeyboardInterrupt
        if isinstance(exc_value, KeyboardInterrupt):
            return None

    return event


def set_player_context(player_id: str, username: Optional[str] = None, email: Optional[str] = None):
    """
    Set player context for error reports.

    Args:
        player_id: Player's unique identifier
        username: Player's username (optional)
        email: Player's email (optional, only if user consents)
    """
    if not SENTRY_AVAILABLE:
        return

    sentry_sdk.set_user({
        "id": player_id,
        "username": username,
        "email": email
    })


def set_game_context(player_data: Dict[str, Any]):
    """
    Set game state context for error reports.

    Args:
        player_data: Dictionary with relevant game state
    """
    if not SENTRY_AVAILABLE:
        return

    sentry_sdk.set_context("game_state", {
        "age": player_data.get('age'),
        "location": player_data.get('location'),
        "status": player_data.get('status'),
        "energy": player_data.get('energy'),
        "money": player_data.get('money'),
        "game_date": player_data.get('date'),
        "hour_of_day": player_data.get('hourOfDay')
    })


def capture_exception(error: Exception, context: Optional[Dict[str, Any]] = None):
    """
    Manually capture an exception with optional context.

    Args:
        error: Exception to report
        context: Optional additional context
    """
    if not SENTRY_AVAILABLE:
        logger.error(f"Exception (Sentry unavailable): {error}", exc_info=error)
        return

    if context:
        with sentry_sdk.push_scope() as scope:
            for key, value in context.items():
                scope.set_context(key, value)
            sentry_sdk.capture_exception(error)
    else:
        sentry_sdk.capture_exception(error)


def capture_message(message: str, level: str = 'info', context: Optional[Dict[str, Any]] = None):
    """
    Capture a message (not an exception).

    Args:
        message: Message to capture
        level: Severity level (debug, info, warning, error, fatal)
        context: Optional additional context
    """
    if not SENTRY_AVAILABLE:
        logger.log(getattr(logging, level.upper(), logging.INFO), f"Message: {message}")
        return

    if context:
        with sentry_sdk.push_scope() as scope:
            for key, value in context.items():
                scope.set_context(key, value)
            sentry_sdk.capture_message(message, level=level)
    else:
        sentry_sdk.capture_message(message, level=level)


def add_breadcrumb(message: str, category: str = 'default', level: str = 'info', data: Optional[Dict] = None):
    """
    Add a breadcrumb for debugging context.

    Args:
        message: Breadcrumb message
        category: Category (e.g., 'game.event', 'player.action')
        level: Severity level
        data: Optional additional data
    """
    if not SENTRY_AVAILABLE:
        return

    sentry_sdk.add_breadcrumb(
        message=message,
        category=category,
        level=level,
        data=data or {}
    )


# Example usage in game code:
"""
# At server startup:
from monitoring.sentry_setup import init_sentry
init_sentry(environment='production', release='1.0.0')

# When a player connects:
from monitoring.sentry_setup import set_player_context, set_game_context
set_player_context(player_id='12345', username='john_doe')

# During gameplay:
from monitoring.sentry_setup import add_breadcrumb
add_breadcrumb('Player started conversation', category='game.conversation', data={'npc_id': 'mom'})

# On error:
try:
    # game logic
    process_event()
except Exception as e:
    from monitoring.sentry_setup import capture_exception
    capture_exception(e, context={'event_type': 'birthday'})
"""
