"""Tests for TimeContextMiddleware."""

from __future__ import annotations

import asyncio
from datetime import datetime, timezone
from unittest.mock import MagicMock

from icarus.runtime.time_context import TimeContextMiddleware
from langchain_core.messages import SystemMessage

# ---------------------------------------------------------------------------
# before_agent
# ---------------------------------------------------------------------------


class TestBeforeAgent:
    def test_first_call_sets_session_start(self):
        mw = TimeContextMiddleware()
        result = mw.before_agent({"messages": []}, MagicMock())

        assert "_time_session_start" in result

    def test_subsequent_call_returns_none(self):
        mw = TimeContextMiddleware()
        state = {
            "messages": [],
            "_time_session_start": "2026-02-26T10:00:00+00:00",
        }
        result = mw.before_agent(state, MagicMock())
        assert result is None

    def test_timestamp_is_valid_iso(self):
        mw = TimeContextMiddleware()
        result = mw.before_agent({"messages": []}, MagicMock())
        datetime.fromisoformat(result["_time_session_start"])


# ---------------------------------------------------------------------------
# _build_time_section
# ---------------------------------------------------------------------------


class TestBuildTimeSection:
    def test_contains_header_and_date(self):
        now = datetime.now().astimezone().isoformat()
        state = {"messages": [], "_time_session_start": now}
        section = TimeContextMiddleware._build_time_section(state)
        assert "## Current Time" in section
        assert "**Date**" in section

    def test_includes_session_started(self):
        now = datetime.now().astimezone().isoformat()
        state = {"messages": [], "_time_session_start": now}
        section = TimeContextMiddleware._build_time_section(state)
        assert "Session started" in section

    def test_stable_across_calls(self):
        """Same state produces identical output — key for prompt caching."""
        iso = datetime(2026, 2, 26, 10, 0, 0, tzinfo=timezone.utc).isoformat()
        state = {"messages": [], "_time_session_start": iso}
        section1 = TimeContextMiddleware._build_time_section(state)
        section2 = TimeContextMiddleware._build_time_section(state)
        assert section1 == section2

    def test_graceful_without_session_start(self):
        section = TimeContextMiddleware._build_time_section({"messages": []})
        assert "## Current Time" in section
        assert "**Date**" in section

    def test_no_volatile_now_field(self):
        """Must NOT include a volatile 'Now' field that changes per call."""
        iso = datetime.now().astimezone().isoformat()
        state = {"messages": [], "_time_session_start": iso}
        section = TimeContextMiddleware._build_time_section(state)
        assert "**Now**" not in section


# ---------------------------------------------------------------------------
# wrap_model_call
# ---------------------------------------------------------------------------


class TestWrapModelCall:
    def _make_request(self):
        now = datetime.now().astimezone().isoformat()
        request = MagicMock()
        request.system_message = SystemMessage(content="Base prompt.")
        request.state = {"messages": [], "_time_session_start": now}
        captured = {}
        request.override = lambda **kw: captured.update(kw) or MagicMock()
        return request, captured

    def test_appends_time_to_system_prompt(self):
        mw = TimeContextMiddleware()
        request, captured = self._make_request()
        mw.wrap_model_call(request, MagicMock(return_value=MagicMock()))

        result = captured["system_message"]
        assert isinstance(result, SystemMessage)
        text = str(result.text)
        assert text.startswith("Base prompt.")
        assert "Current Time" in text

    def test_async_variant(self):
        mw = TimeContextMiddleware()
        request, captured = self._make_request()

        async def handler(req):
            return MagicMock()

        asyncio.run(mw.awrap_model_call(request, handler))

        result = captured["system_message"]
        assert isinstance(result, SystemMessage)
        assert "Current Time" in str(result.text)
