#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
模块名称：import_cases_from_excel.py
模块描述：从 Excel 文件导入测试用例到自动化测试平台

作者：czj
创建日期：2026-07-10
"""

import sys
import json
import requests
from pathlib import Path
from openpyxl import load_workbook

# API 基础地址
API_BASE = "http://localhost:8000/api"


def convert_step(excel_step: dict, order: int) -> dict:
    """
    将 Excel 步骤格式转换为系统步骤格式

    Excel 格式:
    {
        "page": "login/logindf",
        "step": "输入账号",
        "locator_type": "XPATH",
        "locator_value": "//input[@placeholder='账号']",
        "element_type": "input",
        "element_value": "admin",
        "expected_result": ""
    }

    系统格式:
    {
        "order": 1,
        "name": "输入账号",
        "action": "fill",
        "params": {
            "selector": "xpath=//input[@placeholder='账号']",
            "value": "admin"
        },
        "expected": ""
    }
    """
    locator_type = excel_step.get("locator_type", "XPATH")
    locator_value = excel_step.get("locator_value", "")
    element_type = excel_step.get("element_type", "click")
    element_value = excel_step.get("element_value", "")
    step_desc = excel_step.get("step", "")
    expected_result = excel_step.get("expected_result", "")

    # 构建选择器
    selector = f"{locator_type.lower()}={locator_value}" if locator_value else ""

    # 转换动作类型
    action_map = {
        "input": "fill",
        "click": "click",
        "getText": "assert",  # getText 通常用于断言
        "refresh": "wait",
        "wait": "wait",
    }
    action = action_map.get(element_type, "click")

    # 步骤名称取描述
    step_name = step_desc or f"步骤{order}"

    # 特殊处理
    if element_type == "refresh":
        # refresh 动作，element_value 是刷新次数或等待时间
        return {
            "order": order,
            "name": step_name,
            "action": "wait",
            "params": {
                "duration": int(element_value) * 1000 if element_value.isdigit() else 3000
            },
            "expected": ""
        }

    if element_type == "getText" and expected_result:
        # 断言步骤
        return {
            "order": order,
            "name": step_name,
            "action": "assert",
            "params": {
                "selector": selector,
                "assertion_type": "text",
                "expected": expected_result
            },
            "expected": expected_result
        }

    # 普通步骤
    params = {"selector": selector}
    if element_value:
        params["value"] = element_value

    return {
        "order": order,
        "name": step_name,
        "action": action,
        "params": params,
        "expected": expected_result or ""
    }


def convert_case_json(excel_json: str) -> list:
    """
    将 Excel JSON 字符串转换为系统步骤列表

    Args:
        excel_json: Excel 中的 JSON 字符串

    Returns:
        list: 系统格式的步骤列表
    """
    try:
        data = json.loads(excel_json)
        para_list = data.get("para", [])
        base_url = data.get("base_url", "")
        steps = []

        # 如果有 base_url，添加导航步骤作为第一步
        if base_url:
            steps.append({
                "order": 1,
                "name": "打开目标页面",
                "action": "navigate",
                "params": {
                    "url": base_url
                },
                "expected": ""
            })

        for idx, para in enumerate(para_list):
            step = convert_step(para, order=idx + 2 if base_url else idx + 1)
            steps.append(step)

        return steps
    except json.JSONDecodeError as e:
        print(f"  JSON 解析失败: {e}")
        return []


def create_module(name: str, description: str = "") -> str:
    """
    创建模块，返回模块 ID

    Args:
        name: 模块名称
        description: 模块描述

    Returns:
        str: 模块 ID
    """
    # 先检查是否已存在
    resp = requests.get(f"{API_BASE}/modules", params={"search": name})
    modules = resp.json().get("items", [])

    for module in modules:
        if module["name"] == name:
            return module["id"]

    # 创建新模块
    resp = requests.post(
        f"{API_BASE}/modules",
        json={
            "name": name,
            "description": description,
            "icon": "folder"
        }
    )

    if resp.status_code == 200:
        return resp.json()["id"]
    else:
        print(f"  创建模块失败: {resp.text}")
        return None


def create_case(module_id: str, case_data: dict) -> bool:
    """
    创建测试用例

    Args:
        module_id: 模块 ID
        case_data: 用例数据

    Returns:
        bool: 是否成功
    """
    # 映射优先级为系统格式
    priority_map = {
        1: "high",
        2: "high",
        3: "medium",
        4: "medium",
        5: "low"
    }
    raw_priority = case_data.get("priority", 3)
    try:
        priority = priority_map.get(int(raw_priority), "medium")
    except (ValueError, TypeError):
        priority = "medium"

    # 构建用例数据
    payload = {
        "module_id": module_id,
        "name": case_data.get("name", "未命名用例"),
        "description": case_data.get("description", ""),
        "priority": priority,
        "tags": case_data.get("tags", []),
        "steps": case_data.get("steps", []),
        "config": {
            "timeout": 30000,
            "screenshot": True,
            "headless": False
        }
    }

    resp = requests.post(f"{API_BASE}/cases", json=payload)

    if resp.status_code == 200:
        return True
    else:
        print(f"  创建用例失败: {resp.text[:200]}")
        return False


def import_excel(excel_path: str, limit: int = None, only_with_json: bool = False):
    """
    导入 Excel 文件中的测试用例

    Args:
        excel_path: Excel 文件路径
        limit: 限制导入数量（用于测试）
        only_with_json: 只导入有 JSON 步骤的用例
    """
    print(f"开始导入 Excel: {excel_path}")

    wb = load_workbook(excel_path)
    total_imported = 0
    total_failed = 0
    module_stats = {}

    for sheet_name in wb.sheetnames:
        sheet = wb[sheet_name]
        module_name = sheet_name

        # 模块描述从第一行获取
        module_desc = ""
        first_row = list(sheet.iter_rows(min_row=1, max_row=1, values_only=True))[0]
        if first_row and first_row[0]:
            module_desc = str(first_row[0])

        print(f"\n处理模块: {module_name} ({sheet.max_row - 3} 条用例)")

        # 创建模块
        module_id = create_module(module_name, module_desc)
        if not module_id:
            print(f"  跳过该模块")
            continue

        imported = 0
        failed = 0

        # 遍历用例
        for row in sheet.iter_rows(min_row=4, values_only=True):
            if limit and total_imported >= limit:
                break

            if row[0] is None:  # 序号为空则跳过
                continue

            # 提取用例信息
            case_name = row[2] or f"用例-{row[0]}"  # 用例名称
            case_code = row[3] or ""  # 用例编号
            case_desc = row[4] or ""  # 用例描述
            priority = row[5] or 3  # 优先级
            step_text = row[9] or ""  # STEP 文本
            step_json = row[10]  # JSON 步骤

            # 如果设置了只导入有 JSON 的用例
            if only_with_json and not step_json:
                continue

            # 转换步骤
            steps = []
            if step_json:
                steps = convert_case_json(step_json)

            # 创建用例数据
            case_data = {
                "name": f"{case_code} - {case_name}" if case_code else case_name,
                "description": case_desc,
                "priority": int(priority) if priority else 3,
                "steps": steps
            }

            # 创建用例
            if create_case(module_id, case_data):
                imported += 1
                total_imported += 1
                print(f"  ✓ [{total_imported}] {case_data['name']}")
            else:
                failed += 1
                total_failed += 1

        module_stats[module_name] = {"imported": imported, "failed": failed}

        if limit and total_imported >= limit:
            break

    # 打印统计
    print("\n" + "=" * 60)
    print("导入完成统计:")
    print(f"  总导入成功: {total_imported}")
    print(f"  总导入失败: {total_failed}")
    print(f"  模块数量: {len(module_stats)}")

    return module_stats


if __name__ == "__main__":
    # Excel 文件路径
    excel_path = "E:/GithubData/ubains-module-test/platform-auto-test/Docs/新统一平台测试用例.xlsx"

    # 检查 API 是否可用
    try:
        resp = requests.get(f"{API_BASE}/modules")
        if resp.status_code != 200:
            print("API 服务未启动，请先启动后端服务")
            sys.exit(1)
    except requests.ConnectionError:
        print("无法连接到 API 服务，请先启动后端服务")
        sys.exit(1)

    # 导入参数
    import_all = True  # 是否导入全部
    test_limit = 10    # 测试时只导入前 N 条

    if import_all:
        print("开始导入全部用例...")
        import_excel(excel_path, only_with_json=True)  # 先只导入有 JSON 的 158 条
    else:
        print(f"测试导入前 {test_limit} 条用例...")
        import_excel(excel_path, limit=test_limit, only_with_json=True)