#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
模块名称：create_supplementary_cases.py
模块描述：补充用例较少页面的深层交互测试用例

目标页面：
- 会议服务统计（数据分析模块）- 补充筛选器验证、图表验证
- 消息通知（信息发布模块）- 补充筛选器验证、操作按钮验证
- 设备列表（集控控制模块）- 补充表格数据验证、刷新验证
- 远程控制（集控控制模块）- 补充表格数据验证、刷新验证

总计：8个补充用例

设计原则：
1. 复用现有步骤模板函数
2. 断言策略宽松优先：element_exists > visible, element_count_min > count
3. 选择器策略：使用 selectors 回退链
4. 状态重置：每个用例末尾添加"回到首页"步骤
5. auto_login=True，步骤中不包含登录步骤

作者：czj
创建日期：2026-07-23
最后修改日期：2026-07-23
"""

import asyncio
import httpx
import sys

BASE_URL = "http://localhost:8001"
TARGET_URL = "https://192.168.5.44"

# 模块ID
MODULE_DATA_ANALYSIS = "module_6790b99750114326b539458f322f3be8"     # 数据分析
MODULE_INFO_PUBLISH = "module_parent_xinxifabu"                      # 信息发布
MODULE_JIKONG = "module_parent_jikong"                                # 集控控制

# 通用配置
DEFAULT_CONFIG = {
    "timeout": 120000,
    "screenshot": True,
    "auto_login": True,
    "step_retry_count": 2,
}


# ==================== 步骤模板函数 ====================


def build_home_menu_navigate_steps(menu_name: str, wait_selector: str = "body",
                                   wait_timeout: int = 20000, order_start: int = 1):
    """
    构建首页菜单卡片导航步骤

    适用于：数据分析、管理看板、运维管理、会议管理

    Args:
        menu_name: 菜单名称（对应 .block:has-text() 选择器）
        wait_selector: 页面加载后等待的特征元素选择器
        wait_timeout: 等待超时时间(ms)
        order_start: 起始步骤编号

    Returns:
        list[dict]: 步骤列表（3步）
    """
    return [
        {
            "order": order_start,
            "name": f"点击{menu_name}菜单",
            "action": "click",
            "params": {"selector": f'.block:has-text("{menu_name}")'},
        },
        {
            "order": order_start + 1,
            "name": "等待页面加载",
            "action": "wait",
            "params": {"selector": wait_selector, "timeout": wait_timeout},
        },
        {
            "order": order_start + 2,
            "name": "等待页面渲染",
            "action": "wait",
            "params": {"selector": "body", "timeout": 3000},
        },
    ]


def build_func_center_navigate_steps(menu_name: str, wait_selector: str = "body",
                                     wait_timeout: int = 20000, order_start: int = 1):
    """
    构建功能中心抽屉导航步骤

    Args:
        menu_name: 功能中心抽屉内的菜单名称
        wait_selector: 页面加载后等待的特征元素选择器
        wait_timeout: 等待超时时间(ms)
        order_start: 起始步骤编号

    Returns:
        list[dict]: 步骤列表（6步）
    """
    return [
        {
            "order": order_start,
            "name": "等待首页加载",
            "action": "wait",
            "params": {"selector": ".block", "timeout": 15000},
        },
        {
            "order": order_start + 1,
            "name": "点击功能中心图标",
            "action": "click",
            "params": {"selector": ".home_nav_left"},
        },
        {
            "order": order_start + 2,
            "name": "等待抽屉打开",
            "action": "wait",
            "params": {"selector": ".el-drawer", "timeout": 15000},
        },
        {
            "order": order_start + 3,
            "name": f"点击{menu_name}",
            "action": "click",
            "params": {"selector": f".el-drawer >> text='{menu_name}'"},
        },
        {
            "order": order_start + 4,
            "name": "等待抽屉关闭",
            "action": "wait",
            "params": {"selector": "body", "timeout": 3000},
        },
        {
            "order": order_start + 5,
            "name": "等待页面加载",
            "action": "wait",
            "params": {"selector": wait_selector, "timeout": wait_timeout},
        },
    ]


def build_table_wait_steps(order_start: int):
    """
    构建表格等待步骤

    Args:
        order_start: 起始步骤编号

    Returns:
        list[dict]: 步骤列表（2步）
    """
    return [
        {
            "order": order_start,
            "name": "等待表格加载",
            "action": "wait",
            "params": {"selectors": [".el-table", ".el-card", ".content", "body"], "timeout": 30000},
        },
        {
            "order": order_start + 1,
            "name": "等待表格渲染",
            "action": "wait",
            "params": {"selector": "body", "timeout": 3000},
        },
    ]


def build_filter_select_steps(select_index: int, order_start: int):
    """
    构建筛选器下拉选择步骤

    Args:
        select_index: 筛选器索引（0-based）
        order_start: 起始步骤编号

    Returns:
        list[dict]: 步骤列表（2步）
    """
    input_selectors = [
        f".el-select:nth-child({select_index + 1}) .el-input__inner",
        f".el-select:nth-child({select_index + 1}) .el-select__input",
        f".el-select:nth-child({select_index + 1})",
        ".el-select .el-input__inner",
        ".el-select",
    ]
    option_selectors = [
        ".el-select-dropdown:visible .el-select-dropdown__item:first-child",
        ".el-select-dropdown__item:first-child",
    ]
    return [
        {
            "order": order_start,
            "name": f"点击第{select_index + 1}个筛选器",
            "action": "click",
            "params": {"selectors": input_selectors},
        },
        {
            "order": order_start + 1,
            "name": "选择第一个选项",
            "action": "click",
            "params": {"selectors": option_selectors, "timeout": 5000},
        },
    ]


def build_canvas_wait_steps(order_start: int):
    """
    构建图表等待步骤

    Args:
        order_start: 起始步骤编号

    Returns:
        list[dict]: 步骤列表（2步）
    """
    return [
        {
            "order": order_start,
            "name": "等待图表加载",
            "action": "wait",
            "params": {
                "selectors": [".echarts", ".chart-container canvas", "canvas", "[class*='chart']"],
                "timeout": 30000,
            },
        },
        {
            "order": order_start + 1,
            "name": "等待图表渲染",
            "action": "wait",
            "params": {"selector": "body", "timeout": 3000},
        },
    ]


def build_navigate_home_step(order: int):
    """
    构建回到首页步骤（状态重置）

    Args:
        order: 步骤编号

    Returns:
        dict: 步骤字典
    """
    return {
        "order": order,
        "name": "回到首页",
        "action": "navigate",
        "params": {"url": TARGET_URL},
    }


def build_refresh_steps(order_start: int):
    """
    构建刷新按钮点击步骤

    Args:
        order_start: 起始步骤编号

    Returns:
        list[dict]: 步骤列表（2步）
    """
    return [
        {
            "order": order_start,
            "name": "点击刷新按钮",
            "action": "click",
            "params": {"selectors": [".el-button:has-text('刷新')", "button:has-text('刷新')", ".el-button-refresh", "button"]},
        },
        {
            "order": order_start + 1,
            "name": "等待数据刷新",
            "action": "wait",
            "params": {"selector": "body", "timeout": 5000},
        },
    ]


# ==================== 各页面用例构建函数 ====================


def build_meeting_service_stat_cases():
    """构建会议服务统计页面补充用例（2个）"""
    cases = []

    # 1. 会议服务统计-筛选器验证
    cases.append({
        "name": "会议服务统计-筛选器验证",
        "description": "验证会议服务统计页面筛选器可正常操作",
        "module_id": MODULE_DATA_ANALYSIS,
        "priority": "high",
        "order": 1001,
        "config": DEFAULT_CONFIG,
        "steps":
            build_home_menu_navigate_steps("会议服务统计", "body", 20000)  # 1-3
            + [
                {"order": 4, "name": "等待页面渲染", "action": "wait",
                 "params": {"selector": "body", "timeout": 3000}},
                {"order": 5, "name": "验证筛选器存在", "action": "assert",
                 "params": {"type": "element_count_min", "selector": ".el-select", "min_count": 1}},
            ]
            + build_filter_select_steps(0, 6)  # 6-7
            + [
                {"order": 8, "name": "等待数据刷新", "action": "wait",
                 "params": {"selector": "body", "timeout": 3000}},
                {"order": 9, "name": "验证页面主体存在", "action": "assert",
                 "params": {"type": "element_exists", "selectors": [".el-table", "canvas", "body"]}},
                build_navigate_home_step(10),
            ],
    })

    # 2. 会议服务统计-图表验证
    cases.append({
        "name": "会议服务统计-图表验证",
        "description": "验证会议服务统计页面图表正常展示",
        "module_id": MODULE_DATA_ANALYSIS,
        "priority": "medium",
        "order": 1002,
        "config": DEFAULT_CONFIG,
        "steps":
            build_home_menu_navigate_steps("会议服务统计", "canvas", 30000)  # 1-3
            + build_canvas_wait_steps(4)  # 4-5
            + [
                {"order": 6, "name": "验证图表存在", "action": "assert",
                 "params": {"type": "element_exists", "selectors": ["canvas", ".echarts", "body"]}},
                build_navigate_home_step(7),
            ],
    })

    return cases


def build_message_notification_cases():
    """构建消息通知页面补充用例（2个）"""
    cases = []

    # 1. 消息通知-筛选器验证
    cases.append({
        "name": "消息通知-筛选器验证",
        "description": "验证消息通知页面筛选器可正常操作",
        "module_id": MODULE_INFO_PUBLISH,
        "priority": "high",
        "order": 1101,
        "config": DEFAULT_CONFIG,
        "steps":
            build_func_center_navigate_steps("消息通知", "body", 20000)  # 1-6
            + [
                {"order": 7, "name": "等待页面渲染", "action": "wait",
                 "params": {"selector": "body", "timeout": 3000}},
                {"order": 8, "name": "验证筛选器存在", "action": "assert",
                 "params": {"type": "element_count_min", "selector": ".el-select", "min_count": 1}},
            ]
            + build_filter_select_steps(0, 9)  # 9-10
            + [
                {"order": 11, "name": "等待数据刷新", "action": "wait",
                 "params": {"selector": "body", "timeout": 3000}},
                {"order": 12, "name": "验证页面主体存在", "action": "assert",
                 "params": {"type": "element_exists", "selectors": [".el-table", ".el-card", ".content", "body"]}},
                build_navigate_home_step(13),
            ],
    })

    # 2. 消息通知-操作按钮验证
    cases.append({
        "name": "消息通知-操作按钮验证",
        "description": "验证消息通知页面操作按钮存在",
        "module_id": MODULE_INFO_PUBLISH,
        "priority": "medium",
        "order": 1102,
        "config": DEFAULT_CONFIG,
        "steps":
            build_func_center_navigate_steps("消息通知", "body", 20000)  # 1-6
            + [
                {"order": 7, "name": "等待页面渲染", "action": "wait",
                 "params": {"selector": "body", "timeout": 3000}},
                {"order": 8, "name": "验证操作按钮存在", "action": "assert",
                 "params": {"type": "element_count_min", "selectors": ["button", ".el-button", "body"], "min_count": 1}},
                build_navigate_home_step(9),
            ],
    })

    return cases


def build_device_list_cases():
    """构建设备列表页面补充用例（2个）"""
    cases = []

    # 1. 设备列表-表格数据验证
    cases.append({
        "name": "设备列表-表格数据验证",
        "description": "验证设备列表页面表格数据正常加载",
        "module_id": MODULE_JIKONG,
        "priority": "high",
        "order": 1201,
        "config": DEFAULT_CONFIG,
        "steps":
            build_func_center_navigate_steps("设备列表", ".el-tabs, .el-table", 30000)  # 1-6
            + build_table_wait_steps(7)  # 7-8
            + [
                {"order": 9, "name": "验证表格存在", "action": "assert",
                 "params": {"type": "element_exists", "selectors": [".el-table", ".el-tabs", "body"]}},
                build_navigate_home_step(10),
            ],
    })

    # 2. 设备列表-刷新验证
    cases.append({
        "name": "设备列表-刷新验证",
        "description": "验证设备列表页面刷新功能正常",
        "module_id": MODULE_JIKONG,
        "priority": "medium",
        "order": 1202,
        "config": DEFAULT_CONFIG,
        "steps":
            build_func_center_navigate_steps("设备列表", ".el-tabs, .el-table", 30000)  # 1-6
            + build_table_wait_steps(7)  # 7-8
            + build_refresh_steps(9)  # 9-10
            + [
                {"order": 11, "name": "验证表格存在", "action": "assert",
                 "params": {"type": "element_exists", "selectors": [".el-table", ".el-tabs", "body"]}},
                build_navigate_home_step(12),
            ],
    })

    return cases


def build_remote_control_cases():
    """构建远程控制页面补充用例（2个）"""
    cases = []

    # 1. 远程控制-表格数据验证
    cases.append({
        "name": "远程控制-表格数据验证",
        "description": "验证远程控制页面表格数据正常加载",
        "module_id": MODULE_JIKONG,
        "priority": "high",
        "order": 1301,
        "config": DEFAULT_CONFIG,
        "steps":
            build_func_center_navigate_steps("远程控制", ".el-tabs, .el-table", 30000)  # 1-6
            + build_table_wait_steps(7)  # 7-8
            + [
                {"order": 9, "name": "验证表格存在", "action": "assert",
                 "params": {"type": "element_exists", "selectors": [".el-table", ".el-tabs", "body"]}},
                build_navigate_home_step(10),
            ],
    })

    # 2. 远程控制-刷新验证
    cases.append({
        "name": "远程控制-刷新验证",
        "description": "验证远程控制页面刷新功能正常",
        "module_id": MODULE_JIKONG,
        "priority": "medium",
        "order": 1302,
        "config": DEFAULT_CONFIG,
        "steps":
            build_func_center_navigate_steps("远程控制", ".el-tabs, .el-table", 30000)  # 1-6
            + build_table_wait_steps(7)  # 7-8
            + build_refresh_steps(9)  # 9-10
            + [
                {"order": 11, "name": "验证表格存在", "action": "assert",
                 "params": {"type": "element_exists", "selectors": [".el-table", ".el-tabs", "body"]}},
                build_navigate_home_step(12),
            ],
    })

    return cases


# ==================== 用例创建逻辑 ====================


async def update_or_create_case(client: httpx.AsyncClient, case_data: dict):
    """
    更新已有用例或创建新用例

    按名称查找已有用例，存在则更新，不存在则创建。

    Args:
        client: httpx 异步客户端
        case_data: 用例数据

    Returns:
        tuple: (action, result) action为"created"/"updated"/"failed"
    """
    case_name = case_data["name"]

    try:
        # 查找同名用例
        r = await client.get(f"{BASE_URL}/api/cases", params={"keyword": case_name})
        if r.status_code == 200:
            items = r.json().get("items", [])
            existing = [c for c in items if c["name"] == case_name]

            if existing:
                # 更新已有用例
                case_id = existing[0]["id"]
                r = await client.put(f"{BASE_URL}/api/cases/{case_id}", json=case_data)
                if r.status_code == 200:
                    print(f"  ✅ 更新: {case_name}")
                    return "updated", r.json()
                else:
                    print(f"  ❌ 更新失败: {case_name} - {r.text}")
                    return "failed", None

        # 创建新用例
        r = await client.post(f"{BASE_URL}/api/cases", json=case_data)
        if r.status_code in (200, 201):
            print(f"  ✅ 创建: {case_name}")
            return "created", r.json()
        else:
            print(f"  ❌ 创建失败: {case_name} - {r.text}")
            return "failed", None

    except Exception as e:
        print(f"  ❌ 异常: {case_name} - {e}")
        return "failed", None


async def create_cases():
    """创建所有补充用例"""
    all_cases = []
    all_cases.extend(build_meeting_service_stat_cases())
    all_cases.extend(build_message_notification_cases())
    all_cases.extend(build_device_list_cases())
    all_cases.extend(build_remote_control_cases())

    print(f"\n共 {len(all_cases)} 个补充用例待创建/更新")
    print("=" * 60)

    async with httpx.AsyncClient(timeout=60) as client:
        created = 0
        updated = 0
        failed = 0

        for case in all_cases:
            action, result = await update_or_create_case(client, case)
            if action == "created":
                created += 1
            elif action == "updated":
                updated += 1
            else:
                failed += 1

    print("=" * 60)
    print(f"创建: {created}, 更新: {updated}, 失败: {failed}")
    print(f"总计: {created + updated + failed}")


if __name__ == "__main__":
    asyncio.run(create_cases())
