import os

import logging

import sys

import subprocess

import unittest

import time

import platform

import json

from HtmlTestRunner import HTMLTestRunner

from HtmlTestRunner.result import TestResult



sys.path.append('./')

sys.path.append('../')

from bredet.auto_verification.utils.general import merge_and_save_configs



def ensure_log_directory():

    log_dir = 'log'

    os.makedirs(log_dir, exist_ok=True)

    print(f"Ensuring log directory exists: {log_dir}")



def generate_log_file_paths(base_name):

    log_dir = 'log'

    detailed_log_file = os.path.join(log_dir, f"{base_name}_detailed.log")

    error_log_file = os.path.join(log_dir, f"{base_name}_error.log")

    return detailed_log_file, error_log_file



def run_command(command, description, detailed_log_file, error_log_file, html_report_file):

    try:

        logging.info(f"Running command: {command}")

        start_time = time.time()

        result = subprocess.run(command, capture_output=True, text=True, shell=True)

        end_time = time.time()

        execution_time = end_time - start_time



        logging.info(f"Command output: {result.stdout}")

        logging.info(f"Command error: {result.stderr}")



        if result.returncode == 0:

            print(f"Command succeeded: {command}")

            logging.info(f"Command succeeded: {command}")

        else:

            print(f"Command failed: {command}")

            logging.error(f"Test: {description}\n")

            logging.error(f"Command: {command}\n")

            logging.error(f"Error Output: {result.stderr}\n")

            logging.error("-" * 80 + "\n")



            with open(error_log_file, 'w') as f:

                f.write(f"Test: {description}\n")

                f.write(f"Command: {command}\n")

                f.write(f"Error Output: {result.stderr}\n")

                f.write("-" * 80 + "\n")



            # 添加链接到详细的错误日志文件

            error_log_url = f"../log/{os.path.basename(error_log_file)}"

            error_log_link = f"<a href='{error_log_url}'>Error Log</a>"

            logging.error(f"View detailed error log: {error_log_link}\n")



            # Append error log link to HTML report

            with open(html_report_file, 'a') as html_file:

                html_file.write(f"<p>Test: {description} failed. Command: {command}. <a href='{error_log_url}'>View Error Log</a></p>\n")



        return result.returncode == 0, execution_time, command

    except Exception as e:

        logging.error(f"{description} failed with exception: {e}\n")

        logging.error(f"Command: {command}\n")

        logging.error(f"Exception: {str(e)}\n")

        logging.error("-" * 80 + "\n")

        print(f"{description} failed with exception: {e}")



        with open(error_log_file, 'w') as f:

            f.write(f"{description} failed with exception: {e}\n")

            f.write(f"Command: {command}\n")

            f.write(f"Exception: {str(e)}\n")

            f.write("-" * 80 + "\n")



        # 添加链接到详细的错误日志文件

        error_log_url = f"../log/{os.path.basename(error_log_file)}"

        error_log_link = f"<a href='{error_log_url}'>Error Log</a>"

        logging.error(f"View detailed error log: {error_log_link}\n")



        # Append error log link to HTML report

        with open(html_report_file, 'a') as html_file:

            html_file.write(f"<p>Test: {description} failed. Command: {command}. <a href='{error_log_url}'>View Error Log</a></p>\n")



        return False, 0, command



def get_py_files_in_subdirectories(config_path):

    py_files = []

    for dirpath, dirnames, filenames in os.walk(config_path):

        for file in filenames:

            if file.endswith('.py') and 'override' not in file:

                py_files.append(os.path.join(dirpath, file))

    return py_files



class TestModelPipeline(unittest.TestCase):

    def __init__(self, *args, py_file=None, html_report_file=None, **kwargs):

        super(TestModelPipeline, self).__init__(*args, **kwargs)

        if py_file is None:

            raise ValueError("py_file must be provided")

        self.py_file = py_file

        base_name = os.path.splitext(os.path.basename(self.py_file))[0]

        self.detailed_log_file, self.error_log_file = generate_log_file_paths(base_name)

        self.html_report_file = html_report_file

        self._execution_time = 0  # 初始化 _execution_time 属性

        self._command = ""  # 初始化 _command 属性



    def setUp(self):

        # Initialize logging configuration for each test

        logging.basicConfig(level=logging.INFO, filename=self.detailed_log_file, filemode="a", force=True)

        logging.info(f"Starting test with config: {self.py_file}")



    def tearDown(self):

        logging.info(f"Ending test with config: {self.py_file}")



    def test_01_single_test(self):   # 单卡前向

        command = f"python tools/test.py --config {self.py_file}"

        description = "Single card test"

        result, execution_time, command = run_command(command, description, self.detailed_log_file, self.error_log_file, self.html_report_file)

        self._execution_time = execution_time  # 设置 _execution_time 属性

        self._command = command  # 设置 _command 属性

        self.assertTrue(result, f"Command failed: {command}")

        logging.info(f"Execution time for {description}: {execution_time:.2f} seconds")



    def test_02_multi_devices_test(self):   # 多卡前向

        command = f"torchrun --standalone --nproc-per-node 2 tools/test.py --config {self.py_file}"

        description = "Multi-device test"

        result, execution_time, command = run_command(command, description, self.detailed_log_file, self.error_log_file, self.html_report_file)

        self._execution_time = execution_time  # 设置 _execution_time 属性

        self._command = command  # 设置 _command 属性

        self.assertTrue(result, f"Command failed: {command}")

        logging.info(f"Execution time for {description}: {execution_time:.2f} seconds")



    # 添加更多的测试方法

    def test_03_additional_test(self):   # 示例命令

        command = f"python tools/additional_test.py --config {self.py_file}"

        description = "Additional test"

        result, execution_time, command = run_command(command, description, self.detailed_log_file, self.error_log_file, self.html_report_file)

        self._execution_time = execution_time  # 设置 _execution_time 属性

        self._command = command  # 设置 _command 属性

        self.assertTrue(result, f"Command failed: {command}")

        logging.info(f"Execution time for {description}: {execution_time:.2f} seconds")



    def test_04_another_test(self):   # 示例命令

        command = f"python tools/another_test.py --config {self.py_file}"

        description = "Another test"

        result, execution_time, command = run_command(command, description, self.detailed_log_file, self.error_log_file, self.html_report_file)

        self._execution_time = execution_time  # 设置 _execution_time 属性

        self._command = command  # 设置 _command 属性

        self.assertTrue(result, f"Command failed: {command}")

        logging.info(f"Execution time for {description}: {execution_time:.2f} seconds")



    # 可以继续添加更多的测试方法...



class CustomTestResult(TestResult):

    def __init__(self, *args, **kwargs):

        super().__init__(*args, **kwargs)

        self.test_results = []

        self.separator1 = '=' * 70

        self.separator2 = '-' * 70



    def addSuccess(self, test):

        super().addSuccess(test)

        self.test_results.append({

            'test': test,

            'status': 'success',

            'execution_time': test._execution_time,

            'command': test._command

        })



    def addFailure(self, test, err):

        super().addFailure(test, err)

        self.test_results.append({

            'test': test,

            'status': 'failure',

            'execution_time': test._execution_time,

            'error': self._exc_info_to_string(err, test),

            'command': test._command

        })



    def addError(self, test, err):

        super().addError(test, err)

        self.test_results.append({

            'test': test,

            'status': 'error',

            'execution_time': test._execution_time,

            'error': self._exc_info_to_string(err, test),

            'command': test._command

        })



    def addSkip(self, test, reason):

        super().addSkip(test, reason)

        self.test_results.append({

            'test': test,

            'status': 'skipped',

            'execution_time': test._execution_time,

            'reason': reason,

            'command': test._command

        })



    def addExpectedFailure(self, test, err):

        super().addExpectedFailure(test, err)

        self.test_results.append({

            'test': test,

            'status': 'expected_failure',

            'execution_time': test._execution_time,

            'error': self._exc_info_to_string(err, test),

            'command': test._command

        })



    def addUnexpectedSuccess(self, test):

        super().addUnexpectedSuccess(test)

        self.test_results.append({

            'test': test,

            'status': 'unexpected_success',

            'execution_time': test._execution_time,

            'command': test._command

        })



class CustomHTMLTestRunner(HTMLTestRunner):

    def __init__(self, *args, **kwargs):

        super().__init__(*args, **kwargs)

        self.environment_info = self._get_environment_info()



    def _get_environment_info(self):

        import pkg_resources

        environment_info = {

            "Platform": platform.platform(),

            "Python": platform.python_version()

        }

        return environment_info



    def _generate_report(self):

        self._generate_environment()

        self._generate_summary()

        self._generate_test_results()



    def _generate_environment(self):

        env_html = "<h2>Environment</h2>"

        for key, value in self.environment_info.items():

            if isinstance(value, dict):

                value = str(value).replace("{", "").replace("}", "").replace("'", "").replace(", ", "<br>")

            env_html += f"<p><strong>{key}:</strong> {value}</p>"

        self.stream.write(env_html)



    def _generate_summary(self):

        total_time = self.stopTime - self.startTime

        total_tests = len(self.result.test_results)

        successes = sum(1 for result in self.result.test_results if result['status'] == 'success')

        failures = sum(1 for result in self.result.test_results if result['status'] == 'failure')

        errors = sum(1 for result in self.result.test_results if result['status'] == 'error')

        skips = sum(1 for result in self.result.test_results if result['status'] == 'skipped')

        expected_failures = sum(1 for result in self.result.test_results if result['status'] == 'expected_failure')

        unexpected_successes = sum(1 for result in self.result.test_results if result['status'] == 'unexpected_success')



        summary_html = f"""

        <h2>Summary</h2>

        <p><strong>Report generated on:</strong> {time.strftime('%d-%b-%Y at %H:%M:%S')}</p>

        <p><strong>Tests ran in:</strong> {total_time:.2f} seconds.</p>

        <p><strong>{total_tests} tests ran.</strong></p>

        <p><strong>{successes} passed,</strong> <strong>{skips} skipped,</strong> <strong>{failures} failed,</strong> <strong>{errors} errors,</strong> <strong>{expected_failures} expected failures,</strong> <strong>{unexpected_successes} unexpected passes.</strong></p>

        """

        self.stream.write(summary_html)



    def _generate_test_results(self):

        self.stream.write("<h2>Logs</h2>")

        self.stream.write("<table border='1' cellpadding='5' cellspacing='0'>")

        self.stream.write("<tr><th>Command</th><th>Status</th><th>Duration (s)</th></tr>")



        for result in self.result.test_results:

            command = result['command']

            status = result['status']

            execution_time = result['execution_time']



            if status == 'success':

                status_html = "Passed"

            elif status == 'failure':

                status_html = "Failed"

            elif status == 'error':

                status_html = "Error"

            elif status == 'skipped':

                status_html = "Skipped"

            elif status == 'expected_failure':

                status_html = "XFailed"

            elif status == 'unexpected_success':

                status_html = "XPassed"



            test_result_html = f"""

            <tr>

                <td>{command}</td>

                <td>{status_html}</td>

                <td>{execution_time:.2f}</td>

            </tr>

            """

            self.stream.write(test_result_html)



        self.stream.write("</table>")



def run_test_suite():

    ensure_log_directory()



    config_path = "config/test_config/yolov7"

    override_config = 'bredet/auto_verification/config/auto_config.py'



    py_files_list = get_py_files_in_subdirectories(config_path)

    over_list = []

    for py_file in py_files_list:

        base_name = py_file.rsplit('.', 1)[0]  # 去掉文件扩展名

        extension = py_file.rsplit('.', 1)[1]  # 获取文件扩展名

        over_py_file = f"{base_name}_override.{extension}"

        if not os.path.exists(over_py_file):

            merge_and_save_configs(py_file, override_config, over_py_file, 'test')

        over_list.append(over_py_file)



    suite = unittest.TestSuite()



    report_dir = 'reports'

    os.makedirs(report_dir, exist_ok=True)

    report_file_path = os.path.join(report_dir, 'test_report.html')



    for over_py_file in over_list:

        # Create a test case for the specific over_py_file

        test_case_01 = TestModelPipeline('test_01_single_test', py_file=over_py_file, html_report_file=report_file_path)

        suite.addTest(test_case_01)



        test_case_02 = TestModelPipeline('test_02_multi_devices_test', py_file=over_py_file, html_report_file=report_file_path)

        suite.addTest(test_case_02)



    # 使用自定义的HTMLTestRunner生成HTML报告

    runner = CustomHTMLTestRunner(

        output=report_dir,

        report_name='test_report',

        report_title='Test Report',

        combine_reports=True,

        add_timestamp=False,

        descriptions=True,

        failfast=False,

        buffer=False,

        verbosity=2,

        open_in_browser=True,

        resultclass=CustomTestResult  # 使用自定义的TestResult类

    )



    runner.run(suite)



if __name__ == '__main__':

    run_test_suite()   修改一下代码 现在运行报错File "bredet/auto_verification/33.py", line 347, in <module>
    run_test_suite()
  File "bredet/auto_verification/33.py", line 344, in run_test_suite
    runner.run(suite)
  File "/root/miniconda3/envs/bredet/lib/python3.8/site-packages/HtmlTestRunner/runner.py", line 112, in run
    result.generate_reports(self)
AttributeError: 'CustomTestResult' object has no attribute 'generate_reports'