from unittest.mock import AsyncMock, patch

from app.agent import MoviePilotAgent
from app.agent.llm import AgentCapabilityManager, LLMHelper
from app.chain.message import MessageChain
from app.core.config import settings
from app.schemas.types import MessageChannel


def test_llm_supports_image_input_uses_model_catalog_text_only(monkeypatch):
    """内置目录明确为纯文本模型时，应自动关闭图片输入。"""
    monkeypatch.setattr(settings, "LLM_SUPPORT_IMAGE_INPUT", True)

    assert not LLMHelper.supports_image_input(
        provider="minimax",
        model="MiniMax-M2.7",
    )


def test_llm_supports_image_input_keeps_known_vision_model(monkeypatch):
    """内置目录明确为视觉模型时，应允许图片输入。"""
    monkeypatch.setattr(settings, "LLM_SUPPORT_IMAGE_INPUT", True)

    assert LLMHelper.supports_image_input(
        provider="zhipuai",
        model="glm-5v-turbo",
    )


def test_llm_supports_image_input_keeps_unknown_model_override(monkeypatch):
    """未知自定义模型保持用户开关语义，避免误伤私有视觉模型。"""
    monkeypatch.setattr(settings, "LLM_SUPPORT_IMAGE_INPUT", True)

    assert LLMHelper.supports_image_input(
        provider="custom-provider",
        model="custom-vlm-model",
    )


def test_agent_capability_manager_delegates_image_support():
    """Agent 能力管理器应复用统一的模型图片能力判断。"""
    with patch.object(LLMHelper, "supports_image_input", return_value=False) as supports:
        assert not AgentCapabilityManager.supports_image_input()

    supports.assert_called_once_with()


def test_handle_ai_message_routes_text_only_model_images_to_files(monkeypatch):
    """纯文本模型收到图片消息时，应降级为文件附件而非 image_url 内容块。"""
    chain = MessageChain()
    monkeypatch.setattr(settings, "AI_AGENT_ENABLE", True)
    monkeypatch.setattr(settings, "LLM_SUPPORT_IMAGE_INPUT", True)
    monkeypatch.setattr(settings, "LLM_PROVIDER", "minimax")
    monkeypatch.setattr(settings, "LLM_MODEL", "MiniMax-M2.7")

    with patch.object(
        chain, "_get_or_create_session_id", return_value="session-1"
    ), patch.object(
        chain, "_download_attachments_to_data_urls"
    ) as download_images, patch.object(
        chain,
        "_prepare_agent_files",
        return_value=[
            {
                "name": "image_1.jpg",
                "mime_type": "image/jpeg",
                "local_path": "/tmp/image_1.jpg",
                "status": "ready",
            }
        ],
    ) as prepare_files, patch(
        "app.chain.message.agent_manager.process_message", new_callable=AsyncMock
    ) as process_message, patch(
        "app.chain.message.asyncio.run_coroutine_threadsafe",
        side_effect=lambda coro, _loop: coro.close(),
    ):
        chain._handle_ai_message(
            text="/ai 帮我看看这张图",
            channel=MessageChannel.Telegram,
            source="telegram-test",
            userid="10001",
            username="tester",
            images=["tg://file_id/image-1"],
        )

    download_images.assert_not_called()
    prepare_files.assert_called_once()
    assert prepare_files.call_args.kwargs["files"][0].ref == "tg://file_id/image-1"
    assert process_message.call_args.kwargs["images"] is None
    assert process_message.call_args.kwargs["files"][0]["local_path"] == "/tmp/image_1.jpg"


def test_unsupported_image_error_recognizes_vlm_text_only_message():
    """兼容端点返回 not a VLM 时，应识别为图片输入能力错误。"""
    error = Exception(
        "Error code: 400 - {'code': 20041, 'message': "
        "'The model is not a VLM (Vision Language Model). "
        "Please use text-only prompts.'}"
    )

    assert MoviePilotAgent._is_unsupported_image_input_error(error)
