"""Tests for EstimateTokenCounter multimodal support."""

from astrbot.core.agent.context.token_counter import (
    AUDIO_TOKEN_ESTIMATE,
    IMAGE_TOKEN_ESTIMATE,
    EstimateTokenCounter,
)
from astrbot.core.agent.message import (
    AudioURLPart,
    ImageURLPart,
    Message,
    TextPart,
    ThinkPart,
)

counter = EstimateTokenCounter()


def _msg(role: str, content) -> Message:
    return Message(role=role, content=content)


class TestTextCounting:
    def test_plain_string(self):
        tokens = counter.count_tokens([_msg("user", "hello world")])
        assert tokens > 0

    def test_chinese(self):
        # 中文字符权重更高
        en = counter.count_tokens([_msg("user", "abc")])
        zh = counter.count_tokens([_msg("user", "你好啊")])
        assert zh > en

    def test_text_part(self):
        msg = _msg("user", [TextPart(text="hello")])
        assert counter.count_tokens([msg]) > 0


class TestMultimodalCounting:
    def test_image_counted(self):
        msg = _msg(
            "user",
            [
                ImageURLPart(
                    image_url=ImageURLPart.ImageURL(url="data:image/png;base64,abc")
                ),
            ],
        )
        tokens = counter.count_tokens([msg])
        assert tokens == IMAGE_TOKEN_ESTIMATE

    def test_audio_counted(self):
        msg = _msg(
            "user",
            [
                AudioURLPart(
                    audio_url=AudioURLPart.AudioURL(url="https://x.com/a.mp3")
                ),
            ],
        )
        tokens = counter.count_tokens([msg])
        assert tokens == AUDIO_TOKEN_ESTIMATE

    def test_think_counted(self):
        msg = _msg("assistant", [ThinkPart(think="let me think about this")])
        tokens = counter.count_tokens([msg])
        assert tokens > 0

    def test_mixed_content(self):
        """文本 + 图片的多模态消息，token 数 = 文本 token + 图片估算。"""
        text_only = _msg("user", [TextPart(text="describe this image")])
        mixed = _msg(
            "user",
            [
                TextPart(text="describe this image"),
                ImageURLPart(
                    image_url=ImageURLPart.ImageURL(url="data:image/png;base64,x")
                ),
            ],
        )
        text_tokens = counter.count_tokens([text_only])
        mixed_tokens = counter.count_tokens([mixed])
        assert mixed_tokens == text_tokens + IMAGE_TOKEN_ESTIMATE

    def test_multiple_images(self):
        """多张图片应该各自计算。"""
        msg = _msg(
            "user",
            [
                ImageURLPart(
                    image_url=ImageURLPart.ImageURL(url="data:image/png;base64,a")
                ),
                ImageURLPart(
                    image_url=ImageURLPart.ImageURL(url="data:image/png;base64,b")
                ),
                ImageURLPart(
                    image_url=ImageURLPart.ImageURL(url="data:image/png;base64,c")
                ),
            ],
        )
        tokens = counter.count_tokens([msg])
        assert tokens == IMAGE_TOKEN_ESTIMATE * 3


class TestTrustedUsage:
    def test_trusted_overrides(self):
        """如果 API 返回了 token 数，直接用它不做估算。"""
        msg = _msg(
            "user",
            [
                TextPart(text="hello"),
                ImageURLPart(
                    image_url=ImageURLPart.ImageURL(url="data:image/png;base64,x")
                ),
            ],
        )
        tokens = counter.count_tokens([msg], trusted_token_usage=42)
        assert tokens == 42


class TestToolCalls:
    def test_tool_calls_counted(self):
        msg = Message(
            role="assistant",
            content="calling tool",
            tool_calls=[
                {
                    "type": "function",
                    "id": "1",
                    "function": {
                        "name": "get_weather",
                        "arguments": '{"city": "Beijing"}',
                    },
                }
            ],
        )
        tokens = counter.count_tokens([msg])
        # 文本 + tool call JSON 都应被计算
        text_only = counter.count_tokens([_msg("assistant", "calling tool")])
        assert tokens > text_only
