from __future__ import annotations

from dataclasses import dataclass
from typing import Any, Dict, List

from entropic_core.core.llm_middleware import LLMMiddleware, LLMProvider, MiddlewareConfig
from entropic_core.core.runtime_events import RuntimeEvent


@dataclass
class _ListSink:
    events: List[Dict[str, Any]]

    def emit(self, event: RuntimeEvent) -> None:
        self.events.append(event.to_dict())


def test_runtime_events_emitted_request_and_response() -> None:
    sink = _ListSink(events=[])
    cfg = MiddlewareConfig(event_sink=sink, run_id="run_test")
    m = LLMMiddleware(config=cfg)

    def fn(*args: Any, **kwargs: Any) -> Dict[str, Any]:
        return {
            "model": kwargs.get("model", ""),
            "choices": [
                {
                    "message": {
                        "content": "{\"answer\":\"ok\",\"evidence_ids\":[],\"confidence\":0.5,\"notes\":\"\"}"
                    },
                    "finish_reason": "stop",
                }
            ],
            "usage": {"prompt_tokens": 1, "completion_tokens": 1, "total_tokens": 2},
        }

    wrapped = m.wrap(fn, provider=LLMProvider.OPENAI)
    wrapped(
        model="mock",
        messages=[{"role": "system", "content": "x"}, {"role": "user", "content": "y"}],
    )

    types = [e["type"] for e in sink.events]
    assert "request" in types
    assert "response" in types

    req = next(e for e in sink.events if e["type"] == "request")
    resp = next(e for e in sink.events if e["type"] == "response")
    assert req["request_id"] == resp["request_id"]
    assert req["run_id"] == "run_test"
