"""OpenTelemetry tracing and metrics initialization."""

import os
from typing import Any

from opentelemetry import metrics, trace
from opentelemetry.exporter.otlp.proto.grpc.metric_exporter import OTLPMetricExporter
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor
from opentelemetry.instrumentation.httpx import HTTPXClientInstrumentor
from opentelemetry.instrumentation.psycopg2 import Psycopg2Instrumentor
from opentelemetry.instrumentation.redis import RedisInstrumentor
from opentelemetry.sdk.metrics import MeterProvider
from opentelemetry.sdk.metrics.export import (
    MetricExporter,
    PeriodicExportingMetricReader,
)
from opentelemetry.sdk.resources import Resource
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor, SpanExporter


def init_opentelemetry(
    service_name: str,
    service_version: str = "1.0.0",
    otlp_endpoint: str | None = None,
) -> tuple[Any, Any]:
    """Initialize OpenTelemetry tracing and metrics"""

    # Create resource
    resource = Resource.create(
        {
            "service.name": service_name,
            "service.version": service_version,
            "service.instance.id": os.getenv("HOSTNAME", "unknown"),
        }
    )

    # Configure tracing
    span_exporter: SpanExporter
    if otlp_endpoint:
        span_exporter = OTLPSpanExporter(endpoint=otlp_endpoint)
        span_processor = BatchSpanProcessor(span_exporter)
    else:
        # Use console exporter for development
        try:
            # pylint: disable=import-outside-toplevel
            from opentelemetry.sdk.trace.export import ConsoleSpanExporter

            span_exporter = ConsoleSpanExporter()
        except ImportError:
            # Fallback to logging exporter
            # pylint: disable=import-outside-toplevel
            from opentelemetry.sdk.trace.export import ConsoleSpanExporter

            span_exporter = ConsoleSpanExporter()
        span_processor = BatchSpanProcessor(span_exporter)

    tracer_provider = TracerProvider(resource=resource)
    tracer_provider.add_span_processor(span_processor)
    trace.set_tracer_provider(tracer_provider)

    # Configure metrics
    metric_exporter: MetricExporter
    if otlp_endpoint:
        metric_exporter = OTLPMetricExporter(endpoint=otlp_endpoint)
        metric_reader = PeriodicExportingMetricReader(
            metric_exporter, export_interval_millis=30000
        )
    else:
        # Use console exporter for development
        try:
            # pylint: disable=import-outside-toplevel
            from opentelemetry.sdk.metrics.export import ConsoleMetricExporter

            metric_exporter = ConsoleMetricExporter()
        except ImportError:
            # Fallback to logging exporter
            from opentelemetry.sdk.metrics.export import ConsoleMetricExporter

            metric_exporter = ConsoleMetricExporter()
        metric_reader = PeriodicExportingMetricReader(
            metric_exporter, export_interval_millis=30000
        )

    meter_provider = MeterProvider(resource=resource, metric_readers=[metric_reader])
    metrics.set_meter_provider(meter_provider)

    # Auto-instrument common libraries
    try:
        FastAPIInstrumentor().instrument()
        HTTPXClientInstrumentor().instrument()
        Psycopg2Instrumentor().instrument()
        RedisInstrumentor().instrument()
    except Exception:  # pylint: disable=broad-exception-caught
        # Ignore instrumentation errors in tests
        pass

    return trace.get_tracer(service_name), metrics.get_meter(service_name)
