# -*- coding: utf-8 -*-
import argparse
import os
import shutil
import subprocess
import sys

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 = 'joyhub_backend/test_case/TestCase'
case_dir = os.path.join(project_root, TEST_CASE_DIR)
ALLURE_RESULTS_DIR = os.path.join(project_root, 'joyhub_backend', 'test_case', 'reports', 'allure-results')
ALLURE_REPORT_DIR = os.path.join(project_root, 'joyhub_backend', 'test_case', 'reports', 'allure-report')


def ensure_dirs():
    os.makedirs(ALLURE_RESULTS_DIR, exist_ok=True)
    os.makedirs(ALLURE_REPORT_DIR, exist_ok=True)


def clean_allure_results():
    if os.path.exists(ALLURE_RESULTS_DIR):
        shutil.rmtree(ALLURE_RESULTS_DIR)
    os.makedirs(ALLURE_RESULTS_DIR, exist_ok=True)


def find_test_files(directory):
    test_files = []
    for root, dirs, files in os.walk(directory):
        for file in files:
            if file.endswith('.py') and not file.startswith('__') and file != 'conftest.py':
                test_files.append(os.path.join(root, file))
    return test_files


def run_pytest(args_list):
    env = os.environ.copy()
    env['PYTHONPATH'] = project_root + (os.pathsep + env['PYTHONPATH'] if 'PYTHONPATH' in env else '')
    cmd = ['python', '-m', 'pytest'] + args_list
    print("开始执行pytest...")
    print("执行命令: {}".format(' '.join('"{}"'.format(item) if ' ' in item else item for item in cmd)), flush=True)
    result = subprocess.run(cmd, cwd=project_root, env=env)
    print("pytest执行结束，退出码: {}".format(result.returncode), flush=True)
    return result.returncode


def run_tests(target=None, test_type='all'):
    base_args = ['-v', '--tb=short', '--alluredir={}'.format(ALLURE_RESULTS_DIR)]
    if test_type == 'all':
        print("运行所有测试用例...")
        test_files = find_test_files(case_dir)
        if not test_files:
            print("错误: 未找到测试文件")
            return 1
        args = test_files + base_args
    elif test_type == 'dir':
        full_path = os.path.join(case_dir, target.replace('/', os.sep).replace('\\', os.sep))
        if not os.path.exists(full_path):
            print("错误: 目录不存在: {}".format(full_path))
            return 1
        print("按目录运行: {}".format(target))
        test_files = find_test_files(full_path)
        if not test_files:
            print("错误: 未找到测试文件")
            return 1
        args = test_files + base_args
    elif test_type == 'file':
        full_path = os.path.join(case_dir, target.replace('/', os.sep).replace('\\', os.sep))
        if not os.path.exists(full_path):
            print("错误: 文件不存在: {}".format(full_path))
            return 1
        print("按文件运行: {}".format(target))
        args = [full_path] + base_args
    elif test_type == 'keyword':
        print("按关键字运行: {}".format(target))
        test_files = find_test_files(case_dir)
        args = test_files + ['-k={}'.format(target)] + base_args
    elif test_type == 'marker':
        print("按pytest标记运行: {}".format(target))
        test_files = find_test_files(case_dir)
        args = test_files + ['-m={}'.format(target)] + base_args
    elif test_type == 'feature':
        print("按Allure feature运行: {}".format(target))
        test_files = find_test_files(case_dir)
        args = test_files + ['--allure-features={}'.format(target)] + base_args
    elif test_type == 'story':
        print("按Allure story运行: {}".format(target))
        test_files = find_test_files(case_dir)
        args = test_files + ['--allure-stories={}'.format(target)] + base_args
    else:
        print("错误: 未知的测试类型: {}".format(test_type))
        return 1
    return run_pytest(args)


def generate_allure_report():
    print("开始生成Allure报告...", flush=True)
    if os.path.exists(ALLURE_REPORT_DIR):
        shutil.rmtree(ALLURE_REPORT_DIR)
    cmd = 'allure generate "{}" --output "{}"'.format(ALLURE_RESULTS_DIR, ALLURE_REPORT_DIR)
    print("执行命令: {}".format(cmd), flush=True)
    try:
        subprocess.run(cmd, check=True, shell=True)
        print("Allure报告生成成功: {}".format(ALLURE_REPORT_DIR))
        print("打开报告命令: allure open \"{}\"".format(ALLURE_REPORT_DIR))
        return 0
    except (subprocess.CalledProcessError, FileNotFoundError, OSError) as error:
        print("生成Allure报告失败: {}".format(error))
        print("手动执行: {}".format(cmd))
        return 1


def open_allure_report():
    cmd = 'allure open "{}"'.format(ALLURE_REPORT_DIR)
    try:
        subprocess.Popen(cmd, shell=True)
        print("Allure报告已打开: {}".format(ALLURE_REPORT_DIR))
        return 0
    except (FileNotFoundError, OSError) as error:
        print("打开Allure报告失败: {}".format(error))
        return 1


def main():
    parser = argparse.ArgumentParser(description='JoyHub Backend 接口自动化测试执行工具')
    run_group = parser.add_mutually_exclusive_group(required=False)
    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报告')
    parser.add_argument('--no-report', action='store_true', help='不生成Allure报告')
    args = parser.parse_args()

    ensure_dirs()
    clean_allure_results()
    if args.feature:
        exit_code = run_tests(args.feature, 'feature')
    elif args.story:
        exit_code = run_tests(args.story, 'story')
    elif args.dir:
        exit_code = run_tests(args.dir, 'dir')
    elif args.file:
        exit_code = run_tests(args.file, 'file')
    elif args.keyword:
        exit_code = run_tests(args.keyword, 'keyword')
    elif args.marker:
        exit_code = run_tests(args.marker, 'marker')
    else:
        exit_code = run_tests()

    if args.report or not args.no_report:
        generate_allure_report()
        if args.open:
            open_allure_report()

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


if __name__ == '__main__':
    main()
