# =============================================================================
# 企微IT智能服务台 — H5 摇人功能测试
# =============================================================================
# 测试覆盖：
#   1. 摇人成功（新建会话 + 举手标记 + 趣味话术返回）
#   2. 摇人成功（已有会话 + 更新举手标记）
#   3. 缺少 employee_id 请求失败
#   4. 获取当前会话
#   5. H5 发送消息
#   6. 审批链接获取
#   7. 软件下载列表获取
# =============================================================================

import pytest
import pytest_asyncio
from unittest.mock import AsyncMock, patch

from app.models.conversation import Conversation
from app.models.funny_phrase import FunnyPhrase
from tests.conftest import create_test_conversation, MockRedis


class TestShakeEndpoint:
    """测试摇人 API 端点。"""

    @pytest.mark.asyncio
    async def test_shake_creates_new_conversation(self, client, db_session):
        """验证摇人时如果没有活跃会话则创建新会话。"""
        # 先添加趣味话术
        phrase = FunnyPhrase(scene="shake", content="摇人话术测试", tone="亲切", sort_order=1)
        db_session.add(phrase)
        await db_session.flush()

        response = await client.post(
            "/h5/conversations/current/shake",
            json={"employee_id": "shake_new_user", "employee_name": "测试员工"},
        )

        assert response.status_code == 200
        data = response.json()
        assert data["code"] == 0
        assert data["data"]["conversation"]["tags"]["hand_raise"] is True
        assert data["data"]["funny_phrase"] != ""

    @pytest.mark.asyncio
    async def test_shake_updates_existing_conversation(self, client, db_session):
        """验证摇人时如果已有活跃会话则更新举手标记。"""
        conv = create_test_conversation(
            employee_id="shake_existing_user",
            status="queued",
            tags={},
        )
        db_session.add(conv)
        await db_session.flush()

        # 添加话术
        phrase = FunnyPhrase(scene="shake", content="更新摇人话术", tone="亲切", sort_order=1)
        db_session.add(phrase)
        await db_session.flush()

        response = await client.post(
            "/h5/conversations/current/shake",
            json={"employee_id": "shake_existing_user", "employee_name": "已有用户"},
        )

        assert response.status_code == 200
        data = response.json()
        assert data["code"] == 0
        assert data["data"]["conversation"]["tags"]["hand_raise"] is True

    @pytest.mark.asyncio
    async def test_shake_returns_funny_phrase(self, client, db_session):
        """验证摇人返回趣味话术。"""
        phrase = FunnyPhrase(scene="shake", content="测试趣味话术内容", tone="亲切", sort_order=1)
        db_session.add(phrase)
        await db_session.flush()

        response = await client.post(
            "/h5/conversations/current/shake",
            json={"employee_id": "phrase_test_user", "employee_name": "话术测试"},
        )

        data = response.json()
        assert data["data"]["funny_phrase"] != ""


class TestH5CurrentConversation:
    """测试 H5 获取当前会话。"""

    @pytest.mark.asyncio
    async def test_get_current_conversation_exists(self, client, db_session, mock_redis):
        """验证获取当前活跃会话。"""
        # 预设 Bearer Token（替代旧的 X-Employee-Id 头）
        await mock_redis.setex("employee:token:h5_current_token", 28800, "h5_current_user")

        conv = create_test_conversation(employee_id="h5_current_user", status="queued")
        db_session.add(conv)
        await db_session.flush()

        response = await client.get(
            "/h5/conversations/current",
            headers={"Authorization": "Bearer h5_current_token"},
        )

        assert response.status_code == 200
        data = response.json()
        assert data["code"] == 0
        assert data["data"] is not None

    @pytest.mark.asyncio
    async def test_get_current_conversation_not_found(self, client, db_session, mock_redis):
        """验证无活跃会话时返回空数据。"""
        # 预设 Bearer Token
        await mock_redis.setex("employee:token:no_conv_token", 28800, "no_conversation_user")

        response = await client.get(
            "/h5/conversations/current",
            headers={"Authorization": "Bearer no_conv_token"},
        )

        assert response.status_code == 200
        data = response.json()
        assert data["code"] == 0
        assert data["data"] is None

    @pytest.mark.asyncio
    async def test_get_current_conversation_no_employee_id(self, client, db_session):
        """验证缺少员工ID时返回未授权错误。"""
        response = await client.get("/h5/conversations/current")
        assert response.status_code == 200
        data = response.json()
        assert data["code"] != 0  # 应返回错误码


class TestH5SendMessage:
    """测试 H5 发送消息。"""

    @pytest.mark.asyncio
    async def test_send_message_creates_conversation(self, client, db_session, mock_redis):
        """验证发送消息时自动创建会话。"""
        # 预设 Bearer Token
        await mock_redis.setex("employee:token:h5_msg_token", 28800, "h5_msg_user")

        response = await client.post(
            "/h5/conversations/current/messages",
            json={"content": "VPN连不上了"},
            headers={"Authorization": "Bearer h5_msg_token"},
        )

        assert response.status_code == 200
        data = response.json()
        assert data["code"] == 0
        assert data["data"]["content"] == "VPN连不上了"

    @pytest.mark.asyncio
    async def test_send_message_empty_content(self, client, db_session, mock_redis):
        """验证空消息内容返回错误。"""
        # 预设 Bearer Token
        await mock_redis.setex("employee:token:empty_msg_token", 28800, "empty_msg_user")

        response = await client.post(
            "/h5/conversations/current/messages",
            json={"content": ""},
            headers={"Authorization": "Bearer empty_msg_token"},
        )

        data = response.json()
        assert data["code"] != 0


class TestApprovalLinks:
    """测试审批链接获取。"""

    @pytest.mark.asyncio
    async def test_get_approval_links(self, client, seeded_db):
        """验证获取审批链接列表。"""
        response = await client.get("/h5/approval-links")

        assert response.status_code == 200
        data = response.json()
        assert data["code"] == 0
        assert len(data["data"]["items"]) > 0

    @pytest.mark.asyncio
    async def test_get_approval_links_by_category(self, client, seeded_db):
        """验证按分类过滤审批链接。"""
        response = await client.get("/h5/approval-links?category=IT")

        assert response.status_code == 200
        data = response.json()
        assert data["code"] == 0
        for item in data["data"]["items"]:
            assert item["category"] == "IT"


class TestSoftwareDownloads:
    """测试软件下载列表。"""

    @pytest.mark.asyncio
    async def test_get_software_downloads(self, client, seeded_db):
        """验证获取软件下载列表。"""
        response = await client.get("/h5/software-downloads")

        assert response.status_code == 200
        data = response.json()
        assert data["code"] == 0
        assert len(data["data"]["items"]) > 0

    @pytest.mark.asyncio
    async def test_get_software_downloads_by_category(self, client, seeded_db):
        """验证按分类过滤软件下载。"""
        response = await client.get("/h5/software-downloads?category=办公")

        assert response.status_code == 200
        data = response.json()
        assert data["code"] == 0
        for item in data["data"]["items"]:
            assert item["category"] == "办公"
