# ========= Copyright 2023-2026 @ CAMEL-AI.org. All Rights Reserved. =========
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ========= Copyright 2023-2026 @ CAMEL-AI.org. All Rights Reserved. =========

from unittest.mock import MagicMock

import pytest

from camel.configs import ZhipuAIConfig
from camel.models import ZhipuAIModel
from camel.types import ModelType
from camel.utils import OpenAITokenCounter


@pytest.mark.model_backend
@pytest.mark.parametrize(
    "model_type",
    [
        # GLM-5 series (latest)
        ModelType.GLM_5_2,
        ModelType.GLM_5_1,
        ModelType.GLM_5,
        # GLM-4.7 series
        ModelType.GLM_4_7,
        ModelType.GLM_4_7_FLASHX,
        ModelType.GLM_4_7_FLASH,
        # GLM-4.6 series
        ModelType.GLM_4_6,
        # GLM-4 series
        ModelType.GLM_4,
        ModelType.GLM_4_5_AIR,
        ModelType.GLM_4_5_AIRX,
        ModelType.GLM_4_5_FLASH,
        ModelType.GLM_4V,
        ModelType.GLM_4_1V_THINKING_FLASHX,
        ModelType.GLM_4_1V_THINKING_FLASH,
        ModelType.GLM_4V_FLASH,
        ModelType.GLM_4V_PLUS_0111,
        # GLM-4 legacy models
        ModelType.GLM_4_PLUS,
        ModelType.GLM_4_AIR,
        ModelType.GLM_4_AIR_0111,
        ModelType.GLM_4_AIRX,
        ModelType.GLM_4_LONG,
        ModelType.GLM_4_FLASHX,
        ModelType.GLM_4_FLASHX_250414,
        ModelType.GLM_4_FLASH,
        ModelType.GLM_4_FLASH_250414,
        # GLM-Zero series (reasoning models)
        ModelType.GLM_ZERO_PREVIEW,
        ModelType.GLM_3_TURBO,
        # GLM Vision models (VLM)
        ModelType.GLM_4_6V,
        ModelType.GLM_4_6V_FLASHX,
        ModelType.GLM_4_5V,
        ModelType.GLM_4_6V_FLASH,
    ],
)
def test_zhipuai_model(model_type: ModelType, monkeypatch):
    monkeypatch.setenv("ZHIPUAI_API_KEY", "test_key")
    model = ZhipuAIModel(model_type)
    assert model.model_type == model_type
    assert model.model_config_dict == ZhipuAIConfig().as_dict()
    assert isinstance(model.token_counter, OpenAITokenCounter)
    assert isinstance(model.model_type.value_for_tiktoken, str)
    assert isinstance(model.model_type.token_limit, int)
    assert model.model_type.is_zhipuai


@pytest.mark.model_backend
def test_zhipuai_glm_5_2_token_limit():
    assert ModelType.GLM_5_2.token_limit == 1_000_000


@pytest.mark.model_backend
def test_zhipuai_glm_5_1_token_limit():
    assert ModelType.GLM_5_1.token_limit == 200_000


@pytest.mark.model_backend
def test_zhipuai_model_reasoning_effort_config(monkeypatch):
    monkeypatch.setenv("ZHIPUAI_API_KEY", "test_key")
    config = ZhipuAIConfig(reasoning_effort="high")
    model = ZhipuAIModel(
        ModelType.GLM_5_2,
        model_config_dict=config.as_dict(),
    )

    request_config = model._prepare_request_config()
    assert request_config["reasoning_effort"] == "high"


@pytest.mark.model_backend
def test_zhipuai_model_thinking_config(monkeypatch):
    """Test that interleaved_thinking configuration is properly set."""
    monkeypatch.setenv("ZHIPUAI_API_KEY", "test_key")
    config = ZhipuAIConfig(interleaved_thinking=True)
    model = ZhipuAIModel(
        ModelType.GLM_4_PLUS,
        model_config_dict=config.as_dict(),
    )
    assert model.model_config_dict.get("interleaved_thinking") is True
    assert model._is_thinking_enabled() is True


@pytest.mark.model_backend
def test_zhipuai_model_thinking_disabled(monkeypatch):
    """Test that interleaved_thinking is disabled by default."""
    monkeypatch.setenv("ZHIPUAI_API_KEY", "test_key")
    model = ZhipuAIModel(ModelType.GLM_4_PLUS)
    assert model._is_thinking_enabled() is False


@pytest.mark.model_backend
def test_zhipuai_model_inject_reasoning_content(monkeypatch):
    """Test reasoning_content injection into assistant messages."""
    monkeypatch.setenv("ZHIPUAI_API_KEY", "test_key")
    config = ZhipuAIConfig(interleaved_thinking=True)
    model = ZhipuAIModel(
        ModelType.GLM_4_PLUS,
        model_config_dict=config.as_dict(),
    )

    # Set up test messages with tool calls
    messages = [
        {"role": "user", "content": "Hello"},
        {
            "role": "assistant",
            "content": None,
            "tool_calls": [{"id": "call_123", "function": {"name": "test"}}],
        },
        {"role": "tool", "content": "result", "tool_call_id": "call_123"},
    ]

    # Set the last reasoning content
    model._last_reasoning = "This is my reasoning"

    # Inject reasoning content
    processed = model._inject_reasoning(messages)

    # Check that reasoning_content was injected
    assert processed[1].get("reasoning_content") == "This is my reasoning"
    # Check that _last_reasoning was cleared
    assert model._last_reasoning is None


@pytest.mark.model_backend
def test_zhipuai_model_inject_reasoning_content_disabled(monkeypatch):
    """Test that reasoning_content is not injected when disabled."""
    monkeypatch.setenv("ZHIPUAI_API_KEY", "test_key")
    model = ZhipuAIModel(ModelType.GLM_4_PLUS)

    messages = [
        {"role": "user", "content": "Hello"},
        {
            "role": "assistant",
            "content": None,
            "tool_calls": [{"id": "call_123", "function": {"name": "test"}}],
        },
    ]

    model._last_reasoning = "This is my reasoning"
    processed = model._inject_reasoning(messages)

    # Should return original messages unchanged
    assert processed == messages
    # reasoning content should not be cleared when thinking is disabled
    assert model._last_reasoning == "This is my reasoning"


@pytest.mark.model_backend
def test_zhipuai_model_extract_reasoning_content(monkeypatch):
    """Test extraction of reasoning_content from response."""
    monkeypatch.setenv("ZHIPUAI_API_KEY", "test_key")
    model = ZhipuAIModel(ModelType.GLM_4_PLUS)

    # Create a mock response with reasoning_content
    mock_response = MagicMock()
    mock_message = MagicMock()
    mock_message.reasoning_content = "Extracted reasoning"
    mock_choice = MagicMock()
    mock_choice.message = mock_message
    mock_response.choices = [mock_choice]

    result = model._extract_reasoning(mock_response)
    assert result == "Extracted reasoning"


@pytest.mark.model_backend
def test_zhipuai_model_extract_reasoning_content_none(monkeypatch):
    """Test extraction returns None when no reasoning_content."""
    monkeypatch.setenv("ZHIPUAI_API_KEY", "test_key")
    model = ZhipuAIModel(ModelType.GLM_4_PLUS)

    # Create a mock response without reasoning_content
    mock_response = MagicMock()
    mock_message = MagicMock(spec=[])  # No reasoning_content attribute
    mock_choice = MagicMock()
    mock_choice.message = mock_message
    mock_response.choices = [mock_choice]

    result = model._extract_reasoning(mock_response)
    assert result is None
