"""
OpenTelemetry Logs Integration for SigNoz
Exports structured logs to SigNoz via OpenTelemetry Collector using HTTP protocol
"""

import os
import logging
import structlog
from typing import Optional
from opentelemetry._logs import set_logger_provider
from opentelemetry.sdk._logs import LoggerProvider, LoggingHandler
from opentelemetry.sdk._logs.export import BatchLogRecordProcessor
from opentelemetry.sdk.resources import Resource

# Try to import HTTP log exporter (logs always use HTTP)
try:
    from opentelemetry.exporter.otlp.proto.http._log_exporter import OTLPLogExporter
    HTTP_LOG_EXPORTER_AVAILABLE = True
except ImportError:
    try:
        from opentelemetry.exporter.otlp.proto.http.log_exporter import OTLPLogExporter
        HTTP_LOG_EXPORTER_AVAILABLE = True
    except ImportError:
        OTLPLogExporter = None
        HTTP_LOG_EXPORTER_AVAILABLE = False

from .otel_config import OTelConfig

logger = structlog.get_logger()


def setup_otel_logging(
    service_name: str,
    service_version: str = "1.0.0",
    otel_endpoint: Optional[str] = None,
    enable_console: bool = True
) -> Optional[LoggingHandler]:
    """
    Setup OpenTelemetry logging to export logs to SigNoz.

    Uses HTTP protocol (port 4318) for sending logs to SigNoz.
    Integrates with Python's standard logging to automatically export
    all log records to SigNoz via the OTLP HTTP protocol.

    Args:
        service_name: Name of the service (e.g., "auth-service")
        service_version: Version of the service
        otel_endpoint: Optional override for OTLP endpoint (HTTP format with path)
        enable_console: Whether to also log to console (default: True)

    Returns:
        LoggingHandler instance if successful, None otherwise

    Example:
        from shared.monitoring.logs_exporter import setup_otel_logging

        # Setup during service initialization
        handler = setup_otel_logging("auth-service", "1.0.0")

        # Now all standard logging calls will be exported to SigNoz
        import logging
        logger = logging.getLogger(__name__)
        logger.info("This will appear in SigNoz!")
    """

    # Check if logging export is enabled
    if not OTelConfig.is_enabled("logs"):
        logger.info(
            "OpenTelemetry logs export disabled",
            service=service_name,
            reason="OTEL_LOGS_EXPORTER not set to 'otlp'"
        )
        return None

    # Check if HTTP log exporter is available
    if not HTTP_LOG_EXPORTER_AVAILABLE or OTLPLogExporter is None:
        logger.warning(
            "OpenTelemetry HTTP log exporter not available",
            service=service_name,
            reason="opentelemetry-exporter-otlp-proto-http package not installed"
        )
        return None

    try:
        # Get endpoints from centralized config
        endpoints = OTelConfig.get_endpoints()

        # Use provided endpoint or get from config
        if otel_endpoint:
            http_endpoint = OTelConfig._ensure_http_endpoint(otel_endpoint, "/v1/logs")
        else:
            http_endpoint = endpoints.logs_http

        # Get resource attributes
        resource_attrs = OTelConfig.get_resource_attributes(service_name, service_version)
        resource = Resource(attributes=resource_attrs)

        # Configure logger provider
        logger_provider = LoggerProvider(resource=resource)
        set_logger_provider(logger_provider)

        # Configure OTLP HTTP exporter for logs
        otlp_exporter = OTLPLogExporter(
            endpoint=http_endpoint,
            timeout=10
        )

        # Add log record processor with batching
        log_processor = BatchLogRecordProcessor(otlp_exporter)
        logger_provider.add_log_record_processor(log_processor)

        # Create logging handler that bridges standard logging to OpenTelemetry
        otel_handler = LoggingHandler(
            level=logging.NOTSET,  # Capture all levels
            logger_provider=logger_provider
        )

        # Add handler to root logger
        root_logger = logging.getLogger()
        root_logger.addHandler(otel_handler)

        logger.info(
            "OpenTelemetry logs export configured successfully",
            service=service_name,
            http_endpoint=http_endpoint,
            protocol="http",
            console_logging=enable_console
        )

        return otel_handler

    except Exception as e:
        logger.error(
            "Failed to setup OpenTelemetry logs export",
            service=service_name,
            error=str(e)
        )
        return None


def add_log_context(**context):
    """
    Add contextual information to logs that will be sent to SigNoz.

    This is useful for adding request IDs, user IDs, tenant IDs, etc.
    that help with filtering and correlation in SigNoz.

    Args:
        **context: Key-value pairs to add to log context

    Example:
        from shared.monitoring.logs_exporter import add_log_context

        # Add context for current request
        add_log_context(
            request_id="req_123",
            user_id="user_456",
            tenant_id="tenant_789"
        )

        # Now all logs will include this context
        logger.info("Processing order")  # Will include request_id, user_id, tenant_id
    """
    # This works with structlog's context binding
    bound_logger = structlog.get_logger()
    return bound_logger.bind(**context)


def get_current_trace_context() -> dict:
    """
    Get current trace context for log correlation.

    Returns a dict with trace_id and span_id if available,
    which can be added to log records for correlation with traces.

    Returns:
        Dict with trace_id and span_id, or empty dict if no active trace

    Example:
        from shared.monitoring.logs_exporter import get_current_trace_context

        # Get trace context and add to logs
        trace_ctx = get_current_trace_context()
        logger.info("Processing request", **trace_ctx)
    """
    from opentelemetry import trace

    span = trace.get_current_span()
    if span and span.get_span_context().is_valid:
        return {
            "trace_id": format(span.get_span_context().trace_id, '032x'),
            "span_id": format(span.get_span_context().span_id, '016x'),
        }
    return {}


class StructlogOTELProcessor:
    """
    Structlog processor that adds OpenTelemetry trace context to logs.

    This automatically adds trace_id and span_id to all log records,
    enabling correlation between logs and traces in SigNoz.

    Usage:
        import structlog
        from shared.monitoring.logs_exporter import StructlogOTELProcessor

        structlog.configure(
            processors=[
                StructlogOTELProcessor(),
                # ... other processors
            ]
        )
    """

    def __call__(self, logger, method_name, event_dict):
        """Add trace context to log event"""
        trace_ctx = get_current_trace_context()
        if trace_ctx:
            event_dict.update(trace_ctx)
        return event_dict
