import xml.etree.cElementTree as ET
import re
import datetime
import socket
import argparse
import os
def convert(filename, outfile):
    """
    Converts a test result file to an XML format suitable for a test report.

    This function reads a test result file, either creating a default XML file if the
    input file does not exist or converting the contents of an existing test result file
    into a standardized XML format.

    If the input file does not exist:
    - Creates a new XML file with default values indicating that no tests were generated.
    - Sets various attributes such as the hostname, timestamp, and test details.

    If the input file exists:
    - Reads the file contents and extracts test results using regular expressions.
    - Parses and aggregates test results, including the number of tests, failures, errors,
      and skipped tests.
    - Constructs an XML document with the aggregated results and writes it to the specified
      output file.

    Args:
        filename (str): The path to the input test result file. If the file does not exist,
                        a default XML file is generated.
        outfile (str): The path to the output XML file where the converted results will be
                       written.

    Returns:
        None

    Raises:
        Exception: If there is an issue with reading the input file or writing to the output
                   file.

    Example:
        convert('input_results.xml', 'output_results.xml')
    """
    if not os.path.isfile(filename) or os.stat(filename).st_size == 0:
        if os.path.isfile(filename):
            os.remove(filename)
        print("File {} does not exist. Generating:...".format(filename))
        fMessage = "{} Not Generated. Check Log".format(filename)
        name = filename.split(".py")[0].split("/")[-1]
        e = datetime.datetime.now()
        timestamp = e.strftime('%Y-%m-%dT%H:%M:%S.%f')

        data = ET.Element('testsuites')
        element1 = ET.SubElement(data, 'testsuite')
        element1.set('name', "'{}'".format(name))
        element1.set('errors', "0")
        element1.set('failures', "1")
        element1.set('skipped', "0")
        element1.set('tests', "1")
        element1.set('time', "0.01")
        element1.set('timestamp', timestamp)
        element1.set('hostname', socket.gethostname())

        s_elem1 = ET.SubElement(element1, 'testcase')
        s_elem1.set('classname', "{}.SomeClass".format(name))
        s_elem1.set('name', "{}".format(name))
        s_elem1.set('time', "0.01")

        ss_elem1 = ET.SubElement(s_elem1, 'failure')
        ss_elem1.set('message', fMessage)
        ss_elem1.text = fMessage
        b_xml = ET.tostring(data)

        with open(outfile, "wb") as f:
            f.write(b_xml)
        return

    print("Reading: ",filename )
    with open(filename, 'r') as f:
        data = f.read()
    print("Converting... ")
    results = re.findall('(?s)(?<=\<testsuite).*?(?=\<\/testsuite\>)', data)

    start="""<?xml version="1.0" ?>
    <testsuite
    """

    end="""</testsuite>"""
    name = filename.split(".py")[0].split("/")[-1]

    e = datetime.datetime.now()
    timestamp = e.strftime('%Y-%m-%dT%H:%M:%S.%f')
    data = ET.Element('testsuites')
    element1 = ET.SubElement(data, 'testsuite')
    element1.set('name', "'{}'".format(name))

    tests, failures, errors, skipped = 0 , 0 , 0, 0
 
    runtime = 0.0
    for result in results:
        s = "{}{}{}".format(start, result, end)
        root = ET.fromstring(s)
        if "tests" in root.attrib.keys(): tests = tests + int(root.attrib['tests'])
        if "failures" in root.attrib.keys(): failures = failures + int(root.attrib['failures'])
        if "errors" in root.attrib.keys(): errors = errors + int(root.attrib['errors'])
        # if "skipped" in root.attrib.keys(): skipped = skipped + int(root.attrib['skipped'])
        runtime = runtime + float(root.attrib['time'])

        for i in range(len(root)):
            if not root[i].attrib: continue
            #print(root[i].attrib)
            s_elem1 = ET.SubElement(element1, 'testcase')
            s_elem1.set('classname', "{}".format(name))
            s_elem1.set('name', "{}.{}".format(root[i].attrib['classname'],root[i].attrib['name']))
            s_elem1.set('time', root[i].attrib['time'])

            if len(root[i].getchildren()) != 0:
                for child in root[i].getchildren():
                    if child.attrib['type'] == 'skip':
                        ss_elem1 = ET.SubElement(s_elem1, 'skipped')
                        skipped = skipped + 1
                    else:
                        ss_elem1 = ET.SubElement(s_elem1, 'failure')
                    fMessage = child.attrib['message']
                    ss_elem1.set('message', fMessage)
                    ss_elem1.text = fMessage

    element1.set('hostname', socket.gethostname())
    element1.set('timestamp', timestamp)
    element1.set('errors', "0") # for Bamboo, Errors are treated as Failures
    element1.set('failures', str(max(failures, errors))) # for Bamboo, Errors are treated as Failures
    element1.set('skipped', str(skipped))
    element1.set('tests', str(tests))
    element1.set('time', str(round(runtime, 3)))
    b_xml = ET.tostring(data)

    with open(outfile, "wb") as f:
        f.write(b_xml)
    print("File Written To: ",outfile )

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("--infile", help="XMLRunner module File")
    parser.add_argument("--outfile", help="Converted XMLRunner Output File")
    args = parser.parse_args()

    convert(args.infile, args.outfile)