"""Tests for Veloscope SDK core functionality."""

import pytest
import veloscope
import veloscope.core as core
from veloscope.core import (
    _spans_buffer,
    _generate_trace_id,
    _generate_span_id,
)


@pytest.fixture(autouse=True)
def reset_state():
    """Clear state before each test."""
    _spans_buffer.clear()
    core._enabled = True
    core._api_key = "vs_test_key_for_testing_only_fake"
    yield
    _spans_buffer.clear()


class TestInit:
    def test_init_with_key(self):
        core._enabled = False
        veloscope.init(api_key="vs_test_key_for_testing_only_fake")
        assert core._enabled is True

    def test_init_without_key_is_noop(self):
        core._api_key = None
        core._enabled = False
        veloscope.init(api_key=None)
        assert core._enabled is False


class TestIDGeneration:
    def test_trace_id_length(self):
        tid = _generate_trace_id()
        assert len(tid) == 32
        assert all(c in "0123456789abcdef" for c in tid)

    def test_span_id_length(self):
        sid = _generate_span_id()
        assert len(sid) == 16
        assert all(c in "0123456789abcdef" for c in sid)

    def test_ids_are_unique(self):
        ids = {_generate_trace_id() for _ in range(100)}
        assert len(ids) == 100


class TestTraceDecorator:
    def test_trace_creates_span(self):
        @veloscope.trace("test-agent")
        def my_agent():
            return "hello"

        result = my_agent()
        assert result == "hello"
        assert len(_spans_buffer) == 1
        span = _spans_buffer[0]
        assert span["name"] == "test-agent"
        assert span["status"] == "ok"
        assert span["parent_span_id"] is None
        assert len(span["trace_id"]) == 32
        assert len(span["span_id"]) == 16

    def test_trace_captures_error(self):
        @veloscope.trace("failing-agent")
        def failing_agent():
            raise ValueError("test error")

        try:
            failing_agent()
        except ValueError:
            pass

        assert len(_spans_buffer) == 1
        span = _spans_buffer[0]
        assert span["status"] == "error"
        assert span["error_message"] == "test error"


class TestSpanDecorator:
    def test_span_within_trace(self):
        @veloscope.trace("parent-agent")
        def my_agent():
            return child_step()

        @veloscope.span("child-step", span_type="tool")
        def child_step():
            return 42

        result = my_agent()
        assert result == 42
        assert len(_spans_buffer) == 2

        child = _spans_buffer[0]
        parent = _spans_buffer[1]
        assert child["name"] == "child-step"
        assert child["span_type"] == "tool"
        assert child["parent_span_id"] == parent["span_id"]
        assert child["trace_id"] == parent["trace_id"]

    def test_span_without_trace_is_noop(self):
        @veloscope.span("orphan-span")
        def orphan():
            return "no trace"

        result = orphan()
        assert result == "no trace"
        assert len(_spans_buffer) == 0
