"""Tests for staso.client and staso.init/shutdown."""
from __future__ import annotations

import json

import pytest

import staso as st
from staso.client import _set_client, get_client
from staso.config import Config
from staso.provider import TracerProvider


class TestInit:
    def test_init_returns_client(self):
        client = st.init(api_key="ak_test", agent_id="test-agent", enabled=False)
        assert isinstance(client, st.Client)

    def test_init_sets_global_client(self):
        assert get_client() is None
        st.init(api_key="ak_test", agent_id="test-agent", enabled=False)
        assert get_client() is not None

    def test_init_config_passed_through(self):
        client = st.init(
            api_key="ak_123",
            agent_id="agent-x",
            environment="staging",
            enabled=False,
        )
        assert client.config.api_key == "ak_123"
        assert client.config.agent_id == "agent-x"
        assert client.config.environment == "staging"

    def test_init_keyword_only(self):
        with pytest.raises(TypeError):
            st.init("ak_test", "agent")  # type: ignore[misc]


class TestClient:
    def test_config_property(self):
        cfg = Config(api_key="ak_test", agent_id="test", enabled=False)
        client = st.Client(cfg)
        assert client.config is cfg

    def test_provider_property(self):
        cfg = Config(api_key="ak_test", agent_id="test", enabled=False)
        client = st.Client(cfg)
        assert isinstance(client.provider, TracerProvider)

    def test_no_transport_when_disabled(self):
        cfg = Config(api_key="ak_test", agent_id="test", enabled=False)
        client = st.Client(cfg)
        assert client._transport is None

    def test_transport_created_when_enabled(self):
        client = st.init(api_key="ak_test", agent_id="test", enabled=True)
        assert client._transport is not None
        client.shutdown()


class TestShutdown:
    def test_shutdown_without_init(self):
        st.shutdown()  # Should not raise

    def test_shutdown_after_init(self):
        st.init(api_key="ak_test", agent_id="test", enabled=False)
        st.shutdown()


class TestGetClient:
    def test_returns_none_before_init(self):
        _set_client(None)  # type: ignore[arg-type]
        assert get_client() is None

    def test_returns_client_after_init(self):
        client = st.init(api_key="ak_test", agent_id="test", enabled=False)
        assert get_client() is client


class TestManualSpan:
    def test_span_creates_and_captures(self, capturing):
        import staso as st
        with st.span("my-operation") as s:
            s.metadata["custom_key"] = "custom_value"

        assert len(capturing) == 1
        assert capturing[0]["name"] == "my-operation"
        assert capturing[0]["kind"] == "chain"
        assert capturing[0]["status"] == "ok"
        attrs = json.loads(capturing[0]["attributes"])
        assert attrs["custom_key"] == "custom_value"

    def test_span_with_kind(self, capturing):
        import staso as st
        with st.span("tool-call", kind="tool") as s:
            pass

        assert capturing[0]["kind"] == "tool"

    def test_span_with_spankind_enum(self, capturing):
        import staso as st
        from staso.types import SpanKind
        with st.span("llm-call", kind=SpanKind.LLM) as s:
            s.model = "test-model"

        assert capturing[0]["kind"] == "llm"
        assert capturing[0]["model"] == "test-model"

    def test_span_nesting(self, capturing):
        import staso as st
        with st.span("parent") as parent:
            with st.span("child") as child:
                pass

        assert len(capturing) == 2
        assert capturing[0]["trace_id"] == capturing[1]["trace_id"]

    def test_span_records_exception(self, capturing):
        import staso as st
        import pytest
        with pytest.raises(ValueError):
            with st.span("failing"):
                raise ValueError("boom")

        assert capturing[0]["status"] == "error"
        assert capturing[0]["error_message"] == "boom"


class TestEnvVarConfig:
    def test_init_from_env_vars(self, monkeypatch):
        monkeypatch.setenv("STASO_API_KEY", "ak_env")
        monkeypatch.setenv("STASO_AGENT_ID", "env-agent")
        monkeypatch.setenv("STASO_ENVIRONMENT", "staging")
        monkeypatch.setenv("STASO_DEBUG", "true")

        client = st.init(enabled=False)
        assert client.config.api_key == "ak_env"
        assert client.config.agent_id == "env-agent"
        assert client.config.environment == "staging"
        assert client.config.debug is True

    def test_args_override_env_vars(self, monkeypatch):
        monkeypatch.setenv("STASO_API_KEY", "ak_env")
        monkeypatch.setenv("STASO_AGENT_ID", "env-agent")

        client = st.init(api_key="ak_direct", agent_id="direct-agent", enabled=False)
        assert client.config.api_key == "ak_direct"
        assert client.config.agent_id == "direct-agent"

    def test_missing_api_key_raises(self, monkeypatch):
        monkeypatch.delenv("STASO_API_KEY", raising=False)
        with pytest.raises(ValueError, match="api_key is required"):
            st.init(agent_id="test")

    def test_missing_agent_id_raises(self, monkeypatch):
        monkeypatch.delenv("STASO_AGENT_ID", raising=False)
        with pytest.raises(ValueError, match="agent_id is required"):
            st.init(api_key="ak_test")
