"""Langfuse-backed TraceProvider.

The real Langfuse client is imported lazily — tests inject a fake via the
`client` kwarg. Unknown trace ids degrade to a no-op so a buggy call site
never brings a user request down.
"""

from __future__ import annotations

from typing import Any


class LangfuseTraceProvider:
    """TraceProvider that forwards events to a Langfuse client."""

    def __init__(
        self,
        *,
        client: Any = None,
        public_key: str | None = None,
        secret_key: str | None = None,
        host: str | None = None,
    ) -> None:
        if client is None:
            from langfuse import Langfuse  # type: ignore[import-not-found]

            client = Langfuse(
                public_key=public_key, secret_key=secret_key, host=host
            )
        self._client = client
        self._traces: dict[str, Any] = {}

    def start_trace(self, name: str, **metadata: Any) -> str:
        trace = self._client.trace(name=name, metadata=metadata)
        self._traces[trace.id] = trace
        return trace.id

    def log_generation(
        self, trace_id: str, *, model: str, prompt: Any, output: Any, **metadata: Any
    ) -> None:
        trace = self._traces.get(trace_id)
        if trace is None:
            return
        trace.generation(
            model=model, input=prompt, output=output, metadata=metadata
        )

    def log_retrieval(
        self, trace_id: str, *, query: str, results: list[Any], **metadata: Any
    ) -> None:
        trace = self._traces.get(trace_id)
        if trace is None:
            return
        trace.span(
            name="retrieval",
            input={"query": query},
            output={"results": results},
            metadata=metadata,
        )

    def score(
        self, trace_id: str, *, name: str, value: float, **metadata: Any
    ) -> None:
        trace = self._traces.get(trace_id)
        if trace is None:
            return
        trace.score(name=name, value=value)

    def flush(self) -> None:
        self._client.flush()
