// Copyright 2020 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 checklicenses

import (
	"bytes"
	"compress/gzip"
	"fmt"
	"io/ioutil"
	"sort"
	"strings"
	"text/template"

	"go.fuchsia.dev/fuchsia/tools/check-licenses/templates"
)

// saveToOutputFile writes to output the serialized licenses.
//
// It writes an uncompressed version too if a compressed version is requested.
func saveToOutputFile(path string, licenses *Licenses, config *Config) error {
	// Sort the licenses in alphabetical order for consistency.
	sort.Slice(licenses.licenses, func(i, j int) bool { return licenses.licenses[i].Category < licenses.licenses[j].Category })
	data := struct {
		Used   []*License
		Unused []*License
	}{}

	for _, l := range licenses.licenses {
		if len(l.matches) == 0 {
			data.Unused = append(data.Unused, l)
		} else {
			data.Used = append(data.Used, l)
		}
	}
	for _, n := range licenses.notices {
		data.Used = append(data.Used, n)
	}

	templateStr := ""
	switch {
	case strings.HasSuffix(path, ".txt") || strings.HasSuffix(path, ".txt.gz"):
		templateStr = templates.TemplateTxt
	case strings.HasSuffix(path, ".html") || strings.HasSuffix(path, ".html.gz"):
		// TODO(omerlevran): Use html/template instead of text/template.
		// text/template is inherently unsafe to generate HTML.
		templateStr = templates.TemplateHtml
	case strings.HasSuffix(path, ".json") || strings.HasSuffix(path, ".json.gz"):
		// TODO(omerlevran): Use encoding/json instead of hand-rolling out json.
		templateStr = templates.TemplateJson
	default:
		return fmt.Errorf("no template found for %s", path)
	}
	buf := bytes.Buffer{}
	tmpl := template.Must(template.New("name").Funcs(getFuncMap(config)).Parse(templateStr))
	if err := tmpl.Execute(&buf, data); err != nil {
		return err
	}

	// Special handling for compressed file.
	const gz = ".gz"
	if strings.HasSuffix(path, gz) {
		// First write uncompressed, then compressed.
		if err := ioutil.WriteFile(path[:len(path)-len(gz)], buf.Bytes(), 0666); err != nil {
			return err
		}
		d, err := compressGZ(buf.Bytes())
		if err != nil {
			return err
		}
		return ioutil.WriteFile(path, d, 0666)
	}

	return ioutil.WriteFile(path, buf.Bytes(), 0666)
}

// compressGZ returns the compressed buffer with gzip format.
func compressGZ(d []byte) ([]byte, error) {
	buf := bytes.Buffer{}
	zw := gzip.NewWriter(&buf)
	if _, err := zw.Write(d); err != nil {
		return nil, err
	}
	if err := zw.Close(); err != nil {
		return nil, err
	}
	return buf.Bytes(), nil
}

func getFuncMap(config *Config) template.FuncMap {
	return template.FuncMap{
		"getPattern": func(l *License) string {
			return l.pattern.String()
		},
		"getText": func(l *License, author string) string {
			return l.matches[author].Text
		},
		"getEscapedText": func(l *License, author string) string {
			return strings.Replace(l.matches[author].Text, "\"", "\\\"", -1)
		},
		"getCategory": func(l *License) string {
			return strings.TrimSuffix(l.Category, ".lic")
		},
		"getFiles": func(l *License, author string) []string {
			var files []string
			for _, file := range l.matches[author].Files {
				files = append(files, file)
			}
			sort.Strings(files)
			return files
		},
		"getAuthors": func(l *License) []string {
			var authors []string
			for author := range l.matches {
				authors = append(authors, author)
			}
			sort.Strings(authors)
			return authors
		},
		"getHTMLText": func(m *Match) string {
			txt := m.Text
			txt = strings.ReplaceAll(txt, "<", "&lt;")
			txt = strings.ReplaceAll(txt, ">", "&gt;")
			txt = strings.Replace(txt, "\n", "<br />", -1)
			return txt
		},
		"getMatches": func(l *License) []*Match {
			sortedList := []*Match{}
			for _, m := range l.matches {
				sortedList = append(sortedList, m)
			}
			sort.Sort(matchByText(sortedList))

			return sortedList
		},
		"getFilesFromMatch": func(m *Match) string {
			result := ""
			if config.PrintFiles && len(m.Files) > 0 {
				result += "Files:\n"
				sort.Strings(m.Files)
				for _, s := range m.Files {
					result += " -> " + s + "\n"
				}
			}
			return result
		},
		"getProjectsFromMatch": func(m *Match) string {
			result := ""
			if config.PrintProjects && len(m.Projects) > 0 {
				result += "Projects:\n"
				sort.Strings(m.Projects)
				for _, s := range m.Projects {
					result += " -> " + s + "\n"
				}
			}
			return result
		},
		"getCopyrights": func(m *Match) string {
			sortedList := []string{}
			for c := range m.Copyrights {
				trim := strings.TrimSpace(c)
				if trim != "" {
					sortedList = append(sortedList, trim)
				}
			}
			sort.Strings(sortedList)

			result := ""
			for _, s := range sortedList {
				result += s + "\n"
			}
			return result
		},
	}
}
