/*
Copyright 2021 Google LLC

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

    https://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.
*/

// Documentation generator
package main

import (
	"bytes"
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"sort"
	"strings"

	"github.com/bazelbuild/buildtools/warn"
	"github.com/golang/protobuf/proto"

	docspb "github.com/bazelbuild/buildtools/warn/docs/proto"
)

func readWarningsFromFile(path string) (*docspb.Warnings, error) {
	content, err := ioutil.ReadFile(path)
	if err != nil {
		return nil, err
	}
	warnings := &docspb.Warnings{}
	if err := proto.UnmarshalText(string(content), warnings); err != nil {
		return nil, err
	}
	return warnings, nil
}

func isExistingWarning(name string) bool {
	for _, n := range warn.AllWarnings {
		if n == name {
			return true
		}
	}
	return false
}

func isDisabledWarning(name string) bool {
	if !isExistingWarning(name) {
		return false
	}
	for _, n := range warn.DefaultWarnings {
		if n == name {
			return false
		}
	}
	return true
}

func generateWarningsDocs(warnings *docspb.Warnings) string {
	var b bytes.Buffer

	b.WriteString(`# Buildifier warnings

Warning categories supported by buildifier's linter:

`)

	// Table of contents
	var names []string
	for _, w := range warnings.Warnings {
		names = append(names, w.Name...)
	}
	sort.Strings(names)
	for _, n := range names {
		fmt.Fprintf(&b, "  * [`%s`](#%s)\n", n, n)
	}

	// Misc
	b.WriteString(`
### <a name="suppress"></a>How to disable warnings

All warnings can be disabled / suppressed / ignored by adding a special comment ` + "`" + `# buildifier: disable=<category_name>` + "`" + ` to
the expression that causes the warning. Historically comments with ` + "`" + `buildozer` + "`" + ` instead of
` + "`" + `buildifier` + "`" + ` are also supported, they are equivalent.

#### Examples

` + "```" + `python
# buildifier: disable=no-effect
"""
A multiline comment as a string literal.

Docstrings don't trigger the warning if they are first statements of a file or a function.
"""

if debug:
    print("Debug information:", foo)  # buildifier: disable=print
` + "```\n")

	// Individual warnings
	sort.Slice(warnings.Warnings, func(i, j int) bool {
		return strings.Compare(warnings.Warnings[i].Name[0], warnings.Warnings[j].Name[0]) < 0
	})
	for _, w := range warnings.Warnings {
		// Header
		b.WriteString("\n--------------------------------------------------------------------------------\n\n## ")
		for _, n := range w.Name {
			fmt.Fprintf(&b, "<a name=%q></a>", n)
		}
		fmt.Fprintf(&b, "%s\n\n", w.Header)

		// Name(s)
		if len(w.Name) == 1 {
			fmt.Fprintf(&b, "  * Category name: `%s`\n", w.Name[0])
		} else {
			b.WriteString("  * Category names:\n")
			for _, n := range w.Name {
				fmt.Fprintf(&b, "    * `%s`\n", n)
			}
		}

		// Bazel --incompatible flag
		if w.BazelFlag != "" {
			label := fmt.Sprintf("`%s`", w.BazelFlag)
			if w.BazelFlagLink != "" {
				label = fmt.Sprintf("[%s](%s)", label, w.BazelFlagLink)
			}
			fmt.Fprintf(&b, "  * Flag in Bazel: %s\n", label)
		}

		// Automatic fix
		fix := "no"
		if w.Autofix {
			fix = "yes"
		}
		fmt.Fprintf(&b, "  * Automatic fix: %s\n", fix)

		// Disabled by default
		if isDisabledWarning(w.Name[0]) {
			b.WriteString("  * [Disabled by default](buildifier/README.md#linter)\n")
		}

		// Non-existent
		if !isExistingWarning(w.Name[0]) {
			b.WriteString("  * Not supported by the latest version of Buildifier\n")
		}

		// Suppress the warning
		b.WriteString("  * [Suppress the warning](#suppress): ")
		for i, n := range w.Name {
			if i != 0 {
				b.WriteString(", ")
			}
			fmt.Fprintf(&b, "`# buildifier: disable=%s`", n)
		}
		b.WriteString("\n")

		// Description
		fmt.Fprintf(&b, "\n%s\n", w.Description)
	}
	return b.String()
}

func writeWarningsDocs(docs, path string) error {
	f, err := os.Create(path)
	if err != nil {
		return err
	}
	if _, err := f.WriteString(docs); err != nil {
		return err
	}
	return f.Close()
}

func main() {
	flag.Parse()
	warnings, err := readWarningsFromFile(flag.Arg(0))
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
	docs := generateWarningsDocs(warnings)
	if err := writeWarningsDocs(docs, flag.Arg(1)); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}
