"""
Regression tests: every integration must include 'llm_call_count' in the
summary dict passed to complete_trace().

No real framework dependencies required — all external packages are
imported lazily/conditionally in the integration modules.
"""
import types
import uuid
from datetime import datetime, timezone

# ------------------------------------------------------------------
# Shared mock visibe client
# ------------------------------------------------------------------

class _MockVisibe:
    """Captures the last complete_trace summary."""

    def __init__(self):
        self.session_id = None
        self._summary = None
        self._trace_header = None

    def create_trace(self, data):
        self._trace_header = data
        return True

    def queue_span(self, trace_id, span):
        return None

    def complete_trace(self, trace_id, summary):
        self._summary = summary
        return True


# ==================================================================
# OpenAI — _OpenAIGroupTracker._complete_trace()
# ==================================================================

from visibe.integrations.openai import _OpenAIGroupTracker


def _make_openai_tracker(mock_visibe, n_calls=1):
    """Build a tracker with n pre-recorded calls, bypassing start()."""
    mock_client = types.SimpleNamespace()
    integration = types.SimpleNamespace()
    tracker = _OpenAIGroupTracker(mock_visibe, mock_client, "test", integration)
    tracker.start_time = datetime.now(timezone.utc)
    tracker.end_time = datetime.now(timezone.utc)

    for i in range(n_calls):
        tracker.calls.append({
            'timestamp': datetime.now(timezone.utc),
            'model': 'gpt-4o',
            'prompt': f'prompt {i}',
            'output_text': f'response {i}',
            'input_tokens': 100,
            'output_tokens': 50,
            'cost': 0.001,
            'duration_ms': 500,
            'tools_used': [],
        })
    return tracker


def test_openai_tracker_llm_call_count_single_call():
    mock = _MockVisibe()
    tracker = _make_openai_tracker(mock, n_calls=1)
    tracker._complete_trace()
    assert mock._summary is not None
    assert mock._summary.get('llm_call_count') == 1


def test_openai_tracker_llm_call_count_multiple_calls():
    mock = _MockVisibe()
    tracker = _make_openai_tracker(mock, n_calls=3)
    tracker._complete_trace()
    assert mock._summary.get('llm_call_count') == 3


def test_openai_tracker_llm_call_count_zero_calls():
    mock = _MockVisibe()
    tracker = _make_openai_tracker(mock, n_calls=0)
    tracker._complete_trace()
    assert mock._summary.get('llm_call_count') == 0


# ==================================================================
# AutoGen — _AutoGenTracker.stop()
# ==================================================================

from visibe.integrations.autogen import _AutoGenTracker


def _make_autogen_tracker(mock_visibe, n_calls=1):
    """Build an _AutoGenTracker with n pre-recorded llm_calls."""
    mock_model_client = types.SimpleNamespace(
        create=None,
        create_stream=None,
        model_info={"family": "gpt-4o"},
    )
    tracker = _AutoGenTracker(mock_visibe, mock_model_client, "test-task")
    tracker.start_time = datetime.now(timezone.utc)
    # Prevent fallback path from firing: set _start_usage
    tracker._start_usage = (0, 0)

    for i in range(n_calls):
        tracker.llm_calls.append({
            'agent_name': 'TestAgent',
            'model': 'gpt-4o',
            'input_tokens': 80,
            'output_tokens': 40,
            'total_tokens': 120,
            'cost': 0.001,
            'duration': 0.5,
        })
        tracker.total_cost += 0.001
    return tracker


def test_autogen_tracker_llm_call_count_single_call(monkeypatch):
    mock = _MockVisibe()
    tracker = _make_autogen_tracker(mock, n_calls=1)
    # Stub _get_current_usage so fallback path is skipped
    monkeypatch.setattr(tracker, '_get_current_usage', lambda: (0, 0))
    tracker.stop()
    assert mock._summary is not None
    assert mock._summary.get('llm_call_count') == 1


def test_autogen_tracker_llm_call_count_multiple_calls(monkeypatch):
    mock = _MockVisibe()
    tracker = _make_autogen_tracker(mock, n_calls=4)
    monkeypatch.setattr(tracker, '_get_current_usage', lambda: (0, 0))
    tracker.stop()
    assert mock._summary.get('llm_call_count') == 4


def test_autogen_tracker_llm_call_count_zero_calls(monkeypatch):
    mock = _MockVisibe()
    tracker = _make_autogen_tracker(mock, n_calls=0)
    monkeypatch.setattr(tracker, '_get_current_usage', lambda: (0, 0))
    tracker.stop()
    assert mock._summary.get('llm_call_count') == 0


# ==================================================================
# Bedrock — _BedrockGroupTracker._complete_trace()
# ==================================================================

from visibe.integrations.bedrock import _BedrockGroupTracker


def _make_bedrock_tracker(mock_visibe, n_calls=1):
    """Build a Bedrock group tracker with n pre-recorded calls."""
    mock_bedrock_client = types.SimpleNamespace()
    mock_integration = types.SimpleNamespace()
    tracker = _BedrockGroupTracker(
        mock_visibe, mock_bedrock_client, "test-bedrock", mock_integration
    )
    tracker.start_time = datetime.now(timezone.utc)
    tracker.end_time = datetime.now(timezone.utc)

    for i in range(n_calls):
        tracker.calls.append({
            'prompt': f'prompt {i}',
            'model': 'amazon.nova-micro-v1:0',
            'input_tokens': 60,
            'output_tokens': 30,
            'cost': 0.0005,
            'tools_used': [],
        })
    return tracker


def test_bedrock_group_tracker_llm_call_count_single_call():
    mock = _MockVisibe()
    tracker = _make_bedrock_tracker(mock, n_calls=1)
    tracker._complete_trace()
    assert mock._summary is not None
    assert mock._summary.get('llm_call_count') == 1


def test_bedrock_group_tracker_llm_call_count_multiple_calls():
    mock = _MockVisibe()
    tracker = _make_bedrock_tracker(mock, n_calls=5)
    tracker._complete_trace()
    assert mock._summary.get('llm_call_count') == 5


def test_bedrock_group_tracker_llm_call_count_zero_calls():
    mock = _MockVisibe()
    tracker = _make_bedrock_tracker(mock, n_calls=0)
    tracker.calls = []  # ensure empty
    # _complete_trace guards against empty calls for prompt/model
    tracker._complete_trace()
    assert mock._summary.get('llm_call_count') == 0


# ==================================================================
# LangChain — LangChainIntegration._complete_trace()
# ==================================================================

from visibe.integrations.langchain import LangChainIntegration


def _make_langchain_integration(mock_visibe):
    integration = LangChainIntegration.__new__(LangChainIntegration)
    integration.client = mock_visibe
    integration._framework = 'langchain'
    integration._content_limit = 1000
    integration._tool_content_limit = 500
    return integration


def _make_langchain_callback(n_calls=1):
    """Minimal fake LangChainCallback with enough state for _complete_trace."""
    now = datetime.now(timezone.utc)
    llm_calls = []
    for i in range(n_calls):
        llm_calls.append({
            'agent_name': 'langchain',
            'model': 'gpt-4o',
            'input_tokens': 50,
            'output_tokens': 25,
            'cost': 0.0005,
        })

    def get_metrics():
        total_input = sum(c['input_tokens'] for c in llm_calls)
        total_output = sum(c['output_tokens'] for c in llm_calls)
        return {
            'total_input_tokens': total_input,
            'total_output_tokens': total_output,
            'total_cost': sum(c['cost'] for c in llm_calls),
            'end_time': now.isoformat(),
            'duration_ms': 200,
            'steps': [{'type': 'llm_call'} for _ in llm_calls],
            'agents_executed': ['langchain'],
        }

    return types.SimpleNamespace(
        trace_id=str(uuid.uuid4()),
        llm_calls=llm_calls,
        prompt='What is 2+2?',
        _root_agent_name='',
        agents_executed=['langchain'],
        get_metrics=get_metrics,
    )


def test_langchain_complete_trace_llm_call_count_single_call():
    mock = _MockVisibe()
    integration = _make_langchain_integration(mock)
    callback = _make_langchain_callback(n_calls=1)
    integration._complete_trace(callback, 'completed', 'test')
    assert mock._summary is not None
    assert mock._summary.get('llm_call_count') == 1


def test_langchain_complete_trace_llm_call_count_multiple_calls():
    mock = _MockVisibe()
    integration = _make_langchain_integration(mock)
    callback = _make_langchain_callback(n_calls=6)
    integration._complete_trace(callback, 'completed', 'test')
    assert mock._summary.get('llm_call_count') == 6


def test_langchain_complete_trace_llm_call_count_zero_calls():
    mock = _MockVisibe()
    integration = _make_langchain_integration(mock)
    callback = _make_langchain_callback(n_calls=0)
    integration._complete_trace(callback, 'completed', 'test')
    assert mock._summary.get('llm_call_count') == 0
