#!/usr/bin/env python3
# coding=utf-8

#
# Copyright (c) 2022 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

import os
from xml.dom import minidom
from xml.etree import ElementTree

from xdevice import get_cst_time, FilePermission
from devicetest.core.constants import RunResult
from devicetest.core.exception import DeviceTestError
from devicetest.error import ErrorMessage
from devicetest.log.logger import DeviceTestLog as Log


class ReportConstants:
    time_format = "%Y-%m-%d %H:%M:%S"
    report_xml = "report.xml"


class ReportHandler:

    def __init__(self, report_path):
        self.report_path = report_path
        self.test_results = []

    def generate_test_report(self, test_runner, _test_results=None, report_type="normal"):
        if os.path.exists(self.report_path):
            root = ElementTree.parse(self.report_path).getroot()
            return self.report_path, ElementTree.tostring(root).decode()
        try:
            Log.info("start generate test report.")
            test_results = _test_results or test_runner.test_results

            start_time = test_runner.start_time

            testsuites = ElementTree.Element('testsuites')

            test_name = test_runner.configs.get("test_name")
            if test_name is not None:
                testsuites.set("name", test_name)
            else:
                testsuites.set("name", ReportConstants.report_xml)

            if report_type == "xts":
                tests_total, tests_error = self.report_xts_type(testsuites, test_results)
            else:
                tests_total, tests_error = self.report_normal_type(testsuites, test_results, test_name)

            testsuites.set("tests", str(tests_total))
            testsuites.set("failures", str(tests_error))
            testsuites.set("disabled", '')
            testsuites.set("errors", "")
            testsuites.set("starttime", self.get_strftime(start_time))
            testsuites.set("endtime", self.get_now_strftime())
            testsuites.set("report_version", "1.0")

            os.makedirs(os.path.dirname(self.report_path), exist_ok=True)
            xml_content = ElementTree.tostring(testsuites).decode()
            xml_pretty = minidom.parseString(xml_content).toprettyxml(indent="  ")

            result_fd = os.open(self.report_path, os.O_CREAT | os.O_WRONLY | os.O_TRUNC, FilePermission.mode_644)
            with os.fdopen(result_fd, mode="w", encoding="utf-8") as result_file:
                result_file.write(xml_pretty)
            return self.report_path, xml_content

        except Exception as error:
            err_msg = ErrorMessage.Common.Code_0201003
            Log.error(err_msg, is_traceback=True)
            raise DeviceTestError(err_msg) from error

        finally:
            Log.info("exit generate test report.")

    def get_strftime(self, stamp_time):
        return stamp_time.strftime(ReportConstants.time_format)

    def get_now_strftime(self):
        return get_cst_time().strftime(ReportConstants.time_format)

    def report_normal_type(self, testsuites, test_results, test_name):
        tests_total = 0
        tests_error = 0
        for result_info in test_results:

            tests_total += 1
            case_error = 0
            case_result = "true"
            result = result_info.get('result')
            if result != RunResult.PASSED:
                tests_error += 1
                case_error += 1
                case_result = "false"
            case_name = result_info.get('case_name')
            case_start_time = result_info.get('start_time').timestamp()
            case_end_time = result_info.get('end_time').timestamp()
            error = result_info.get('error')
            report = result_info.get("report", "")
            case_time = case_end_time - case_start_time

            testcase = ElementTree.Element('testcase')
            testcase.set("name", case_name)
            testcase.set("status", 'run')
            testcase.set("classname", case_name)
            testcase.set("level", "")
            testcase.set("result", case_result)
            testcase.set("result_kind", result)
            testcase.set("message", error)
            testcase.set("report", report)
            # 用例测试结果的拓展内容
            result_content = result_info.get('result_content')
            if result_content:
                testcase.set("result_content", f"<![CDATA[{result_content}]]>")

            testsuite = ElementTree.Element('testsuite')
            testsuite.set("modulename", test_name)
            testsuite.set("name", case_name)
            testsuite.set("tests", str(1))
            testsuite.set("failures", str(case_error))
            testsuite.set("disabled", '0')
            testsuite.set("time", "{:.2f}".format(case_time))
            testsuite.set("result", case_result)
            testsuite.set("result_kind", result)
            testsuite.set("report", report)

            testsuite.append(testcase)
            testsuites.append(testsuite)
        return tests_total, tests_error

    def report_xts_type(self, testsuites, test_results):
        tests_total = 0
        tests_error = 0
        test_suites = {}
        for result_info in test_results:

            tests_total += 1
            case_error = 0
            case_result = "true"
            result = result_info.get('result')
            if result != RunResult.PASSED:
                tests_error += 1
                case_error += 1
                case_result = "false"
            case_info = result_info.get('case_name').split("#")
            case_name = case_info[1]
            module_name = case_info[0]
            case_start_time = result_info.get('start_time').timestamp()
            case_end_time = result_info.get('end_time').timestamp()
            error = result_info.get('error')
            report = result_info.get("report", "")
            case_time = case_end_time - case_start_time

            testcase = ElementTree.Element('testcase')
            testcase.set("name", case_name)
            testcase.set("status", 'run')
            testcase.set("classname", module_name)
            testcase.set("level", "")
            testcase.set("result", case_result)
            testcase.set("result_kind", result)
            testcase.set("message", error)
            testcase.set("report", report)

            testsuite = ElementTree.Element('testsuite')
            testsuite.set("modulename", module_name)
            testsuite.set("name", module_name)
            testsuite.set("tests", str(1))
            testsuite.set("disabled", '0')
            testsuite.set("time", "{:.2f}".format(case_time))
            testsuite.set("report", report)
            if module_name not in test_suites:
                test_suites[module_name] = {"test_suite": testsuite, "tests": 0, "failures": 0}
                testsuites.append(testsuite)
            test_suites[module_name]["test_suite"].append(testcase)
            test_suites[module_name]["tests"] += 1
            tests = test_suites[module_name]["tests"]
            if case_result == "false":
                test_suites[module_name]["failures"] += 1
            failures = test_suites[module_name]["failures"]
            test_suites[module_name]["test_suite"].set("tests", str(tests))
            test_suites[module_name]["test_suite"].set("failures", str(failures))
        return tests_total, tests_error