"""plyra-trace span processors."""

from __future__ import annotations

import fnmatch

from opentelemetry.context import Context
from opentelemetry.sdk.trace import ReadableSpan, SpanProcessor


class NoiseFilterProcessor(SpanProcessor):
    """
    Drops spans whose names match any of the given glob patterns
    before forwarding to the wrapped processor.

    Usage:
        pt = plyra_trace.init(
            project="my-agent",
            filter_spans=[
                "starlette.*",
                "a2a.*",
                "GET /health",
                "GET /metrics",
                "http.server.*",
            ]
        )

    Patterns use fnmatch glob syntax:
        "starlette.*"   matches starlette.routing, starlette.middleware, etc.
        "GET /health"   exact match
        "a2a.*"         matches any a2a internal span
    """

    def __init__(self, wrapped: SpanProcessor, patterns: list[str]) -> None:
        self._wrapped = wrapped
        self._patterns = patterns

    def _should_drop(self, span: ReadableSpan) -> bool:
        name = span.name or ""
        return any(fnmatch.fnmatch(name, p) for p in self._patterns)

    def on_start(self, span: ReadableSpan, parent_context: Context | None = None) -> None:
        if not self._should_drop(span):
            self._wrapped.on_start(span, parent_context)

    def on_end(self, span: ReadableSpan) -> None:
        if not self._should_drop(span):
            self._wrapped.on_end(span)

    def shutdown(self) -> None:
        self._wrapped.shutdown()

    def force_flush(self, timeout_millis: int = 30000) -> bool:
        return self._wrapped.force_flush(timeout_millis)
