// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package testrunner

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"io"
	"io/fs"
	"net/url"
	"path/filepath"
	"strconv"
	"strings"

	"go.fuchsia.dev/fuchsia/tools/lib/osmisc"
	"go.fuchsia.dev/fuchsia/tools/testing/runtests"
	"go.fuchsia.dev/fuchsia/tools/testing/tap"
)

// TestOutputs manages the test runner's output drivers. Upon completion, if tar output is
// initialized, a TAR archive containing all other outputs is produced.
type TestOutputs struct {
	OutDir  string
	Summary runtests.TestSummary
	tap     *tap.Producer
}

func CreateTestOutputs(producer *tap.Producer, outdir string) (*TestOutputs, error) {
	if outdir == "" {
		return nil, fmt.Errorf("outdir must be set")
	}
	return &TestOutputs{
		OutDir: outdir,
		tap:    producer,
	}, nil
}

// rebaseOutputFiles takes the list of outputFiles and rebases them against the
// global OutDir. If an `output file` refers to a directory, all the files in that
// directory will be returned in the list of outputs.
func (o *TestOutputs) rebaseOutputFiles(outputFiles []string, outputDir string) ([]string, error) {
	var allOutputs []string
	for _, outputFilePath := range outputFiles {
		outputFilePath = filepath.Join(outputDir, outputFilePath)
		if err := filepath.Walk(outputFilePath, func(path string, info fs.FileInfo, err error) error {
			if err != nil {
				return err
			}
			if !info.IsDir() {
				pathRel, err := filepath.Rel(o.OutDir, path)
				if err != nil {
					return fmt.Errorf("failed to get relative path of %s to %s: %w", path, o.OutDir, err)
				}
				allOutputs = append(allOutputs, pathRel)
			}
			return nil
		}); err != nil {
			return nil, err
		}
	}
	return allOutputs, nil
}

// Record writes the test result to initialized outputs.
func (o *TestOutputs) Record(ctx context.Context, result TestResult) error {
	// Sponge doesn't seem to like the path if we just put Name in there.
	nameForPath := url.PathEscape(strings.ReplaceAll(result.Name, ":", ""))
	outputRelPath := filepath.Join(nameForPath, strconv.Itoa(result.RunIndex))
	// Strip any leading //.
	outputRelPath = strings.TrimLeft(outputRelPath, "//")

	stdioPath := filepath.Join(outputRelPath, runtests.TestOutputFilename)

	duration := result.Duration()
	if duration < 0 {
		return fmt.Errorf("test %q must have non-negative duration: (start, end) = (%s, %s)", result.Name, result.StartTime, result.EndTime)
	}

	// Rebase outputs from test against the global outdir.
	suiteOutputFiles, err := o.rebaseOutputFiles(result.OutputFiles, result.OutputDir)
	if err != nil {
		return fmt.Errorf("error rebasing output files: %w", err)
	}
	containsStdio := false
	for _, outputFile := range suiteOutputFiles {
		if filepath.Base(outputFile) == runtests.TestOutputFilename {
			containsStdio = true
			break
		}
	}

	// If the stdout/stderr file didn't already exist in the test result's OutputFiles,
	// create it using the bytes from the test Stdio.
	//
	// We'll write a file even if the stdio is empty for consistency, and to
	// make it clear that a file's stdio was empty versus infra silently failing
	// to create the file.
	if !containsStdio {
		pathWriter, err := osmisc.CreateFile(filepath.Join(o.OutDir, stdioPath))
		if err != nil {
			return fmt.Errorf("failed to create stdio file for test %q: %w", result.Name, err)
		}
		defer pathWriter.Close()
		if _, err := pathWriter.Write(result.Stdio); err != nil {
			return fmt.Errorf("failed to write stdio file for test %q: %w", result.Name, err)
		}

		suiteOutputFiles = append(suiteOutputFiles, stdioPath)
	}

	var cases []runtests.TestCaseResult
	for _, testCase := range result.Cases {
		caseOutputFiles, err := o.rebaseOutputFiles(testCase.OutputFiles, testCase.OutputDir)
		if err != nil {
			return fmt.Errorf("error rebasing output files: %w", err)
		}
		newCase := testCase
		newCase.OutputFiles = caseOutputFiles
		newCase.OutputDir = ""
		cases = append(cases, newCase)
	}

	// Only append the test summary after writing all output files to disk. This
	// ensures that even if writing the output files fails, the summary won't
	// reference nonexistent files.
	o.Summary.Tests = append(o.Summary.Tests, runtests.TestDetails{
		Name:           result.Name,
		GNLabel:        result.GNLabel,
		OutputFiles:    suiteOutputFiles,
		Result:         result.Result,
		Cases:          cases,
		StartTime:      result.StartTime,
		DurationMillis: duration.Milliseconds(),
		DataSinks:      result.DataSinks.Sinks,
		Affected:       result.Affected,
		Tags:           result.Tags,
	})

	desc := fmt.Sprintf("%s (%s)", result.Name, duration)
	if o.tap != nil {
		o.tap.Ok(result.Passed(), desc)
	}

	return nil
}

// UpdateDataSinks updates the DataSinks field of the tests in the summary with
// the provided `newSinks`. If the sinks were copied to a subdirectory within
// o.outDir, that path should be provided as the `insertPrefixPath` which will
// get prepended to the sink file paths so that they point to the correct paths
// relative to o.outDir.
func (o *TestOutputs) updateDataSinks(newSinks map[string]runtests.DataSinkReference, insertPrefixPath string) {
	for i, test := range o.Summary.Tests {
		if sinkRef, ok := newSinks[test.Name]; ok {
			if test.DataSinks == nil {
				test.DataSinks = runtests.DataSinkMap{}
			}
			for name, sinks := range sinkRef.Sinks {
				for _, sink := range sinks {
					sink.File = filepath.Join(insertPrefixPath, sink.File)
					test.DataSinks[name] = append(test.DataSinks[name], sink)
				}
			}
			o.Summary.Tests[i] = test
		}
	}
}

// Close stops the recording of test outputs; it must be called to finalize them.
func (o *TestOutputs) Close() error {
	if o.OutDir == "" {
		return nil
	}
	summaryBytes, err := json.Marshal(o.Summary)
	if err != nil {
		return err
	}
	summaryPath := filepath.Join(o.OutDir, runtests.TestSummaryFilename)
	s, err := osmisc.CreateFile(summaryPath)
	if err != nil {
		return fmt.Errorf("failed to create file: %w", err)
	}
	defer s.Close()
	_, err = io.Copy(s, bytes.NewBuffer(summaryBytes))
	return err
}
