# #region TestAgentChat.Confirmations [C:3] [TYPE Module] [SEMANTICS test,agent,confirmation,hitl]
# @BRIEF Supplementary HITL confirmation flow tests — concurrent send, unknown action, model edge cases.
# @RELATION BINDS_TO -> [AgentChat.GradioApp.Handler]
# @TEST_EDGE: concurrent_send -> handler yields CONCURRENT_SEND error
# @TEST_EDGE: confirm_without_conversation_id -> handler still processes confirm
# @NOTE Resume confirm/deny handler tests are in test_agent_handler.py (test_handler_resume_confirm,
#       test_handler_resume_deny). Model-level state machine tests are in AgentChatModel.test.ts.
import os
from pathlib import Path
import sys
from unittest.mock import MagicMock, patch

sys.path.append(str(Path(__file__).parent.parent.parent / "src"))

import pytest

import jwt

JWT_SECRET = "test-jwt-secret-key"
os.environ["JWT_SECRET"] = JWT_SECRET
os.environ["OPENAI_API_KEY"] = "sk-test-key"
os.environ["LLM_API_KEY"] = "sk-test-key"
os.environ["LLM_MODEL"] = "gpt-4o"
os.environ["LLM_BASE_URL"] = "https://api.openai.com/v1"


def _make_test_jwt(user_id: str = "test-user") -> str:
    return jwt.encode({"sub": user_id}, JWT_SECRET, algorithm="HS256")


# #region TestAgentChat.Confirmations.Concurrent [C:2] [TYPE Function] [SEMANTICS test,confirmation,concurrent]
# @BRIEF Concurrent send lock prevents multiple simultaneous sends from same user.

@pytest.mark.asyncio
async def test_concurrent_send_lock():
    """Handler rejects concurrent sends from same user with CONCURRENT_SEND error."""
    from src.agent.app import _user_locks, agent_handler

    # Manually lock an anonymous user
    _user_locks["anon_test-conv"] = True

    history: list = []
    mock_request = MagicMock()
    mock_request.headers = {}
    mock_request.client.host = "127.0.0.1"

    message = {"text": "hello", "files": None}

    results = []
    async for chunk in agent_handler(message, history, mock_request, "test-conv", None):
        results.append(chunk)

    assert len(results) == 1
    import json
    parsed = json.loads(results[0]) if isinstance(results[0], str) else results[0]
    assert parsed["metadata"]["code"] == "CONCURRENT_SEND"

    # Clean up
    _user_locks.pop("anon_test-conv", None)
# #endregion TestAgentChat.Confirmations.Concurrent


# #region TestAgentChat.Confirmations.UnknownAction [C:2] [TYPE Function] [SEMANTICS test,confirmation,unknown]
# @BRIEF Non-confirm/deny action values are treated as normal messages.

@pytest.mark.asyncio
async def test_handler_unknown_action_treated_as_normal():
    """Handler with unknown action string proceeds as normal message send."""
    from src.agent.app import agent_handler

    history: list = []
    mock_request = MagicMock()
    token = _make_test_jwt()
    mock_request.headers = {"authorization": f"Bearer {token}"}
    mock_request.client.host = "127.0.0.1"

    message = {"text": "hello", "files": None}

    with patch("src.agent.app.create_agent") as mock_create:
        mock_graph = MagicMock()
        async def _mock_stream(*args, **kwargs):
            yield {"event": "on_chat_model_stream", "data": {"chunk": MagicMock(content="Hello")}}
        mock_graph.astream_events = _mock_stream
        mock_create.return_value = mock_graph

        results = []
        async for chunk in agent_handler(message, history, mock_request, "test-conv", "unknown_action"):
            results.append(chunk)

        # Should produce stream tokens, not confirm_resolved
        assert len(results) > 0
        import json
        meta_types = [json.loads(r)["metadata"]["type"] for r in results]
        assert "stream_token" in meta_types
        assert "confirm_resolved" not in meta_types
# #endregion TestAgentChat.Confirmations.UnknownAction


# #region TestAgentChat.Confirmations.ExpiredState [C:2] [TYPE Function] [SEMANTICS test,confirmation,expired]
# @BRIEF Stale confirmations — checkpoint no longer available.

@pytest.mark.asyncio
async def test_handler_confirm_no_graph():
    """Handler with action='confirm' but create_agent raises handles it gracefully."""
    from src.agent.app import agent_handler

    history: list = []
    mock_request = MagicMock()
    token = _make_test_jwt()
    mock_request.headers = {"authorization": f"Bearer {token}"}
    mock_request.client.host = "127.0.0.1"

    message = {"text": "confirm", "files": None}

    with patch("src.agent.app.create_agent") as mock_create:
        mock_create.side_effect = Exception("Graph creation failed")

        try:
            results = []
            async for chunk in agent_handler(message, history, mock_request, "test-conv", "confirm"):
                results.append(chunk)
            # Exception may propagate or be caught — either is acceptable
        except Exception:
            pass
# #endregion TestAgentChat.Confirmations.ExpiredState
# #endregion TestAgentChat.Confirmations
