"""Tests for ChatWZRD — mocked, no network calls."""

from __future__ import annotations

from unittest.mock import MagicMock, patch

import pytest
from langchain_core.messages import AIMessage, HumanMessage
from langchain_core.outputs import ChatGeneration, ChatResult

from langchain_wzrd import ChatWZRD


def _mock_pick_result(model: str = "qwen/qwen3.5-9b", task: str = "code") -> MagicMock:
    result = MagicMock()
    result.model = model
    result.signal_model = model
    result.task = task
    result.score = 0.95
    result.raw_score = 0.8
    result.trend = "accelerating"
    result.confidence = "normal"
    result.action = "pre_warm"
    result.platform = "openrouter"
    result.policy = "strict"
    result.reason = "strict feed signal from openrouter"
    return result


def _mock_chat_result(content: str = "Hello!") -> ChatResult:
    return ChatResult(
        generations=[ChatGeneration(message=AIMessage(content=content))]
    )


class TestChatWZRD:
    def test_import(self):
        from langchain_wzrd import ChatWZRD
        assert ChatWZRD is not None

    def test_llm_type(self):
        llm = ChatWZRD(openai_api_key="test")
        assert llm._llm_type == "wzrd"

    def test_identifying_params(self):
        llm = ChatWZRD(task="code", fallback="gpt-4o", openai_api_key="test")
        params = llm._identifying_params
        assert params["task"] == "code"
        assert params["fallback"] == "gpt-4o"
        assert params["wzrd_report"] is False

    @patch("langchain_wzrd.chat.ChatOpenAI")
    @patch("langchain_wzrd.chat.wzrd.pick_details")
    def test_generate_routes_via_wzrd(self, mock_pick, mock_openai_cls):
        mock_pick.return_value = _mock_pick_result("qwen/qwen3.5-9b", "code")
        mock_llm = MagicMock()
        mock_llm._generate.return_value = _mock_chat_result("sorted list")
        mock_openai_cls.return_value = mock_llm

        llm = ChatWZRD(task="code", openai_api_key="sk-test")
        messages = [HumanMessage(content="Write a sort function")]
        result = llm._generate(messages)

        mock_pick.assert_called_once_with("code", candidates=None, fallback="meta-llama/llama-3.3-70b-instruct")
        mock_openai_cls.assert_called_once()
        call_kwargs = mock_openai_cls.call_args[1]
        assert call_kwargs["model"] == "qwen/qwen3.5-9b"
        assert call_kwargs["openai_api_base"] == "https://openrouter.ai/api/v1"
        assert len(result.generations) == 1

    @patch("langchain_wzrd.chat.ChatOpenAI")
    @patch("langchain_wzrd.chat.wzrd.pick_details")
    def test_candidates_passed_through(self, mock_pick, mock_openai_cls):
        mock_pick.return_value = _mock_pick_result()
        mock_openai_cls.return_value.generate.return_value = _mock_chat_result()
        mock_openai_cls.return_value._generate.return_value = _mock_chat_result()

        candidates = ["qwen/qwen3.5-9b", "meta-llama/llama-3.3-70b"]
        llm = ChatWZRD(task="code", candidates=candidates, openai_api_key="sk-test")
        llm._generate([HumanMessage(content="test")])

        mock_pick.assert_called_once_with("code", candidates=candidates, fallback="meta-llama/llama-3.3-70b-instruct")

    @patch("langchain_wzrd.chat.ChatOpenAI")
    @patch("langchain_wzrd.chat.wzrd.pick_details")
    def test_fallback_used_when_pick_fails(self, mock_pick, mock_openai_cls):
        fallback_result = _mock_pick_result("gpt-4o", "code")
        fallback_result.policy = "fallback"
        mock_pick.return_value = fallback_result
        mock_openai_cls.return_value._generate.return_value = _mock_chat_result()

        llm = ChatWZRD(task="code", fallback="gpt-4o", openai_api_key="sk-test")
        llm._generate([HumanMessage(content="test")])

        call_kwargs = mock_openai_cls.call_args[1]
        assert call_kwargs["model"] == "gpt-4o"

    @patch("langchain_wzrd.chat.ChatOpenAI")
    @patch("langchain_wzrd.chat.wzrd.pick_details")
    def test_per_invocation_routing(self, mock_pick, mock_openai_cls):
        """Each call should pick a fresh model, not reuse the first pick."""
        mock_pick.side_effect = [
            _mock_pick_result("qwen/qwen3.5-9b"),
            _mock_pick_result("meta-llama/llama-3.3-70b"),
        ]
        mock_openai_cls.return_value._generate.return_value = _mock_chat_result()

        llm = ChatWZRD(task="code", openai_api_key="sk-test")
        llm._generate([HumanMessage(content="first")])
        llm._generate([HumanMessage(content="second")])

        assert mock_pick.call_count == 2
        models_used = [call[1]["model"] for call in mock_openai_cls.call_args_list]
        assert models_used == ["qwen/qwen3.5-9b", "meta-llama/llama-3.3-70b"]

    @patch("langchain_wzrd.chat.ChatOpenAI")
    @patch("langchain_wzrd.chat.wzrd.pick_details")
    def test_no_report_by_default(self, mock_pick, mock_openai_cls):
        mock_pick.return_value = _mock_pick_result()
        mock_openai_cls.return_value._generate.return_value = _mock_chat_result()

        llm = ChatWZRD(openai_api_key="sk-test")
        llm._generate([HumanMessage(content="test")])

        assert llm.wzrd_report is False
        assert llm._agent is None
