import base64
from typing import Optional, Union, Tuple
import os

# 1. SDK Check (Brain/Muscle Separation)
try:
    from opentelemetry.sdk.trace import TracerProvider
    from opentelemetry.sdk.trace.export import BatchSpanProcessor
    from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
    from opentelemetry.sdk.resources import Resource
    HAS_OTEL_SDK = True
except ImportError:
    HAS_OTEL_SDK = False

from opentelemetry import trace, metrics
from opentelemetry.propagate import set_global_textmap
from opentelemetry.propagators.composite import CompositePropagator
from opentelemetry.baggage.propagation import W3CBaggagePropagator
from opentelemetry.trace.propagation.tracecontext import TraceContextTextMapPropagator
from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor
from opentelemetry.instrumentation.httpx import HTTPXClientInstrumentor

from guardianhub.config.settings import settings
from guardianhub import get_logger
from guardianhub.observability.otel_middlewares import SovereignContextProcessor

logger = get_logger(__name__)

def configure_instrumentation(
    app,
    enable_console_export: bool = False,
    excluded_urls: str = "/health,/metrics",
    httpx_excluded_urls: Union[str, Tuple[str, ...]] = "/health,/metrics",
) -> None:
    # 1️⃣ Setup Global Propagation (Crucial: Works even without SDK)
    set_global_textmap(CompositePropagator([
        TraceContextTextMapPropagator(),
        W3CBaggagePropagator()
    ]))
    logger.info("Configured Global Composite Propagator (TraceContext + Baggage)")

    if not HAS_OTEL_SDK:
        logger.warning("OpenTelemetry SDK not found. Running in Propagation-Only mode.")
        return

    # 2️⃣ Setup Resource and Tracer Provider
    otlp_endpoint = settings.endpoints.get("LANGFUSE_HOST")
    
    resource = Resource.create({
        "service.name": settings.service.name,
        "deployment.environment": settings.endpoints.ENVIRONMENT,
        "service.version": settings.service.version,
    })

    tracer_provider = TracerProvider(resource=resource)

    # 3️⃣ Register Sovereign Processor (The Tenant Mapping)
    tracer_provider.add_span_processor(SovereignContextProcessor())

    # 4️⃣ Configure OTLP Trace Exporter WITH Resilient Timeout
    print(f"OTLP Endpoint: {otlp_endpoint}")
    if otlp_endpoint:
        # Use getattr to avoid the AttributeError if Pydantic hasn't mapped them to the root
        pk = getattr(settings.credentials, "LANGFUSE_PUBLIC_KEY", os.getenv("LANGFUSE_PUBLIC_KEY"))
        sk = getattr(settings.credentials, "LANGFUSE_SECRET_KEY", os.getenv("LANGFUSE_SECRET_KEY"))

        if not pk or not sk:
            logger.error("❌ OTLP Auth failed: Keys not found in settings or environment.")
            return

        # 1. Prepare Headers
        auth_str = f"{pk}:{sk}"
        encoded_auth = base64.b64encode(auth_str.encode()).decode()

        project_id = getattr(settings.credentials, "LANGFUSE_PROJECT_ID", os.getenv("LANGFUSE_PROJECT_ID"))

        # 2. Use the BASE bridge URL (The SDK will append /v1/traces)
        # If your SDK version DOES NOT append it, use the full path.
        # But usually, providing the base /otel/ path is safer.
        base_otel_endpoint = "http://langfuse.guardianhub.com/api/public/otel/v1/traces"

        trace_exporter = OTLPSpanExporter(
            endpoint=base_otel_endpoint,
            headers={
                "Authorization": f"Basic {encoded_auth}",
                "x-langfuse-project-id": project_id  # <--- CRITICAL ADDITION
            },
            timeout=10  # Give it time to breathe
        )

        # Use BatchSpanProcessor
        tracer_provider.add_span_processor(BatchSpanProcessor(trace_exporter))
        logger.info(f"Traces exported to: {otlp_endpoint}/api/public/otel (Auth Enabled)")

    trace.set_tracer_provider(tracer_provider)

    # 5️⃣ Instrument FastAPI & HTTPX
    FastAPIInstrumentor.instrument_app(
        app=app,
        tracer_provider=tracer_provider,
        excluded_urls=excluded_urls,
        http_capture_headers_server_request=["user-agent", "content-type", "x-tenant-id"],
        http_capture_headers_server_response=["content-type"]
    )

    excluded_urls_param = ",".join(httpx_excluded_urls) if isinstance(httpx_excluded_urls, tuple) else httpx_excluded_urls
    HTTPXClientInstrumentor().instrument(
        excluded_urls=excluded_urls_param,
        tracer_provider=tracer_provider
    )

    logger.info("Instrumentation complete: Tenant-Aware and Langfuse-Ready.")