"""Response 协议帧字段验证。

通过 ``FakeLinkskyClient`` 拦截所有 ``send_text``，断言 JSON 字段。
"""

from __future__ import annotations

import base64
import json

from linksoul_agentsdk.agent_param import AgentParam
from linksoul_agentsdk.passive.asr2_llm import Asr2LlmResponse
from linksoul_agentsdk.passive.audio2_tts import Audio2TtsResponse
from linksoul_agentsdk.passive.base import GreetResponse

from .conftest import FakeLinkskyClient
from linksoul_agentsdk.agent_sdk import AgentSdk


def _client():
    sdk = AgentSdk.create("wss://e/v1", "app", "test-app-key", "0123456789abcdef0123456789abcdef")
    return FakeLinkskyClient(sdk)


# ---- 通用 envelope ----


def test_envelope_includes_agent_mode_and_cid():
    client = _client()
    r = Asr2LlmResponse(client, "AGENT_1", "cid_x")
    r.on_llm_item_delta("ev_1", "item_1", "hello")
    sent = client.sent[0]["json"]
    assert sent["agentId"] == "AGENT_1"
    assert sent["robotCid"] == "cid_x"
    assert sent["cid"] == "cid_x"
    assert sent["eventId"] == "ev_1"
    assert sent["agentMode"] == "passive"


# ---- 各方法对应事件 type ----


def test_asr_llm_response_methods():
    client = _client()
    r = Asr2LlmResponse(client, "A", "C")
    r.on_llm_item_delta("ev", "it", "x")
    r.on_llm_item_done("ev", "it")
    r.on_llm_done("ev")
    types = [s["json"]["type"] for s in client.sent]
    assert types == [
        "agentsdk.llm_response.item.delta",
        "agentsdk.llm_response.item.done",
        "agentsdk.llm_response.done",
    ]
    assert client.sent[0]["json"]["itemId"] == "it"
    assert client.sent[0]["json"]["text"] == "x"


def test_on_interrupt_carries_type_and_tips():
    client = _client()
    r = Asr2LlmResponse(client, "A", "C")
    r.on_interrupt("ev", "risk_control", "敏感话题")
    payload = client.sent[0]["json"]
    assert payload["type"] == "agentsdk.xlm_response.interrupt"
    assert payload["interruptType"] == "risk_control"
    assert payload["interruptTips"] == "敏感话题"


def test_on_interrupt_chat_tips_can_be_none():
    client = _client()
    r = Asr2LlmResponse(client, "A", "C")
    r.on_interrupt("ev", "chat", None)
    payload = client.sent[0]["json"]
    assert payload["interruptType"] == "chat"
    assert payload["interruptTips"] is None


def test_on_skill_includes_skill_param_fields():
    client = _client()
    r = Asr2LlmResponse(client, "A", "C")
    sp = AgentParam.create().set_string("movement", "move_forward").set_integer("meter", 10)
    r.on_skill("ev", "it", "movement", "move_forward", sp)
    payload = client.sent[0]["json"]
    assert payload["type"] == "agentsdk.xlm_response.skill"
    assert payload["skillType"] == "movement"
    assert payload["skillName"] == "move_forward"
    assert payload["skillParam"] == {"movement": "move_forward", "meter": 10}


def test_on_skill_without_param():
    client = _client()
    r = Asr2LlmResponse(client, "A", "C")
    r.on_skill("ev", "it", "status", "freeze", None)
    payload = client.sent[0]["json"]
    assert "skillParam" not in payload


def test_tts_item_delta_base64_audio_and_sanitized_log():
    client = _client()
    r = Audio2TtsResponse(client, "A", "C")
    audio = b"\x01\x02\x03\x04"
    r.on_tts_item_delta("ev", "it", audio)
    sent = client.sent[0]
    payload = sent["json"]
    assert payload["audio"] == base64.b64encode(audio).decode()
    assert payload["audioLen"] == 4
    # 日志侧应剔除 audio
    log_payload = json.loads(sent["log_text"])
    assert "audio" not in log_payload
    assert log_payload["audioLen"] == 4


def test_on_error_envelope():
    client = _client()
    r = Asr2LlmResponse(client, "A", "C")
    r.on_error("ev", 1010, "boom")
    payload = client.sent[0]["json"]
    assert payload["type"] == "agentsdk.error"
    assert payload["errorCode"] == 1010
    assert payload["errorMsg"] == "boom"


# ---- GreetResponse 双路 ----


def test_greet_response_vlm_and_tts():
    client = _client()
    r = GreetResponse(client, "A", "C")
    r.on_greet_vlm_delta("ev", "hi")
    r.on_greet_vlm_done("ev")
    r.on_greet_tts_delta("ev", "你好")
    r.on_greet_tts_done("ev")
    types = [s["json"]["type"] for s in client.sent]
    assert types == [
        "agentsdk.greet_response.vlm.delta",
        "agentsdk.greet_response.vlm.done",
        "agentsdk.greet_response.tts.delta",
        "agentsdk.greet_response.tts.done",
    ]
