# -*- coding: utf-8 -*-
"""
统一测试执行文件
支持批量运行所有用例、按标签运行、按目录运行等
"""
import os
import sys
import subprocess
import argparse
from pathlib import Path

# 添加项目根目录到 Python 路径
current_file_path = os.path.abspath(__file__)
project_root = os.path.abspath(os.path.join(os.path.dirname(current_file_path), '../../'))
if project_root not in sys.path:
    sys.path.insert(0, project_root)

# 测试目录
TEST_CASE_DIR = 'zhyy/test_case/TestCase'
# 报告目录
REPORT_DIR = os.path.join(os.path.dirname(current_file_path), 'reports')
ALLURE_RESULTS_DIR = os.path.join(REPORT_DIR, 'allure-results')
ALLURE_REPORT_DIR = os.path.join(REPORT_DIR, 'allure-report')


def ensure_dirs():
    """确保报告目录存在"""
    os.makedirs(ALLURE_RESULTS_DIR, exist_ok=True)
    os.makedirs(ALLURE_REPORT_DIR, exist_ok=True)


def run_pytest(args_list):
    """执行pytest命令"""
    # 基础pytest命令
    # 设置PYTHONPATH环境变量，确保能导入zhyy模块
    env = os.environ.copy()
    if 'PYTHONPATH' in env:
        env['PYTHONPATH'] = project_root + os.pathsep + env['PYTHONPATH']
    else:
        env['PYTHONPATH'] = project_root

    # 检测是否在Jenkins环境中
    is_jenkins = 'JENKINS_URL' in env or 'BUILD_NUMBER' in env
    if is_jenkins:
        print("检测到Jenkins环境，使用Jenkins配置...")
        # 在Jenkins中，报告路径使用绝对路径
        if 'WORKSPACE' in env:
            workspace = env['WORKSPACE']
            # 确保使用Jenkins工作空间的报告目录
            global ALLURE_RESULTS_DIR, ALLURE_REPORT_DIR
            ALLURE_RESULTS_DIR = os.path.join(workspace, 'zhyy', 'test_case', 'reports', 'allure-results')
            ALLURE_REPORT_DIR = os.path.join(workspace, 'zhyy', 'test_case', 'reports', 'allure-report')
            ensure_dirs()

    cmd = ['python', '-m', 'pytest'] + args_list

    print("=" * 80)
    print("执行命令: {}".format(' '.join(cmd)))
    print("命令列表: {}".format(cmd))
    print("测试目录: {}".format(TEST_CASE_DIR))
    print("测试目录是否存在: {}".format(os.path.exists(TEST_CASE_DIR)))
    if is_jenkins:
        print("Jenkins工作空间: {}".format(env.get('WORKSPACE', 'N/A')))
        print("构建编号: {}".format(env.get('BUILD_NUMBER', 'N/A')))
    print("PYTHONPATH: {}".format(env.get('PYTHONPATH')))
    print("Allure结果目录: {}".format(ALLURE_RESULTS_DIR))
    print("当前工作目录: {}".format(os.getcwd()))
    print("=" * 80)

    # 使用 shell=True 来执行命令，确保能正确处理路径和参数
    result = subprocess.run(' '.join(cmd), shell=True, cwd=project_root, env=env)
    return result.returncode


def find_test_files(directory):
    """递归查找所有测试文件"""
    test_files = []
    for root, dirs, files in os.walk(directory):
        for file in files:
            if file.endswith('.py'):
                # 检查文件中是否包含测试函数
                file_path = os.path.join(root, file)
                try:
                    with open(file_path, 'r', encoding='utf-8') as f:
                        content = f.read()
                        if 'def test_' in content or 'class Test' in content:
                            test_files.append(file_path)
                except:
                    pass
    return test_files


def run_all_tests():
    """运行所有测试用例"""
    print("运行所有测试用例...")
    # 递归查找所有测试文件
    test_files = find_test_files(TEST_CASE_DIR)
    if not test_files:
        print("未找到测试文件")
        return 1

    print(f"找到 {len(test_files)} 个测试文件:")
    for file in test_files:
        print(f"  - {file}")

    args = [
        *test_files,
        '-v',  # 详细输出
        '--tb=short',  # 简短的错误信息
        f'--alluredir={ALLURE_RESULTS_DIR}',  # allure结果目录
    ]
    return run_pytest(args)


def run_by_feature(feature_name):
    """按allure feature标签运行"""
    print("按feature标签运行: {}".format(feature_name))
    args = [
        TEST_CASE_DIR,
        '-v',
        '--tb=short',
        f'--allure-features={feature_name}',
        f'--alluredir={ALLURE_RESULTS_DIR}',
    ]
    return run_pytest(args)


def run_by_story(story_name):
    """按allure story标签运行"""
    print("按story标签运行: {}".format(story_name))
    args = [
        TEST_CASE_DIR,
        '-v',
        '--tb=short',
        f'--allure-stories={story_name}',
        f'--alluredir={ALLURE_RESULTS_DIR}',
    ]
    return run_pytest(args)


def run_by_marker(marker):
    """按pytest标记运行"""
    print("按pytest标记运行: {}".format(marker))
    args = [
        TEST_CASE_DIR,
        '-v',
        '--tb=short',
        f'-m={marker}',
        f'--alluredir={ALLURE_RESULTS_DIR}',
    ]
    return run_pytest(args)


def run_by_dir(directory):
    """按目录运行"""
    full_path = os.path.join(TEST_CASE_DIR, directory)
    if not os.path.exists(full_path):
        print("错误: 目录不存在: {}".format(full_path))
        return 1

    print("按目录运行: {}".format(directory))
    args = [
        full_path,
        '-v',
        '--tb=short',
        f'--alluredir={ALLURE_RESULTS_DIR}',
    ]
    return run_pytest(args)


def run_by_file(file_path):
    """按文件运行"""
    full_path = os.path.join(TEST_CASE_DIR, file_path)
    if not os.path.exists(full_path):
        print("错误: 文件不存在: {}".format(full_path))
        return 1

    print("按文件运行: {}".format(file_path))
    args = [
        full_path,
        '-v',
        '--tb=short',
        f'--alluredir={ALLURE_RESULTS_DIR}',
    ]
    return run_pytest(args)


def run_by_keyword(keyword):
    """按关键字运行（匹配文件名或类名）"""
    print("按关键字运行: {}".format(keyword))
    args = [
        TEST_CASE_DIR,
        '-v',
        '--tb=short',
        f'-k={keyword}',
        f'--alluredir={ALLURE_RESULTS_DIR}',
    ]
    return run_pytest(args)


def generate_allure_report():
    """生成allure报告"""
    print("生成Allure报告...")
    cmd = [
        'allure',
        'generate',
        ALLURE_RESULTS_DIR,
        '-o',
        ALLURE_REPORT_DIR,
        '--clean'
    ]

    try:
        # 使用shell=True来执行命令，确保使用正确的环境变量
        result = subprocess.run(' '.join(cmd), shell=True, check=True)
        print("Allure报告生成成功: {}".format(ALLURE_REPORT_DIR))
        print("打开报告命令: allure open {}".format(ALLURE_REPORT_DIR))
        return 0
    except subprocess.CalledProcessError as e:
        print("生成Allure报告失败: {}".format(e))
        return 1
    except FileNotFoundError:
        print("警告: 未找到allure命令，请先安装allure")
        print("安装方法: https://docs.qameta.io/allure/")
        return 1


def open_allure_report():
    """打开allure报告"""
    print("打开Allure报告...")
    cmd = ['allure', 'open', ALLURE_REPORT_DIR]

    try:
        # 使用shell=True来执行命令，确保使用正确的环境变量
        subprocess.Popen(' '.join(cmd), shell=True)
        print("Allure报告已在浏览器中打开")
    except FileNotFoundError:
        print("警告: 未找到allure命令，请先安装allure")


def main():
    parser = argparse.ArgumentParser(
        description='统一测试执行工具',
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="""
使用示例:
  # 运行所有测试
  python run_tests.py --all

  # 按feature标签运行
  python run_tests.py --feature "深圳采购工作台采购订单页面"

  # 按story标签运行
  python run_tests.py --story "验证采购工作台采购订单页面列表查询"

  # 按目录运行
  python run_tests.py --dir "接口/SZPurchase"

  # 按文件运行
  python run_tests.py --file "接口/SZPurchase/PurchaseOrderManage.py"

  # 按关键字运行
  python run_tests.py --keyword "purchase"

  # 按pytest标记运行
  python run_tests.py --marker "smoke"

  # 生成并打开报告
  python run_tests.py --all --report --open
        """
    )

    # 运行选项（不强制要求，默认运行所有测试）
    run_group = parser.add_mutually_exclusive_group(required=False)
    run_group.add_argument('--all', action='store_true', help='运行所有测试用例（默认）')
    run_group.add_argument('--feature', type=str, help='按allure feature标签运行')
    run_group.add_argument('--story', type=str, help='按allure story标签运行')
    run_group.add_argument('--dir', type=str, help='按目录运行（相对于TestCase目录）')
    run_group.add_argument('--file', type=str, help='按文件运行（相对于TestCase目录）')
    run_group.add_argument('--keyword', type=str, help='按关键字运行（匹配文件名或类名）')
    run_group.add_argument('--marker', type=str, help='按pytest标记运行')

    # 报告选项
    parser.add_argument('--report', action='store_true', help='生成Allure报告')
    parser.add_argument('--open', action='store_true', help='打开Allure报告（需要先使用--report）')
    parser.add_argument('--no-report', action='store_true', help='不生成Allure报告（默认会生成）')

    args = parser.parse_args()

    # 确保目录存在
    ensure_dirs()

    # 执行测试（如果没有指定选项，默认运行所有测试）
    exit_code = 0
    if args.feature:
        exit_code = run_by_feature(args.feature)
    elif args.story:
        exit_code = run_by_story(args.story)
    elif args.dir:
        exit_code = run_by_dir(args.dir)
    elif args.file:
        exit_code = run_by_file(args.file)
    elif args.keyword:
        exit_code = run_by_keyword(args.keyword)
    elif args.marker:
        exit_code = run_by_marker(args.marker)
    else:
        # 默认运行所有测试
        exit_code = run_all_tests()

    # 生成报告
    if args.report or (not args.no_report and exit_code == 0):
        generate_allure_report()
        if args.open:
            open_allure_report()

    print("=" * 80)
    if exit_code == 0:
        print("✓ 测试执行完成")
    else:
        print("✗ 测试执行失败，退出码: {}".format(exit_code))
    print("=" * 80)

    sys.exit(exit_code)


if __name__ == '__main__':
    main()
