package main

import (
	"bufio"
	"encoding/xml"
	"fmt"
	"io"
	"strings"
)

type JUnitTestSuite struct {
	XMLName   xml.Name `xml:"testsuite"`
	Tests     int      `xml:"tests,attr"`
	Failures  int      `xml:"failures,attr"`
	Time      string   `xml:"time,attr"`
	Name      string   `xml:"name,attr"`
	TestCases []JUnitTestCase
}

type JUnitTestCase struct {
	XMLName   xml.Name `xml:"testcase"`
	Classname string   `xml:"classname,attr"`
	Name      string   `xml:"name,attr"`
	Time      string   `xml:"time,attr"`
	Failure   *string  `xml:"failure"`
}

func JUnitReportXML(report *Report, w io.Writer) error {
	suites := []JUnitTestSuite{}

	// convert Report to JUnit test suites
	for _, pkg := range report.Packages {
		ts := JUnitTestSuite{
			Tests:     len(pkg.Tests),
			Failures:  0,
			Time:      formatTime(pkg.Time),
			Name:      pkg.Name,
			TestCases: []JUnitTestCase{},
		}

		classname := pkg.Name
		if idx := strings.LastIndex(classname, "/"); idx > -1 && idx < len(pkg.Name) {
			classname = pkg.Name[idx+1:]
		}

		// individual test cases
		for _, test := range pkg.Tests {
			testCase := JUnitTestCase{
				Classname: classname,
				Name:      test.Name,
				Time:      formatTime(test.Time),
				Failure:   nil,
			}

			if test.Result == FAIL {
				ts.Failures += 1

				// TODO: set error message
				msg := ""
				testCase.Failure = &msg
			}

			ts.TestCases = append(ts.TestCases, testCase)
		}

		suites = append(suites, ts)
	}

	// to xml
	bytes, err := xml.MarshalIndent(suites, "", "\t")
	if err != nil {
		return err
	}

	writer := bufio.NewWriter(w)

	// remove newline from xml.Header, because xml.MarshalIndent starts with a newline
	writer.WriteString(xml.Header[:len(xml.Header)-1])
	writer.Write(bytes)
	writer.WriteByte('\n')
	writer.Flush()

	return nil
}

func countFailures(tests []Test) (result int) {
	for _, test := range tests {
		if test.Result == FAIL {
			result += 1
		}
	}
	return
}

func formatTime(time int) string {
	return fmt.Sprintf("%.3f", float64(time)/1000.0)
}