"""
plyra-trace semantic conventions.

Extends OpenInferenc (https://github.com/Arize-ai/openinference)
with agent-native primitives for multi-agent coordination and
policy/safety event tracing.

Full compatibility with OpenInference attribute names is maintained
for all standard span types (LLM, TOOL, RETRIEVER, EMBEDDING, etc).
"""

from enum import Enum


class SpanKind(str, Enum):  # noqa: UP042
    """
    plyra-trace span kinds.
    Stored as the string attribute "plyra.span.kind" on every span.
    OTel span kind is always set to INTERNAL (for chains/agents/tools)
    or CLIENT (for LLM/retriever calls) separately.

    Note: We use (str, Enum) for backward compatibility with Python 3.11.
    Python 3.11+ supports StrEnum but we maintain explicit inheritance.
    """

    LLM = "LLM"  # Call to a language model
    CHAIN = "CHAIN"  # Glue code linking pipeline steps
    AGENT = "AGENT"  # Autonomous reasoning block
    TOOL = "TOOL"  # External function/API call
    RETRIEVER = "RETRIEVER"  # Vector/document retrieval
    EMBEDDING = "EMBEDDING"  # Embedding generation
    RERANKER = "RERANKER"  # Document re-ranking
    GUARD = "GUARD"  # Policy/safety check (plyra-native)
    EVALUATOR = "EVALUATOR"  # Output quality assessment
    PROMPT = "PROMPT"  # Prompt template rendering
    ROUTER = "ROUTER"  # Agent routing/delegation (plyra-native)


class SpanAttributes:
    """
    Semantic attribute constants.

    Naming convention:
    - OpenInference-compatible attributes use the openinference namespace
    - plyra-native extensions use the plyra namespace
    - All plyra.guard.*, plyra.agent.handoff.*, plyra.agent.routing.*
      are new namespaces not present in OpenInference

    Full OpenInference spec:
    https://arize-ai.github.io/openinference/spec/semantic_conventions.html
    """

    # ── Core plyra attribute ──────────────────────────────────────────
    SPAN_KIND = "plyra.span.kind"  # SpanKind enum value

    # ── Input / Output (OpenInference compatible) ─────────────────────
    INPUT_VALUE = "input.value"
    INPUT_MIME_TYPE = "input.mime_type"  # "text/plain" | "application/json"
    OUTPUT_VALUE = "output.value"
    OUTPUT_MIME_TYPE = "output.mime_type"

    # ── LLM attributes (OpenInference compatible) ─────────────────────
    LLM_MODEL_NAME = "llm.model_name"
    LLM_PROVIDER = "llm.provider"  # "openai" | "anthropic" | "google" etc
    LLM_SYSTEM = "llm.system"  # Same as provider, OpenInference alias
    LLM_TOKEN_COUNT_PROMPT = "llm.token_count.prompt"
    LLM_TOKEN_COUNT_COMPLETION = "llm.token_count.completion"
    LLM_TOKEN_COUNT_TOTAL = "llm.token_count.total"
    LLM_INVOCATION_PARAMETERS = "llm.invocation_parameters"  # JSON string
    LLM_PROMPT_TEMPLATE_TEMPLATE = "llm.prompt_template.template"
    LLM_PROMPT_TEMPLATE_VARIABLES = "llm.prompt_template.variables"  # JSON string
    LLM_PROMPT_TEMPLATE_VERSION = "llm.prompt_template.version"

    # LLM input/output messages use indexed format:
    # llm.input_messages.{i}.message.role
    # llm.input_messages.{i}.message.content
    # llm.input_messages.{i}.message.name
    # llm.input_messages.{i}.message.tool_calls.{j}.tool_call.function.name
    # llm.input_messages.{i}.message.tool_calls.{j}.tool_call.function.arguments
    # llm.input_messages.{i}.message.tool_calls.{j}.tool_call.id
    # llm.output_messages.{i}.message.role
    # llm.output_messages.{i}.message.content

    # ── Tool attributes (OpenInference compatible) ────────────────────
    TOOL_NAME = "tool.name"
    TOOL_DESCRIPTION = "tool.description"
    TOOL_PARAMETERS = "tool.parameters"  # JSON schema string
    TOOL_CALL_ID = "tool.call.id"
    TOOL_CALL_FUNCTION_NAME = "tool.call.function.name"
    TOOL_CALL_FUNCTION_ARGUMENTS = "tool.call.function.arguments"  # JSON string

    # ── Retrieval attributes (OpenInference compatible) ───────────────
    RETRIEVAL_QUERY = "retrieval.query"
    RETRIEVAL_TOP_K = "retrieval.top_k"
    # Retrieval documents use indexed format:
    # retrieval.documents.{i}.document.id
    # retrieval.documents.{i}.document.content
    # retrieval.documents.{i}.document.score
    # retrieval.documents.{i}.document.metadata  (JSON string)

    # ── Embedding attributes (OpenInference compatible) ───────────────
    EMBEDDING_MODEL_NAME = "embedding.model_name"
    EMBEDDING_DIMENSIONS = "embedding.dimensions"
    # Embeddings use indexed format:
    # embedding.embeddings.{i}.embedding.text
    # embedding.embeddings.{i}.embedding.model_name
    # embedding.embeddings.{i}.embedding.vector  (omitted by default — large)

    # ── Session / User (OpenInference compatible) ─────────────────────
    SESSION_ID = "session.id"
    USER_ID = "user.id"

    # ── Metadata (OpenInference compatible) ───────────────────────────
    METADATA = "metadata"  # JSON string of arbitrary metadata
    TAG_TAGS = "tag.tags"  # JSON array of tag strings

    # ── Agent attributes (plyra-native extensions) ────────────────────
    AGENT_NAME = "agent.name"
    AGENT_DESCRIPTION = "agent.description"
    AGENT_FRAMEWORK = "agent.framework"  # "langgraph" | "crewai" | "autogen" etc
    AGENT_PATTERN = "agent.pattern"  # "ReAct" | "Chain-of-Thought" | "Tree-of-Thoughts"

    # Agent handoff (cross-agent delegation) — plyra-native
    AGENT_HANDOFF_FROM = "agent.handoff.from"
    AGENT_HANDOFF_TO = "agent.handoff.to"
    AGENT_HANDOFF_REASON = "agent.handoff.reason"
    # "in-process" | "http" | "grpc" | "mcp" | "a2a" | "queue"
    AGENT_HANDOFF_PROTOCOL = "agent.handoff.protocol"
    AGENT_HANDOFF_CONTEXT_KEYS = "agent.handoff.context_keys"  # JSON array

    # Agent routing — plyra-native
    AGENT_ROUTING_STRATEGY = "agent.routing.strategy"  # "llm-based" | "rule-based" | "semantic"
    AGENT_ROUTING_CANDIDATES = "agent.routing.candidates"  # JSON array of agent names
    AGENT_ROUTING_SELECTED = "agent.routing.selected"
    AGENT_ROUTING_SCORES = "agent.routing.scores"  # JSON object {agent_name: score}
    AGENT_ROUTING_REASON = "agent.routing.reason"

    # ── Guard attributes (plyra-native — unique to plyra-trace) ───────
    GUARD_POLICY = "guard.policy"  # Policy name e.g. "content-safety"
    GUARD_ACTION = "guard.action"  # "allow" | "block" | "redact" | "flag" | "modify"
    GUARD_TRIGGERED = "guard.triggered"  # bool
    GUARD_CONFIDENCE = "guard.confidence"  # float [0.0, 1.0]
    GUARD_DETAILS = "guard.details"  # JSON string with structured details
    GUARD_PROVIDER = "guard.provider"  # "plyra-guard" | "guardrails-ai" | "nemo-guardrails"
    GUARD_INPUT_HASH = "guard.input_hash"  # SHA256 hash of checked input
    GUARD_LATENCY_MS = "guard.latency_ms"  # int

    # ── OpenInference compatibility aliases ───────────────────────────
    # These are the exact OpenInference attribute names — kept for
    # cross-platform compatibility when exporting to Phoenix or Langfuse
    OPENINFERENCE_SPAN_KIND = "openinference.span.kind"  # Set alongside plyra.span.kind
